Reset chances are issued monthly; use one to refill your balance back up to 30,000,000 CU. Learn more →

Backfilling and polling HyperEVM data under public RPC rate limits

Understand HyperEVM public RPC rate limits and restrictions, perform chunked eth_getLogs backfilling with retryable error handling, leverage Data API, and poll new blocks.

When building applications or synchronizing chain data on HyperEVM, developers typically handle two core operational patterns: backfilling historical event logs and transactions, and polling for newly produced blocks and events in real time.

Official public RPC endpoints and third-party node providers operate under distinct rate limits, supported methods, and state retention policies. This guide details those parameters based on official documentation and published specifications, and demonstrates chunked backfilling, retryable error handling, querying structured Data API endpoints, and polling new blocks.

Status quo: official public RPC limits

According to official Hyperliquid developer documentation, the public RPC operates under the following parameters and limits:

  1. Rate limits: The official Rate limits and user limits documentation specifies that for the public endpoint rpc.hyperliquid.xyz/evm, requests are subject to a limit of at most 100 EVM JSON-RPC requests per minute per IP address ("Maximum of 100 EVM JSON-RPC requests per minute for rpc.hyperliquid.xyz/evm").
  2. WebSocket support: The official HyperEVM overview states that the public RPC endpoint rpc.hyperliquid.xyz/evm does not currently support WebSocket JSON-RPC ("There is currently no websocket JSON-RPC support for the RPC at rpc.hyperliquid.xyz/evm but other RPC implementations may support it").
  3. Chain parameters and endpoints:
    • Mainnet: Chain ID 999, public JSON-RPC endpoint https://rpc.hyperliquid.xyz/evm.
    • Testnet: Chain ID 998, public JSON-RPC endpoint https://rpc.hyperliquid-testnet.xyz/evm.
  4. Hardfork and gas mechanics: HyperEVM uses the Cancun hardfork with support for MCOPY, TSTORE, and TLOAD, but does not support blob transactions. EIP-1559 is enabled, but there are no priority fees (priority fees are burned and sent to the zero address balance, so transaction maxFeePerGas and maxPriorityFeePerGas must be equal).

Under a limit of 100 requests per minute per IP and without WebSocket support, broad historical log backfills and rapid block polling require deliberate chunking, retry handling, or polling logic.

BlockVectra parameters and service rules

BlockVectra serves HyperEVM mainnet through JSON-RPC and REST Data API endpoints. Published parameters and service rules originate from public specifications:

  1. Chain parameters and log limits: From GET /v1/chains for hyperevm_mainnet:
    • Chain identifier (Slug): hyperevm_mainnet, Chain ID 999.
    • max_logs_block_range: Governed by the max_logs_block_range field from GET /v1/chains. A single eth_getLogs request may span at most this number of blocks (toBlock − fromBlock + 1). Exceeding this span returns HTTP 200 with JSON-RPC error code -32602 (eth_getLogs block range too large: max <N> blocks), which is not billed.
    • state_window_blocks: Governed by the state_window_blocks field from GET /v1/chains. State-reading calls (such as eth_call and eth_getBalance) are subject to the retention window declared by this field (when null, full state is retained without a rolling window limit).
    • Method policy: Governed by methods.allow and methods.deny. Standard EVM methods (eth_blockNumber, eth_getLogs, eth_call, eth_getBalance, eth_getBlockByNumber, eth_getTransactionReceipt, etc.) are allowed; filter and subscription methods (eth_subscribe, eth_unsubscribe, eth_newFilter, eth_newBlockFilter) are denied, returning -32601 (not billed).
  2. Free tier rate limits and upgrading: From GET /v1/plans:
    • free.max_calls_per_sec: Governed by the free-plan calls-per-second cap returned by the API (note: this limit represents the aggregated average across all API keys in the account).
    • Default key limits: Each API key has a CU bucket (cu_per_sec refill, burst_cu capacity — defaults are 400 CU/s and burst 1,600 CU). Methods are metered by Compute Unit (CU) weights (for example, eth_getLogs is 30 CU, eth_blockNumber is 1 CU, address transactions and transfers are 25 CU).
    • Upgrading limits: After topping up, the account-wide calls-per-second limit is removed; each key remains subject to Compute Unit (CU) rate and burst limits. For current rates and billing units, see the Pricing page.

Backfilling historical logs: chunked eth_getLogs and retry logic

When querying historical logs, wide intervals must be divided into contiguous chunks bounded by the target chain's max_logs_block_range. Client retry strategies should inspect the retryable field inside error responses.

Evaluating retryable in error responses

On BlockVectra, JSON-RPC error objects include an error.data payload containing reason, docs_url, and retryable (boolean):

  • retryable: true: Transient conditions, including service overload (overloaded), free plan calls-per-second limit (free_plan_call_limit), node synchronization (node_syncing), or upstream unavailable (upstream_unavailable). Clients should respect the Retry-After header when present or apply exponential backoff with jitter.
  • retryable: false: Non-transient errors, such as block span exceeding limits (-32602 / logs_range_too_large), invalid parameters (invalid_params), missing API key (missing_api_key), or request exceeding burst capacity (-32022 / request_exceeds_burst). Retrying without adjusting parameters will not succeed.

Below is the response returned when an API key is omitted:

{
  "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
    }
  }
}

Code example: chunked queries and retries

export BLOCKVECTRA_API_KEY="rgw_your_api_key"

# 1. Fetch published max_logs_block_range dynamically (unauthenticated)
curl -s "https://api.blockvectra.com/v1/chains"

# 2. Query a single chunk within max_logs_block_range (e.g. 0x1 to 0x3e8)
curl -s "https://api.blockvectra.com/v1/hyperevm_mainnet" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getLogs",
    "params": [{
      "address": "0x2222222222222222222222222222222222222222",
      "fromBlock": "0x1",
      "toBlock": "0x3e8"
    }]
  }'

Using Data API endpoints instead of extensive getLogs scanning

When an application tracks transaction history or token movements for a specific address, scanning via eth_getLogs requires issuing sequential chunked queries bounded by max_logs_block_range and parsing raw Transfer event logs.

BlockVectra Data API provides pre-indexed REST endpoints for hyperevm_mainnet (defined in openapi/data.yaml), supporting windows up to 100,000 blocks with cursor-based pagination:

  1. Address transactions: GET /v1/data/hyperevm_mainnet/addresses/{address}/transactions
    • Parameters: from_block (required), to_block (required), direction (optional: from, to, any, default any), clamp (optional boolean string, default false; when set to true, windows exceeding 100,000 blocks or higher than finalized_block are truncated instead of returning 409), limit (optional, max 500), cursor (pagination token).
  2. Address token transfers: GET /v1/data/hyperevm_mainnet/addresses/{address}/transfers
    • Parameters: standard (required: erc20 or erc721; OpenAPI defines that erc1155 cannot be queried by address and returns 422 no_coverage), token (optional token contract filter), from_block (required), to_block (required), direction (optional: in, out, any), clamp (optional), limit, cursor.

Response structure (from OpenAPI specification)

Responses use standard envelope schemas:

  • data: Array of records. Transactions include hash, block_number, block_timestamp, from, to, value, tx_index, gas_limit, gas_used, and status. Transfers include token, standard, from, to, block_number, block_timestamp, tx_hash, tx_index, and log_index (amount for ERC-20, token_id for ERC-721).
  • next_cursor: Opaque pagination token returned when subsequent records exist (absent on the final page, not null).
  • meta: Metadata containing chain, chain_slug, chain_external_id, as_of_block, finalized_block, coverage (full or partial), and refreshed_at.

Code example: Data API queries

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"

Real-time tracking: polling new blocks

Because HyperEVM official public RPC does not offer WebSocket JSON-RPC support, and BlockVectra disables eth_subscribe under methods.deny, real-time block and event tracking is accomplished via polling.

Polling flow

  1. Issue periodic lightweight calls to eth_blockNumber (weighted at 1 CU) to inspect the latest chain head.
  2. Compare the returned block number with the previously processed lastSeenBlock.
  3. If currentBlock > lastSeenBlock, fetch new blocks or logs across [lastSeenBlock + 1, currentBlock] and update lastSeenBlock.
  4. viem's watchBlockNumber or watchBlocks natively implements HTTP polling under an HTTP transport, allowing customization through the pollingInterval parameter (such as 1000 ms).

Code example: polling blocks

export BLOCKVECTRA_API_KEY="rgw_your_api_key"

# Query the latest block height (1 CU)
curl -s "https://api.blockvectra.com/v1/hyperevm_mainnet" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'

Next steps

Last updated:

On this page