Лимиты частоты RPC и выгрузка логов HyperEVM
В BlockVectra аутентифицированные запросы eth_getLogs к HyperEVM покрывают до 1,000 блоков с учетом обоих концов; разбивайте длинные окна и сохраняйте последний завершенный блок для возобновления.
Прямой ответ
По умолчанию официальный публичный RPC HyperEVM разрешает не более 50 блоков на один запрос eth_getLogs (источник: официальная документация по JSON-RPC Hyperliquid). В BlockVectra аутентифицированные запросы eth_getLogs покрывают до 1,000 блоков на запрос (hyperevm_mainnet.max_logs_block_range из GET /v1/chains), включая оба конца диапазона. Более широкий диапазон возвращает HTTP 200, JSON-RPC -32602 и logs_range_too_large с retryable: false (см. каталог ошибок); разделите диапазон на [from, min(from + max − 1, end)], сохраните курсор и после успешного завершения переходите к блоку end + 1 для возобновления работы. Лимит частоты запросов на IP официального публичного RPC и лимиты ключей BlockVectra описаны отдельно в разделе Лимиты частоты запросов официального публичного RPC и ошибки 429 и в параметрах сервиса ниже.
- Первый шаг: прочитайте последний блок без API key с помощью команды curl ниже.
- Критерий завершения: скрипт выгрузки выводит
fromBlock,toBlockи массивresultдля каждого фрагмента в выбранном окне; пустой массив означает отсутствие подходящих логов в этом фрагменте.
Параметры сети и варианты доступа.
Задачи, которые помогает решить это руководство
- Проверка HyperEVM RPC с помощью публичного чтения через viem или ethers перед выбором аутентифицированных методов.
- Выгрузка ограниченного окна логов в пределах лимита
eth_getLogsдля HyperEVM с решениями о повторных попытках на основе возвращенной ошибки. - Чтение активности по адресу через проиндексированные транзакции и переводы с использованием ключа, с проверкой возвращенных метаданных покрытия и актуальности.
Задача из трех шагов: выгрузка ограниченного окна логов HyperEVM
Прочитайте последний блок без ключа, создайте ключ, затем получите журналы событий контракта за конечное окно блоков.
Выберите необходимый контракт и окно блоков. Эта задача охватывает указанное ограниченное окно; она не гарантирует получение полной истории контракта.
1. Чтение последнего блока без API key
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. Список public.methods публичного эндпоинта не включает eth_getLogs; для шага 3 требуется ключ.
2. Создание API key
Создайте ключ для этой выгрузки. Создайте ключ и сохраните секрет, показанный в диалоговом окне, для использования с hyperevm_mainnet.
Для ИИ-агента, использующего HTTP без браузера, следуйте руководству по программной регистрации. Передайте валидный параметр ref из URL руководства в теле JSON-запроса POST /auth/siwe/login вместо значения docs-signup из примера; опустите его, если он недоступен. Не просите пользователя вставлять ключ в чат.
3. Выгрузка логов с вашим ключом
Готовый начальный шаблон: blockvectra/hyperevm-backfill
Сохраните следующий скрипт как hyperevm-task.ts. Он работает с Node.js 24 или новее без дополнительных пакетов. Установите BLOCKVECTRA_API_KEY в ваш сохраненный ключ и LOG_ADDRESS в адрес контракта-эмитента, который вы хотите проверить; сохраняйте ключ на своем сервере или в локальном терминале.
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) номеров блоков перед запуском. Более крупные окна разбиваются на последовательные фрагменты, каждый из которых не превышает опубликованного лимита.
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. Скрипт выводит оценку в стандартный поток ошибок: N × weight(eth_getLogs) + weight(eth_blockNumber), включая аутентифицированный запрос вершины сети. Это исключает дополнительные вызовы и любые тарифицируемые повторные попытки; расчет см. в правилах тарификации. Потребление CU зависит от вызовов, а не от количества возвращенных логов.
Доставка событий: используйте фрагментированный HTTP-опрос ниже или отправляйте события отслеживаемых адресов на HTTPS-приемник с помощью 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. Для операций чтения без ключа используйте public.url из каталога и только методы, перечисленные в public.methods; доступность публичного HTTP не означает доступности WebSocket.
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.
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.
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 перед подписанием.
: "${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. Пополните баланс деплоера нативными токенами HYPE в EVM и ознакомьтесь с требованиями к двойным блокам ниже перед масштабным развертыванием.
HYPE, малые блоки и крупные развертывания
В официальном руководстве по сети HyperEVM указано, что HYPE используется для оплаты газа и имеет 18 знаков после запятой (по состоянию на 2026-10-07). Убедитесь, что адрес деплоера содержит HYPE в сети HyperEVM; баланс в HyperCore сам по себе не является балансом газа в EVM. Следуйте инструкциям по ссылке для перевода нативных средств.
В руководстве по архитектуре с двумя типами блоков описываются быстрые малые блоки и более медленные большие блоки для крупных транзакций (по состоянию на 2026-10-07). Сначала оцените объем газа для развертывания. Для развертываний, превышающих лимит малого блока, деплоер должен быть действующим пользователем HyperCore и подписать действие Core {"type":"evmUserModify","usingBigBlocks":true}; одного лишь указания большего лимита газа для транзакции недостаточно для выбора больших блоков. После завершения верните usingBigBlocks=false, чтобы вернуться к малым блокам.
У провайдера, поддерживающего их, используйте eth_usingBigBlocks для проверки режима адреса и eth_bigBlockGasPrice для базовой комиссии большого блока. Эти методы описаны в официальном справочнике по JSON-RPC (по состоянию на 2026-10-07). Проверьте методы выбранного провайдера; для BlockVectra используйте /v1/chains. Минимальное развертывание выше нацелено на небольшой контракт и не меняет режим аккаунта Core.
Данные HyperCore и HyperEVM
EVM RPC обслуживает контракты, квитанции и логи. Торговые данные и действия HyperCore используют Core API. Контракты могут считывать состояние Core через прекомпиляторы и отправлять действия через CoreWriter; используйте официальное руководство по взаимодействию при интеграции этих путей (по состоянию на 2026-10-07). Логи EVM не заменяют запросы к книге ордеров или позициям Core.
Системные транзакции HyperEVM (такие как переводы из HyperCore в HyperEVM) не включаются в стандартные ответы eth_getBlockByNumber и предоставляются официальным RPC отдельно через eth_getSystemTxsByBlockNumber и eth_getSystemTxsByBlockHash (см. официальную документацию по JSON-RPC, по состоянию на 2026-10-07). Данные блоков, транзакций и Data API BlockVectra для HyperEVM в настоящее время не включают системные транзакции; используйте эти два метода официального RPC напрямую, если вам требуются данные системных транзакций.
Обработка официальной ошибки 10055
В официальном руководстве по HyperEVM ошибка 10055 определяется как ошибка на границе Core/EVM, включая сбои, связанные с nonce, недостатком средств, дублированием хэша и заниженной комиссией при замене транзакции (по состоянию на 2026-10-07). Изучите сообщение от RPC-транслятора, прежде чем принимать решение о способе восстановления:
- Nonce: сравните
eth_getTransactionCountс вашими ожидающими транзакциями; упорядочивайте отправку от одного деплоера и согласуйте его следующий nonce. - Средства: проверьте баланс HYPE деплоера в EVM на соответствие сумме перевода плюс стоимости газа.
- Дубликат хэша: найдите существующую транзакцию и квитанцию перед отправкой другой транзакции.
- Комиссия за замену: проверьте существующий nonce и комиссию, затем используйте политику замены транслятора; повторная отправка тех же байтов не увеличивает комиссию.
Сама по себе ошибка 10055 не дает оснований для слепых повторных попыток. Ошибки и рекомендации по их устранению описаны отдельно в справочнике по ошибкам BlockVectra.
Лимиты частоты запросов официального публичного RPC и ошибки 429
Официальная документация по лимитам Hyperliquid устанавливает ограничение не более 100 запросов JSON-RPC к EVM в минуту на один IP для rpc.hyperliquid.xyz/evm. Ее документация по 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 вместо применения лимитов блоков или запросов в минуту официального публичного RPC. Частота запросов отдельно регулируется параметрами ключа cu_per_sec, burst_cu и лимитом вызовов бесплатного плана (см. следующий раздел). При ошибке 429 проверьте error.data.reason и retryable; ошибка request_exceeds_burst требует уменьшения размера запросов, а не повторных попыток без изменений с задержкой.
Параметры и правила сервиса BlockVectra
BlockVectra обслуживает HyperEVM mainnet через эндпоинты JSON-RPC и REST Data API:
- Параметры сети и лимиты логов:
Из
GET /v1/chainsдляhyperevm_mainnet:- Идентификатор сети (слаг):
hyperevm_mainnet, Chain ID999. 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(не тарифицируется).
- Идентификатор сети (слаг):
- Лимиты частоты бесплатного тарифа и повышение лимитов:
Из
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) и всплеска. Актуальные тарифы и расчетные единицы см. на странице цен.
Выгрузка исторических логов: составной 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:
{
"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 блоков с пагинацией на основе курсора:
- Транзакции адреса:
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(токен пагинации).
- Параметры:
- Переводы токенов адреса:
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
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"Отслеживание в реальном времени: опрос новых блоков
Для протокола HTTP отслеживайте блоки с помощью периодического опроса и получайте журналы событий последовательными фрагментами в пределах max_logs_block_range. Выбирайте WebSocket только в том случае, если /v1/chains сообщает ws=true и содержит необходимую запись в subscriptions. Для доставки на HTTPS-приемник используйте Push через вебхуки.
Для проверки развернутого контракта Hello укажите его адрес в LOG_ADDRESS. Отправьте ping() через транслирующий RPC, затем выгрузите блок квитанции с помощью скрипта выгрузки на этой странице. Для новых событий продолжайте с последнего завершенного фрагмента.
cast send "$CONTRACT_ADDRESS" "ping()" --rpc-url "$DEPLOY_RPC_URL" \
--private-key "$DEPLOYER_PRIVATE_KEY"Процесс опроса
- Выполняйте периодические легковесные вызовы
eth_blockNumberдля проверки последней вершины цепи. - Сравнивайте возвращенный номер блока с ранее обработанным
lastSeenBlock. - Если
currentBlock > lastSeenBlock, разделите[lastSeenBlock + 1, currentBlock]на фрагменты размером не болееmax_logs_block_range. СохраняйтеlastSeenBlockтолько после успешной обработки каждого фрагмента; при сбое повторите незавершенный фрагмент. Выполняйте дедупликацию по(blockHash, transactionHash, logIndex)и повторяйте опрос с перекрытием после повторного подключения для согласования реорганизаций. - Функции 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 раз с интервалом в пять секунд и запрашивает каждый новый диапазон последовательными фрагментами. Ошибка останавливает работу скрипта до продвижения невыполненного фрагмента.
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.
- Полные правила по диапазонам
eth_getLogsи алгоритмам разбиения на фрагменты см. в руководстве Лимиты диапазона блоков eth_getLogs и составные запросы. - Для сравнения
eth_getLogsс переводами Data API, описания границas_of_blockи маркеровsafe_block/finalized_blockсм. руководство eth_getLogs против Token Transfers API: история переводов ERC-20. - Подробную информацию об учете CU, нетарифицируемых ошибках и повторных попытках см. в руководстве Что не тарифицируется: коды ошибок и правила списания.
Следующие шаги
- Ознакомьтесь с каталогом наборов данных, чтобы увидеть все наборы данных, которые индексирует BlockVectra.
- Посмотрите бесплатный план и цены, чтобы узнать, что включено в ваш аккаунт.
- Войдите в консоль, чтобы создать API key.
Последнее обновление:
Диапазон блоков eth_getLogs
При ошибке logs_range_too_large прочитайте max_logs_block_range сети, разбейте диапазон блоков с включением обоих концов в пределах лимита и переходите дальше только после успеха текущего фрагмента.
Сравнение с Infura
Используйте цикловые кредиты BlockVectra для концентрированных задач чтения, платите по методам без ежемесячной RPC-подписки и автоматизируйте создание аккаунтов и пополнение стейблкоинами.