# Лимиты частоты RPC и выгрузка логов HyperEVM

> Source: https://docs.blockvectra.com/ru/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)]`, сохраните курсор и после успешного завершения переходите к блоку end + 1 для возобновления работы. Лимит частоты запросов на 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/ru/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 содержит номер последнего блока в шестнадцатеричном формате. Это URL `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`.

  Для ИИ-агента, использующего 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`, с максимум четырьмя попытками на запрос, экспоненциальной задержкой и джиттером, а также поддержкой секунд или 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-приемник с помощью [Push через вебхуки](https://docs.blockvectra.com/en/guides/webhook-push/). **GET /v1/push/chains возвращает поддерживаемые сети** и настройки подтверждений; аутентификация выполняется с помощью `x-api-key`. Подписи вебхуков, дедупликация и защита от повторов рассматриваются в том руководстве. Push через вебхуки работает отдельно от подписок WebSocket (`ws` и `subscriptions` в `/v1/chains`).

## Подключение с помощью viem или ethers

| Параметр / Конечная точка | Значение / Шаблон | Аутентификация |
|---|---|---|
| Chain ID (EIP-155) | `999` | — |
| JSON-RPC (key в пути) | `POST https://api.blockvectra.com/v1/hyperevm_mainnet/{api_key}` | API key в URL пути |
| JSON-RPC (key в заголовке) | `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` | Без аутентификации (публичный) |

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

Сохраните этот код как `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 с поддержкой отправки транзакций. Укажите в переменной `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/). Пополните баланс деплоера нативными токенами HYPE в EVM и ознакомьтесь с требованиями к двойным блокам ниже перед масштабным развертыванием.

## 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 обслуживает контракты, квитанции и логи. Торговые данные и действия HyperCore используют Core API. Контракты могут считывать состояние Core через прекомпиляторы и отправлять действия через 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 BlockVectra для HyperEVM в настоящее время не включают системные транзакции; используйте эти два метода официального RPC напрямую, если вам требуются данные системных транзакций.

## Обработка официальной ошибки 10055

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

* **Nonce:** сравните `eth_getTransactionCount` с вашими ожидающими транзакциями; упорядочивайте отправку от одного деплоера и согласуйте его следующий nonce.
* **Средства:** проверьте баланс HYPE деплоера в EVM на соответствие сумме перевода плюс стоимости газа.
* **Дубликат хэша:** найдите существующую транзакцию и квитанцию перед отправкой другой транзакции.
* **Комиссия за замену:** проверьте существующий 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 запросов JSON-RPC к EVM в минуту на один 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). Если он отсутствует, используйте экспоненциальную задержку с джиттером и ограниченным числом повторов, повторяя тот же незавершенный фрагмент. Снизьте параллелизм и частоту опроса, а также разделите запросы логов на фрагменты в пределах лимита эндпоинта. Само по себе разбиение на фрагменты не отменяет лимитов частоты; клиенты, использующие один 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 mainnet через эндпоинты JSON-RPC и REST Data API:

1. **Параметры сети и лимиты логов**:
   Из `GET /v1/chains` для `hyperevm_mainnet`:
   * **Идентификатор сети (слаг)**: `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). Потребление методов измеряется по весам Compute Units (CU).
   * **Повышение лимитов**: После пополнения счета ограничение вызовов в секунду на уровне аккаунта снимается; каждый ключ по-прежнему подчиняется лимитам скорости Compute Units (CU) и всплеска. Актуальные тарифы и расчетные единицы см. на [странице цен](https://blockvectra.com/ru/pricing/).

## Выгрузка исторических логов: составной eth\_getLogs и логика повторов

При запросе исторических логов широкие интервалы должны разбиваться на непрерывные фрагменты, ограниченные параметром `max_logs_block_range` целевой сети. Стратегии повторных попыток на стороне клиента должны проверять поле `retryable` в ответах с ошибками.

### Оценка поля retryable в ответах с ошибками

В BlockVectra объекты ошибок JSON-RPC содержат данные `error.data` с полями `reason`, `docs_url` и `retryable` (boolean):

* **`retryable: true`**: Временные состояния, включая перегрузку сервиса (`overloaded`), лимит вызовов в секунду бесплатного плана (`free_plan_call_limit`), синхронизацию узла (`node_syncing`) или недоступность апстрима (`upstream_unavailable`). Клиенты должны учитывать заголовок `Retry-After`, если он присутствует, или применять экспоненциальную задержку с джиттером.
* **`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`.

### Структура ответа

Ответы используют стандартные схемы-конверты:

* `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-приемник используйте [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. Функции viem `watchBlockNumber` или `watchBlocks` нативно реализуют опрос по HTTP при использовании HTTP-транспорта, позволяя настраивать параметр `pollingInterval` (например, 1000 мс).

### Опрос логов событий ограниченными фрагментами

Сохраните как `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 или других повторяемых сбоях применяйте рекомендации по ограниченной экспоненциальной задержке к тому же незавершенному фрагменту.

## Связанные руководства

* Найдите публичный RPC URL, поддерживаемые методы и актуальные лимиты на [странице сети HyperEVM](https://blockvectra.com/ru/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 против Token Transfers API: история переводов ERC-20](https://docs.blockvectra.com/en/guides/logs-vs-transfers/).
* Подробную информацию об учете CU, нетарифицируемых ошибках и повторных попытках см. в руководстве [Что не тарифицируется: коды ошибок и правила списания](https://docs.blockvectra.com/en/guides/billing-rules/).

## Следующие шаги

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