HyperSync Complete Documentation
This document contains all HyperSync documentation consolidated into a single file for LLM consumption.
| What it is | A purpose-built, high-performance blockchain data retrieval layer built in Rust - a direct alternative to traditional JSON-RPC endpoints |
| Performance | Up to 2000x faster than traditional RPC (e.g. scan Arbitrum for sparse log data in 2 seconds vs. hours/days); ~500x faster for event queries |
| Supported networks | 70+ EVM chains and Fuel, with new networks added regularly |
| Client libraries | Python, Rust, Node.js, Go |
| API token | Required - set via ENVIO_API_TOKEN environment variable |
| Data types | Logs, transactions, traces, blocks - with fine-grained field selection |
| Query features | Log filters, transaction filters, trace filters, block filters, field selection, join modes, streaming |
| Quickstart | pnpx logtui aave arbitrum - zero setup required |
| Powers | HyperIndex, ChainDensity.xyz, Scope.sh, LogTUI, and more |
| Relationship to HyperIndex | HyperSync is the data engine; HyperIndex is the full indexing framework built on top of it |
| Support | Discord · GitHub |
HyperSync: Ultra-Fast & Flexible Data API
File: overview.md
What is HyperSync?
HyperSync is a purpose-built data retrieval layer for onchain data, built from the ground up in Rust. It serves as an alternative to traditional JSON-RPC endpoints, letting you filter and select exactly the data you need. On the workloads in our performance benchmarks, scans that take hours or days over RPC complete in seconds.
HyperSync is Envio's high-performance blockchain data engine that serves as a direct replacement for traditional RPC endpoints, delivering up to 2000x faster data access.
HyperIndex is built on top of HyperSync, providing a complete indexing framework with schema management, event handling, and GraphQL APIs.
Use HyperSync directly when you need raw blockchain data at maximum speed, or use HyperIndex when you need a full-featured indexing solution.
The Problem HyperSync Solves
Traditional blockchain data access through JSON-RPC faces several limitations:
- Speed constraints: Retrieving large amounts of historical data can take days
- Query flexibility: Complex data analysis requires many separate calls
- Cost inefficiency: Expensive for data-intensive applications
Key Benefits
- Exceptional Performance: Retrieve and process blockchain data up to 1000x faster than traditional RPC methods
- Comprehensive Coverage: Access data across EVM chains and Fuel, with new networks added regularly
- Flexible Query Capabilities: Filter, select, and process exactly the data you need with powerful query options
- Cost Efficiency: Dramatically reduce infrastructure costs for data-intensive applications
- Simple Integration: Client libraries available for Python, Rust, Node.js, and Go
Performance Benchmarks
HyperSync delivers transformative performance compared to traditional methods:
| Task | Traditional RPC | HyperSync | Improvement |
|---|---|---|---|
| Scan Arbitrum blockchain for sparse log data | Hours/Days | 2 seconds | ~2000x faster |
| Fetch all Uniswap v3 PoolCreated events ethereum | Hours | Seconds | ~500x faster |
Use Cases
HyperSync powers a wide range of blockchain applications, enabling developers to build tools that would be impractical with traditional data access methods:
General Applications
- Blockchain Indexers: Build high-performance data indexers with minimal infrastructure
- Data Analytics: Perform complex on-chain analysis in seconds instead of days
- Block Explorers: Create responsive explorers with comprehensive data access
- Monitoring Tools: Track blockchain activity with near real-time updates
- Cross-chain Applications: Access unified data across multiple networks
- ETL Pipelines: Create pipelines to extract and save data fast
Powered by HyperSync
HyperIndex
- 100x faster blockchain indexing across EVM chains and Fuel
- Powers 100 plus applications like v4.xyz analytics
ChainDensity.xyz
- Fast transaction/event density analysis for any address
- Generates insights in seconds that would take hours with traditional methods
Scope.sh
- Ultra-fast Account Abstraction (AA) focused block explorer
- Fast historical data retrieval with minimal latency
LogTUI
- Terminal-based UI for finding all historical blockchain events
- Built-in presets for 20+ protocols (Uniswap, Chainlink, Aave, ENS, etc.)
- Try it:
pnpx logtui aave arbitrumto track Aave events on Arbitrum in your terminal
See HyperSync in Action
Next Steps
- Try the Quick Start Guide to get up and running in minutes
- Build queries visually with our Intuitive Query Builder
- Get an API Token to access HyperSync services
- View Supported Networks to see available chains
- Check Client Documentation for language-specific guides
- Join our Discord for support and updates
Our documentation is continuously improving! If you have questions or need assistance, please reach out in our Discord community.
Quickstart
File: quickstart.md
The HyperSync Query Builder lets you construct and run queries directly in your browser — no install, no code required. It's the fastest way to get familiar with HyperSync and see what's possible.
Get up and running with HyperSync in minutes. This guide will help you start accessing blockchain data at unprecedented speeds with minimal setup. For a conceptual overview before you dive in, see What is HyperSync?.
Quickest Start: Try LogTUI
Want to see HyperSync in action with zero setup? Try LogTUI, a terminal-based blockchain event viewer:
# Monitor Aave events on Arbitrum (no installation needed)
pnpx logtui aave arbitrum
Clone the Quickstart Repository
The fastest way to get started is to clone our minimal example repository:
git clone https://github.com/enviodev/hypersync-quickstart.git
cd hypersync-quickstart
This repository contains everything you need to start streaming blockchain data using HyperSync.
Install Dependencies
# Using pnpm (recommended)
pnpm install
Choose Your Adventure
The repository includes three different script options, all of which retrieve Uniswap V3 events from Ethereum mainnet:
# Run minimal version (recommended for beginners)
node run-simple.js
# Run full version with progress bar
node run.js
# Run version with terminal UI
node run-tui.js
That's it! You're now streaming data directly from Ethereum mainnet through HyperSync! (TUI version below)
Understanding the Code
Let's look at the core concepts in the example code:
1. Initialize the Client
// Initialize Hypersync client
const client = new HypersyncClient({
url: "https://eth.hypersync.xyz", // Change this URL for different networks
apiToken: process.env.ENVIO_API_TOKEN!,
});
Note: To connect to different networks, see the Supported Networks page for a complete list of available URLs.
2. Build Your Query
The heart of HyperSync is the query object, which defines what data you want to retrieve:
let query = {
fromBlock: 0, // Start block (0 = genesis)
logs: [
// Filter for specific events
{
topics: [topic0_list], // Event signatures we're interested in
},
],
fieldSelection: {
// Only return fields we need
log: [
"Data",
"Address",
"Topic0",
"Topic1",
"Topic2",
"Topic3",
],
},
};
3. Stream and Process Results
// Start streaming events
const stream = await client.stream(query, {});
while (true) {
const res = await stream.recv();
// Process results
if (res.data && res.data.logs) {
// Do something with the logs
totalEvents += res.data.logs.length;
}
// Update starting block for next batch
if (res.nextBlock) {
query.fromBlock = res.nextBlock;
}
}
Key Concepts for Building Queries
Filtering Data
HyperSync lets you filter blockchain data in several ways:
- Log filters: Find specific events by contract address and event signature
- Transaction filters: Filter by sender/receiver addresses, method signatures, etc.
- Trace filters: Access internal transactions and state changes (only supported on select networks like Ethereum Mainnet)
- Block filters: Get data from specific block ranges
Field Selection
One of HyperSync's most powerful features is the ability to retrieve only the fields you need:
fieldSelection: {
// Block fields
block: ["Number", "Timestamp"],
// Log fields
log: ["Address", "Topic0", "Data"],
// Transaction fields
transaction: ["From", "To", "Value"],
}
This selective approach dramatically reduces unnecessary data transfer and improves performance.
Join Modes
HyperSync allows you to control how related data is joined:
- JoinNothing: Return only exact matches
- JoinAll: Return matches plus all related objects
- JoinTransactions: Return matches plus their transactions
- Default: Return a reasonable set of related objects
Examples
Finding Uniswap V3 Events
This example (from the quickstart repo) streams all Uniswap V3 events from the beginning of Ethereum:
// Define Uniswap V3 event signatures
const event_signatures = [
"PoolCreated(address,address,uint24,int24,address)",
"Burn(address,int24,int24,uint128,uint256,uint256)",
"Initialize(uint160,int24)",
"Mint(address,address,int24,int24,uint128,uint256,uint256)",
"Swap(address,address,int256,int256,uint160,uint128,int24)",
];
// Create topic0 hashes from event signatures
const topic0_list = event_signatures.map((sig) => keccak256(toHex(sig)));
// Initialize Hypersync client
const client = new HypersyncClient({
url: "https://eth.hypersync.xyz",
apiToken: process.env.ENVIO_API_TOKEN!,
});
// Define query for Uniswap V3 events
let query = {
fromBlock: 0,
logs: [
{
topics: [topic0_list],
},
],
fieldSelection: {
log: [
"Data",
"Address",
"Topic0",
"Topic1",
"Topic2",
"Topic3",
],
},
};
const main = async () => {
console.log("Starting Uniswap V3 event scan...");
const stream = await client.stream(query, {});
// Process stream...
};
main();
Supported Networks
HyperSync supports EVM-compatible networks. You can change networks by simply changing the client URL:
// Ethereum Mainnet
const client = new HypersyncClient({
url: "https://eth.hypersync.xyz",
apiToken: process.env.ENVIO_API_TOKEN!,
});
// Arbitrum
const client = new HypersyncClient({
url: "https://arbitrum.hypersync.xyz",
apiToken: process.env.ENVIO_API_TOKEN!,
});
// Base
const client = new HypersyncClient({
url: "https://base.hypersync.xyz",
apiToken: process.env.ENVIO_API_TOKEN!,
});
See the Supported Networks page for a complete list.
Using LogTUI
This quickstart repository powers LogTUI, a terminal-based blockchain event viewer built on HyperSync. LogTUI lets you monitor events from popular protocols across multiple chains with zero configuration.
Try it with a single command:
# Monitor Uniswap events on unichain
pnpx logtui uniswap-v4 unichain
# Monitor Aave events on Arbitrum
pnpx logtui aave arbitrum
# See all available options
pnpx logtui --help
LogTUI supports scanning historically for any events across all networks supported by HyperSync.
Next Steps
You're now ready to build with HyperSync! Here are some resources for diving deeper:
- Client Libraries - Explore language-specific clients
- Query Reference - Learn advanced query techniques
- Build queries visually - Use our Intuitive Query Builder
- curl Examples - Test queries directly in your terminal
- Complete Getting Started Guide - More comprehensive guidance
API Token
An API token is required to use HyperSync. Get an API token and set it as an environment variable:
export ENVIO_API_TOKEN="your-api-token-here"
Congratulations! You've taken your first steps with HyperSync, bringing ultra-fast blockchain data access to your applications. Happy building!
Getting Started with HyperSync
File: hypersync-usage.md
The HyperSync Query Builder lets you construct and run queries directly in your browser — no install, no code required. It's the fastest way to get familiar with HyperSync and see what's possible.
HyperSync is Envio's high-performance blockchain data engine that provides up to 2000x faster access to blockchain data compared to traditional RPC endpoints. This guide will help you understand how to effectively use HyperSync in your applications.
Quick Start Video
Watch this quick tutorial to see HyperSync in action:
Core Concepts
HyperSync revolves around two main concepts:
- Queries - Define what blockchain data you want to retrieve
- Output Configuration - Specify how you want that data formatted and delivered
Think of queries as your data filter and the output configuration as your data processor.
Building Effective Queries
Queries are the heart of working with HyperSync. They allow you to filter for specific blocks, logs, transactions, and traces.
Query Structure
A basic HyperSync query contains:
query = hypersync.Query(
from_block=12345678, # Required: Starting block number
to_block=12345778, # Optional: Ending block number
field_selection=field_selection, # Required: What fields to return
logs=[log_selection], # Optional: Filter for specific logs
transactions=[tx_selection], # Optional: Filter for specific transactions
traces=[trace_selection], # Optional: Filter for specific traces
include_all_blocks=False, # Optional: Include blocks with no matches
max_num_blocks=1000, # Optional: Limit number of blocks processed
max_num_transactions=5000, # Optional: Limit number of transactions processed
max_num_logs=5000, # Optional: Limit number of logs processed
max_num_traces=5000 # Optional: Limit number of traces processed
)
Field Selection
Field selection allows you to specify exactly which data fields you want to retrieve. This improves performance by only fetching what you need:
field_selection = hypersync.FieldSelection(
# Block fields you want to retrieve
block=[
BlockField.NUMBER,
BlockField.TIMESTAMP,
BlockField.HASH
],
# Transaction fields you want to retrieve
transaction=[
TransactionField.HASH,
TransactionField.FROM,
TransactionField.TO,
TransactionField.VALUE
],
# Log fields you want to retrieve
log=[
LogField.ADDRESS,
LogField.TOPIC0,
LogField.TOPIC1,
LogField.TOPIC2,
LogField.TOPIC3,
LogField.DATA,
LogField.TRANSACTION_HASH
],
# Trace fields you want to retrieve (if applicable)
trace=[
TraceField.ACTION_FROM,
TraceField.ACTION_TO,
TraceField.ACTION_VALUE
]
)
Filtering for Specific Data
For most use cases, you'll want to filter for specific logs, transactions, or traces:
Log Selection Example
# Filter for Transfer events from USDC contract
log_selection = hypersync.LogSelection(
address=["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], # USDC contract
topics=[
["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] # Transfer event signature
]
)
Transaction Selection Example
# Filter for transactions to the Uniswap V3 router
tx_selection = hypersync.TransactionSelection(
to=["0xE592427A0AEce92De3Edee1F18E0157C05861564"] # Uniswap V3 Router
)
Processing the Results
HyperSync provides multiple ways to process query results:
Stream to Parquet Files
Parquet is the recommended format for large data sets:
# Configure output format
config = hypersync.StreamConfig(
hex_output=hypersync.HexOutput.PREFIXED,
event_signature="Transfer(address indexed from, address indexed to, uint256 value)"
)
# Stream results to a Parquet file
await client.collect_parquet("data_directory", query, config)
Stream to JSON Files
For smaller datasets or debugging:
# Stream results to JSON
await client.collect_json("output.json", query, config)
Process Data in Memory
For immediate processing:
# Process data directly
async for result in client.stream(query, config):
for log in result.logs:
# Process each log
print(f"Transfer from {log.event_params['from']} to {log.event_params['to']}")
Tips and Best Practices
Performance Optimization
-
Use Appropriate Batch Sizes: Adjust batch size based on your chain and use case:
config = hypersync.ParquetConfig(
path="data",
hex_output=hypersync.HexOutput.PREFIXED,
batch_size=1000000, # Process 1M blocks at a time
concurrency=10, # Use 10 concurrent workers
) -
Enable Trace Logs: Set
RUST_LOG=traceto see detailed progress:export RUST_LOG=trace -
Paginate Large Queries: HyperSync requests have a 5-second time limit. For large data sets, paginate results:
current_block = start_block
while current_block < end_block:
query.from_block = current_block
query.to_block = min(current_block + 1000000, end_block)
result = await client.collect_parquet("data", query, config)
current_block = result.end_block + 1
Network-Specific Considerations
- High-Volume Networks: For networks like Ethereum Mainnet, use smaller block ranges or more specific filters
- Low-Volume Networks: For smaller chains, you can process the entire chain in one query
Complete Example
Here's a complete example that fetches all USDC Transfer events:
import hypersync
from hypersync import (
LogSelection,
LogField,
BlockField,
FieldSelection,
TransactionField,
HexOutput
)
import asyncio
async def collect_usdc_transfers():
# Initialize client
client = hypersync.HypersyncClient(
hypersync.ClientConfig(
url="https://eth.hypersync.xyz",
bearer_token="your-token-here", # Get from https://docs.envio.dev/docs/HyperSync/api-tokens
)
)
# Define field selection
field_selection = hypersync.FieldSelection(
block=[BlockField.NUMBER, BlockField.TIMESTAMP],
transaction=[TransactionField.HASH],
log=[
LogField.ADDRESS,
LogField.TOPIC0,
LogField.TOPIC1,
LogField.TOPIC2,
LogField.DATA,
]
)
# Define query for USDC transfers
query = hypersync.Query(
from_block=12000000,
to_block=12100000,
field_selection=field_selection,
logs=[
LogSelection(
address=["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], # USDC contract
topics=[
["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] # Transfer signature
]
)
]
)
# Configure output
config = hypersync.StreamConfig(
hex_output=HexOutput.PREFIXED,
event_signature="Transfer(address indexed from, address indexed to, uint256 value)"
)
# Collect data to a Parquet file
result = await client.collect_parquet("usdc_transfers", query, config)
print(f"Processed blocks {query.from_block} to {result.end_block}")
asyncio.run(collect_usdc_transfers())
Decoding Event Logs
When working with blockchain data, event logs contain encoded data that needs to be properly decoded to extract meaningful information. HyperSync provides powerful decoding capabilities to simplify this process.
Understanding Log Structure
Event logs in Ethereum have the following structure:
- Address: The contract that emitted the event
- Topic0: The event signature hash (keccak256 of the event signature)
- Topics 1-3: Indexed parameters (up to 3)
- Data: Non-indexed parameters packed together
Using the Decoder
HyperSync's client libraries include a Decoder class that can parse these raw logs into structured data:
// Create a decoder with event signatures
const decoder = Decoder.fromSignatures([
"Transfer(address indexed from, address indexed to, uint256 amount)",
"Approval(address indexed owner, address indexed spender, uint256 amount)",
]);
// Decode logs
const decodedLogs = await decoder.decodeLogs(logs);
Single vs. Multiple Event Types
HyperSync provides flexibility to decode different types of event logs:
-
Single Event Type: For processing one type of event (e.g., only Swap events)
- See complete example: run-decoder.js
-
Multiple Event Types: For processing different events from the same contract (e.g., Transfer and Approval)
- See complete example: run-decoder-multi.js
Working with Decoded Data
After decoding, you can access the log parameters in a structured way:
- Indexed parameters: Available in
decodedLog.indexedarray - Non-indexed parameters: Available in
decodedLog.bodyarray
Each parameter object contains:
- name: The parameter name from the signature
- type: The Solidity type
- val: The actual value
For example, to access parameters from a Transfer event:
// Access indexed parameters (from, to)
const from = decodedLog.indexed[0]?.val.toString();
const to = decodedLog.indexed[1]?.val.toString();
// Access non-indexed parameters (amount)
const amount = decodedLog.body[0]?.val.toString();
Benefits of Using the Decoder
- Type Safety: Values are properly converted to their corresponding types
- Simplified Access: Direct access to named parameters
- Batch Processing: Decode multiple logs with a single call
- Multiple Event Support: Handle different event types in the same processing pipeline
Next Steps
Now that you understand the basics of using HyperSync:
- Browse the Python Client or other language-specific clients
- Learn about advanced query options
- Tune throughput, and read your rate-limit quota from code, in Stream Config & Tuning
- See example queries for common use cases
- Get your API token to start building
For detailed API references and examples in other languages, check our client documentation.
HyperSync Client Libraries
File: hypersync-clients.md
HyperSync provides powerful client libraries that enable you to integrate high-performance blockchain data access into your applications. These libraries handle the communication with HyperSync servers, data serialization/deserialization, and provide convenient APIs for querying blockchain data.
Quick Links
| Client | Resources |
|---|---|
| Node.js | 📝 API Docs · 📦 NPM · 💻 GitHub · 🧪 Examples |
| Python | 📦 PyPI · 💻 GitHub · 🧪 Examples |
| Rust | 📦 Crates.io · 📝 API Docs · 💻 GitHub · 🧪 Examples |
| Go (community) | 💻 GitHub · 🧪 Examples |
| Solana (Rust) | 📖 Guide · 📦 Crates.io · 📝 API Docs · 💻 GitHub |
| API Tokens | 🔑 Get Tokens |
Client Overview
All HyperSync clients share these key features:
- High Performance: Built on a common Rust foundation for maximum efficiency
- Optimized Transport: Uses binary formats to minimize bandwidth and maximize throughput
- Consistent Experience: Similar APIs across all language implementations
- Automatic Pagination: Handles large data sets efficiently
- Event Decoding: Parses binary event data into structured formats
Choose the client that best matches your application's technology stack:
| Feature | Node.js | Python | Rust | Go |
|---|---|---|---|---|
| Async Support | ✅ | ✅ | ✅ | ✅ |
| Typing | TypeScript | Type Hints | Native | Native |
| Data Formats | JSON, Parquet | JSON, Parquet, CSV | JSON, Parquet | JSON, Parquet |
| Memory Efficiency | Good | Better | Best | Better |
| Installation | npm | pip | cargo | go get |
Node.js Client
The Node.js client provides a TypeScript-first experience for JavaScript developers.
Installation
# Using npm
npm install @envio-dev/hypersync-client
# Using yarn
yarn add @envio-dev/hypersync-client
# Using pnpm
pnpm add @envio-dev/hypersync-client
Python Client
The Python client provides a Pythonic interface with full type hinting support.
Installation
pip install hypersync
Rust Client
The Rust client provides the most efficient and direct access to HyperSync, with all the safety and performance benefits of Rust.
Installation
Add the following to your Cargo.toml:
[dependencies]
hypersync-client = "0.1"
tokio = { version = "1", features = ["full"] }
Solana Client
- 📖 Solana Client Guide
- 📦 Crates.io Package
- 📝 API Documentation
- 💻 GitHub Repository
Solana HyperSync has its own client, because the query and table model is Solana-shaped (slots, instruction calls, account activity) rather than EVM-shaped. It is Rust today, with unpublished Node bindings in the same repository. Everything client-side is covered in the Solana client guide.
[dependencies]
hypersync-client-solana = "0.2"
Go Client
The Go client is community maintained and marked as work-in-progress. For production use, you may want to test thoroughly or consider the officially supported clients.
The Go client provides a native Go interface for accessing HyperSync, with support for streaming and decoding blockchain data.
Installation
go get github.com/enviodev/hypersync-client-go
Using API Tokens
You'll need an API token to use any HyperSync client. Get your token here.
All HyperSync clients require an API token for authentication. Tokens are used to manage access and usage limits.
To get an API token:
- Visit Envio
- Register or sign in with your github account
- Navigate to the API Tokens section
- Create a new token
For detailed instructions, see our API Tokens guide.
Client Selection Guide
Choose the client that best fits your use case:
Choose when: You're building JavaScript/TypeScript applications or if your team is most comfortable with the JavaScript ecosystem.
Choose when: You're doing data science work, need integration with pandas/numpy, or if your team prefers Python's simplicity.
Choose when: You need maximum performance, are doing systems programming, or building performance-critical applications.
Choose when: You're working in a Go ecosystem and want native integration with Go applications. Note that this client is community maintained.
Additional Resources
- 📚 HyperSync Usage Guide
- 📝 Query Reference
- 🧪 cURL Examples
- 📊 Supported Networks
- 🧱 HyperIndex blockchain indexer, the full framework with schema, handlers, and a hosted GraphQL API, powered by HyperSync
Support
Need help getting started or have questions about our clients? Connect with our community:
HyperSync Query
File: hypersync-query.md
This guide explains how to structure queries for HyperSync to efficiently retrieve blockchain data. You'll learn both the basics and advanced techniques to make the most of HyperSync's powerful querying capabilities.
Not all features implemented in HyperSync are available in HyperFuel (the Fuel implementation of HyperSync). For example, as of this writing, stream and collect functions aren't implemented in the Fuel client.
Client Examples
HyperSync offers client libraries in multiple languages, each with its own comprehensive examples. Instead of providing generic examples here, we recommend exploring the language-specific examples:
| Client | Example Links |
|---|---|
| Node.js | Example Repository |
| Python | Example Repository |
| Rust | Example Repository |
| Go | Example Repository |
Additionally, we maintain a comprehensive collection of real-world examples covering various use cases across different languages:
- 30 HyperSync Examples - A diverse collection of practical examples demonstrating HyperSync's capabilities in Python, JavaScript, TypeScript, Rust, and more.
For more details on client libraries, see the HyperSync Clients documentation.
Need help building queries? Try our Intuitive Query Builder to construct queries visually and see the results in real-time.
Set the RUST_LOG environment variable to trace for more detailed logs when using client libraries.
Table of Contents
- Understanding HyperSync Queries
- Query Execution Process
- Query Structure Reference
- Data Schema
- Response Structure
- Stream and Collect Functions
- Working with Join Modes
- Best Practices
Understanding HyperSync Queries
A HyperSync query defines what blockchain data you want to retrieve and how you want it returned. Unlike regular RPC calls, HyperSync queries offer:
- Flexible filtering across logs, transactions, traces, and blocks
- Field selection to retrieve only the data you need
- Automatic pagination to handle large result sets
- Join capabilities that link related blockchain data together
Core Concepts
- Selections: Define criteria for filtering blockchain data (logs, transactions, traces)
- Field Selection: Specify which fields to include in the response
- Limits: Control query execution time and response size
- Joins: Determine how related data is connected in the response
Query Execution Process
How Data is Organized
HyperSync organizes blockchain data into groups of contiguous blocks. When executing a query:
- The server identifies which block group contains the starting block
- It processes data groups sequentially until it hits a limit
- Results are returned along with a
next_blockvalue for pagination
Query Limits
HyperSync enforces several types of limits to ensure efficient query execution:
| Limit Type | Description | Behavior |
|---|---|---|
| Time | Server-configured maximum execution time | May slightly exceed limit to complete current block group |
| Response Size | Maximum data returned | May slightly exceed limit to complete current block group |
| to_block | User-specified ending block (exclusive) | Never exceeds this limit |
| maxnum* | User-specified maximum number of results by type | May slightly exceed limit to complete current block group |
Execution Steps
- Server receives query and identifies the starting block group
- It scans each block group, applying selection criteria
- It joins related data according to the specified join mode
- When a limit is reached, it finishes processing the current block group
- It returns results with pagination information
Understanding Pagination
HyperSync uses a time-based pagination model that differs from traditional RPC calls:
- By default, HyperSync has a 5-second query execution limit
- Within this time window, it processes as many blocks as possible
- For example, starting with
from_block: 0might progress to block 10 million in a single request - Each response includes a
next_blockvalue indicating where to resume for the next query - This differs from RPC calls where you typically specify fixed block ranges (e.g., 0-1000)
Understanding nextBlock
nextBlock is the block number immediately after the last block included in the response. Use it as the fromBlock of your next query if you want to continue scanning. Resuming from nextBlock gives you a continuous, non-overlapping scan—no gaps, no duplicates.
Usage pattern: Call get or getEvents, process the page, then if nextBlock is less than your desired end (toBlock or archiveHeight), set fromBlock = nextBlock and repeat:
let query = { fromBlock: 0, logs: [...], fieldSelection: {...} };
while (true) {
const res = await client.get(query);
// Process res.data...
const targetEnd = query.toBlock ?? res.archiveHeight;
if (res.nextBlock >= targetEnd) break;
query = { ...query, fromBlock: res.nextBlock };
}
For most use cases, the stream function handles pagination automatically, making it the recommended approach for processing large ranges of blocks.
Reverse Search
HyperSync supports searching from the head of the chain backwards, which is useful for:
- Block explorers showing the most recent activity
- UIs displaying latest transactions for a user
- Any use case where recent data is more relevant
To use reverse search, add the reverse: true parameter to your stream call:
// Example of reverse search to get recent transactions
const receiver = await client.stream(query, { reverse: true });
let count = 0;
while (true) {
let res = await receiver.recv();
if (res === null) {
break;
}
for (const tx of res.data.transactions) {
console.log(JSON.stringify(tx, null, 2));
}
count += res.data.transactions.length;
if (count >= 20) {
break;
}
}
With reverse search, HyperSync starts from the latest block and works backwards, allowing you to efficiently access the most recent blockchain data first.
Query Structure Reference
A complete HyperSync query can include the following components:
Core Query Parameters
struct Query {
/// The block to start the query from
from_block: u64,
/// The block to end the query at (exclusive)
/// If not specified, the query runs until the end of available data
to_block: Optional<u64>,
/// Log selection criteria (OR relationship between selections)
logs: Array<LogSelection>,
/// Transaction selection criteria (OR relationship between selections)
transactions: Array<TransactionSelection>,
/// Trace selection criteria (OR relationship between selections)
traces: Array<TraceSelection>,
/// Whether to include all blocks in the requested range
/// Default: only return blocks related to matched transactions/logs
include_all_blocks: bool,
/// Fields to include in the response
field_selection: FieldSelection,
/// Maximum results limits (approximate)
max_num_blocks: Optional<usize>,
max_num_transactions: Optional<usize>,
max_num_logs: Optional<usize>,
max_num_traces: Optional<usize>,
/// Data relationship model (Default, JoinAll, or JoinNothing)
join_mode: JoinMode,
}
Selection Types
Log Selection
struct LogSelection {
/// Contract addresses to match (empty = match all)
address: Array<Address>,
/// Topics to match by position (empty = match all)
/// Each array element corresponds to a topic position (0-3)
/// Within each position, any matching value will satisfy the condition
topics: Array<Array<Topic>>,
}
Transaction Selection
struct TransactionSelection {
/// Sender addresses (empty = match all)
/// Has AND relationship with 'to' field
from: Array<Address>,
/// Recipient addresses (empty = match all)
/// Has AND relationship with 'from' field
to: Array<Address>,
/// Method signatures to match (first 4 bytes of input)
sighash: Array<Sighash>,
/// Transaction status to match (1 = success, 0 = failure)
status: Optional<u8>,
/// Transaction types to match (e.g., 0 = legacy, 2 = EIP-1559)
type: Array<u8>,
/// Created contract addresses to match
contract_address: Array<Address>,
}
Block Selection
struct BlockSelection {
/// Block hashes to match (empty = match all)
hash: Array<Hash>,
/// Miner/validator addresses to match (empty = match all)
miner: Array<Address>,
}
Trace Selection
struct TraceSelection {
/// Sender addresses (empty = match all)
/// Has AND relationship with 'to' field
from: Array<Address>,
/// Recipient addresses (empty = match all)
/// Has AND relationship with 'from' field
to: Array<Address>,
/// Created contract addresses to match
address: Array<Address>,
/// Call types to match (e.g., "call", "delegatecall")
call_type: Array<String>,
/// Reward types to match (e.g., "block", "uncle")
reward_type: Array<String>,
/// Trace types to match (e.g., "call", "create", "suicide", "reward")
kind: Array<String>,
/// Method signatures to match (first 4 bytes of input)
sighash: Array<Sighash>,
}
Field Selection
struct FieldSelection {
/// Block fields to include in response
block: Array<String>,
/// Transaction fields to include in response
transaction: Array<String>,
/// Log fields to include in response
log: Array<String>,
/// Trace fields to include in response
trace: Array<String>,
}
Data Schema
HyperSync organizes blockchain data into four main tables. Below are the available fields for each table.
When specifying fields in your query, always use snake_case names (e.g., block_number, not blockNumber).
Block Fields
class BlockField(StrEnum):
# Fields present on all EVM chains
NUMBER = 'number' # Block number
HASH = 'hash' # Block hash
PARENT_HASH = 'parent_hash' # Parent block hash
SHA3_UNCLES = 'sha3_uncles' # SHA3 of uncles data
LOGS_BLOOM = 'logs_bloom' # Bloom filter for logs
TRANSACTIONS_ROOT = 'transactions_root' # Root of transaction trie
STATE_ROOT = 'state_root' # Root of state trie
RECEIPTS_ROOT = 'receipts_root' # Root of receipts trie
MINER = 'miner' # Miner/validator address
EXTRA_DATA = 'extra_data' # Extra data field
SIZE = 'size' # Block size in bytes
GAS_LIMIT = 'gas_limit' # Block gas limit
GAS_USED = 'gas_used' # Total gas used in block
TIMESTAMP = 'timestamp' # Block timestamp (Unix time)
# Optional fields — not present on all EVM chains (may be null)
NONCE = 'nonce' # Block nonce (absent on some L2s)
DIFFICULTY = 'difficulty' # Block difficulty (PoW chains only)
TOTAL_DIFFICULTY = 'total_difficulty' # Total chain difficulty (PoW chains only)
UNCLES = 'uncles' # Uncle block hashes (absent on some L2s)
MIX_HASH = 'mix_hash' # Mix hash (absent on some L2s)
BASE_FEE_PER_GAS = 'base_fee_per_gas' # EIP-1559 base fee (post-London chains only)
BLOB_GAS_USED = 'blob_gas_used' # Total blob gas used (EIP-4844 chains only)
EXCESS_BLOB_GAS = 'excess_blob_gas' # Excess blob gas (EIP-4844 chains only)
PARENT_BEACON_BLOCK_ROOT = 'parent_beacon_block_root' # Parent beacon block root (EIP-4844 chains only)
WITHDRAWALS_ROOT = 'withdrawals_root' # Root of withdrawals trie (post-Shanghai chains only)
WITHDRAWALS = 'withdrawals' # Validator withdrawals (post-Shanghai chains only)
L1_BLOCK_NUMBER = 'l1_block_number' # L1 block number (Arbitrum only)
SEND_COUNT = 'send_count' # Send count (Arbitrum only)
SEND_ROOT = 'send_root' # Send root (Arbitrum only)
Transaction Fields
class TransactionField(StrEnum):
# Block-related fields
BLOCK_HASH = 'block_hash' # The Keccak 256-bit hash of the block
BLOCK_NUMBER = 'block_number' # Block number containing the transaction
# Transaction identifiers
HASH = 'hash' # Transaction hash (keccak hash of RLP encoded signed transaction)
TRANSACTION_INDEX = 'transaction_index' # Index of the transaction in the block
# Transaction participants
FROM = 'from' # 160-bit address of the sender
TO = 'to' # 160-bit address of the recipient (null for contract creation)
# Gas information
GAS = 'gas' # Gas limit set by sender
GAS_PRICE = 'gas_price' # Wei paid per unit of gas
GAS_USED = 'gas_used' # Actual gas used by the transaction
CUMULATIVE_GAS_USED = 'cumulative_gas_used' # Total gas used in the block up to this transaction
EFFECTIVE_GAS_PRICE = 'effective_gas_price' # Sum of base fee and tip paid per unit of gas
# EIP-1559 fields
MAX_PRIORITY_FEE_PER_GAS = 'max_priority_fee_per_gas' # Max priority fee (a.k.a. GasTipCap)
MAX_FEE_PER_GAS = 'max_fee_per_gas' # Max fee per gas (a.k.a. GasFeeCap)
# Transaction data
INPUT = 'input' # Transaction input data or contract initialization code
VALUE = 'value' # Amount of ETH transferred in wei
NONCE = 'nonce' # Number of transactions sent by the sender
# Signature fields
V = 'v' # Replay protection value (based on chain_id)
R = 'r' # The R field of the signature
S = 's' # The S field of the signature
Y_PARITY = 'y_parity' # Signature Y parity
CHAIN_ID = 'chain_id' # Chain ID for replay protection (EIP-155)
# Contract-related fields
CONTRACT_ADDRESS = 'contract_address' # Address of created contract (for contract creation txs)
# Transaction result fields
STATUS = 'status' # Success (1) or failure (0)
LOGS_BLOOM = 'logs_bloom' # Bloom filter for logs produced by this transaction
ROOT = 'root' # State root (pre-Byzantium)
# EIP-2930 fields
ACCESS_LIST = 'access_list' # List of addresses and storage keys to pre-warm
# EIP-4844 (blob transactions) fields
MAX_FEE_PER_BLOB_GAS = 'max_fee_per_blob_gas' # Max fee per data gas (blob fee cap)
BLOB_VERSIONED_HASHES = 'blob_versioned_hashes' # List of blob versioned hashes
# Transaction type
KIND = 'type' # Transaction type (0=legacy, 1=EIP-2930, 2=EIP-1559, 3=EIP-4844, 4=EIP-7702) # note - in old versions of the clients this was called 'kind', in newer versions its called 'type'
# L2-specific fields (for rollups)
L1_FEE = 'l1_fee' # Fee for L1 data (L1GasPrice × L1GasUsed)
L1_GAS_PRICE = 'l1_gas_price' # Gas price on L1
L1_GAS_USED = 'l1_gas_used' # Amount of gas consumed on L1
L1_FEE_SCALAR = 'l1_fee_scalar' # Multiplier for L1 fee calculation
GAS_USED_FOR_L1 = 'gas_used_for_l1' # Gas spent on L1 calldata in L2 gas units
Log Fields
class LogField(StrEnum):
# Log identification
LOG_INDEX = 'log_index' # Index of the log in the block
TRANSACTION_INDEX = 'transaction_index' # Index of the transaction in the block
# Transaction information
TRANSACTION_HASH = 'transaction_hash' # Hash of the transaction that created this log
# Block information
BLOCK_HASH = 'block_hash' # Hash of the block containing this log
BLOCK_NUMBER = 'block_number' # Block number containing this log
# Log content
ADDRESS = 'address' # Contract address that emitted the event
DATA = 'data' # Non-indexed data from the event
# Topics (indexed parameters)
TOPIC0 = 'topic0' # Event signature hash
TOPIC1 = 'topic1' # First indexed parameter
TOPIC2 = 'topic2' # Second indexed parameter
TOPIC3 = 'topic3' # Third indexed parameter
# Reorg information
REMOVED = 'removed' # True if log was removed due to chain reorganization
Trace Fields
class TraceField(StrEnum):
# Trace identification
TRANSACTION_HASH = 'transaction_hash' # Hash of the transaction
TRANSACTION_POSITION = 'transaction_position' # Index of the transaction in the block
SUBTRACES = 'subtraces' # Number of sub-traces created during execution
TRACE_ADDRESS = 'trace_address' # Array indicating position in the trace tree
# Block information
BLOCK_HASH = 'block_hash' # Hash of the block containing this trace
BLOCK_NUMBER = 'block_number' # Block number containing this trace
# Transaction participants
FROM = 'from' # Address of the sender
TO = 'to' # Address of the recipient (null for contract creation)
# Value and gas
VALUE = 'value' # ETH value transferred (in wei)
GAS = 'gas' # Gas limit
GAS_USED = 'gas_used' # Gas actually used
# Call data
INPUT = 'input' # Call data for function calls
INIT = 'init' # Initialization code for contract creation
OUTPUT = 'output' # Return data from the call
# Contract information
ADDRESS = 'address' # Contract address (for creation/destruction)
CODE = 'code' # Contract code
# Trace types and categorization
TYPE = 'type' # Trace type (call, create, suicide, reward)
CALL_TYPE = 'call_type' # Call type (call, delegatecall, staticcall, etc.)
REWARD_TYPE = 'reward_type' # Reward type (block, uncle)
# Other actors
AUTHOR = 'author' # Address of receiver for reward transactions
# Result information
ERROR = 'error' # Error message if failed
For a complete list of all available fields, refer to the HyperSync API Reference.
Response Structure
When you execute a HyperSync query, the response includes both metadata and the requested data:
struct QueryResponse {
/// Current height of the blockchain in HyperSync
archive_height: Optional<u64>,
/// Block number immediately after the last block included in this response.
/// Use as from_block in your next query for pagination.
next_block: u64,
/// Query execution time in milliseconds
total_execution_time: u64,
/// The actual blockchain data matching your query
data: ResponseData,
/// Information to help handle chain reorganizations
rollback_guard: Optional<RollbackGuard>,
}
The next_block value tells you where to resume scanning. See Understanding nextBlock for a clear definition and usage pattern.
Rollback Guard
The optional rollback_guard lets you detect chain reorganizations (reorgs) between successive queries, so you can re-fetch any data that has become stale.
struct RollbackGuard {
/// Last block scanned in this query
block_number: u64,
/// Timestamp of the last block scanned
timestamp: i64,
/// Hash of the last block scanned
hash: Hash,
/// First block scanned in this query
first_block_number: u64,
/// Parent hash of the first block scanned
first_parent_hash: Hash,
}
The guard is Optional<RollbackGuard>: it is present whenever the response covers blocks near the chain tip (where reorgs can still happen) and absent for queries that return no data.
How HyperSync handles reorgs internally
As HyperSync ingests new blocks it checks each block's parent_hash against the previous block's hash. When a mismatch is detected, HyperSync re-syncs the affected blocks and continues serving the canonical chain.
A single query response is always internally consistent: you will never receive a mix of blocks from different forks. The rollback guard exists to detect reorgs that happen between successive queries, where data you fetched earlier may now be stale.
Detecting a reorg
After each query, store the guard's block_number and hash. On the next query, compare:
previous response.hash(last block you saw)next response.first_parent_hash(parent of the first block in the new batch)
If they match, the chain is intact. If they differ, a reorg occurred somewhere between the two queries.
Query N: rollback_guard.hash = 0xABC... (stored)
Query N+1: rollback_guard.first_parent_hash = 0xABC... match -> no reorg
= 0xDEF... mismatch -> reorg
Recovering from a reorg
The guard tells you that a reorg happened but not how deep. To find the depth, keep enough history to cover your chain's reorg threshold (for example, 200 blocks for Polygon) and walk backwards: re-fetch each stored block's hash and compare. The first block whose hash still matches is the last canonical block; rewind your downstream state to there and resume querying.
history = [] # list of (block_number, hash)
while True:
res = client.get(query)
guard = res.rollback_guard
if guard is None:
process(res.data)
query.from_block = res.next_block
continue
if history and guard.first_parent_hash != history[-1][1]:
# Walk back to find the last block still on chain.
while history:
block_num, stored_hash = history[-1]
if client.get_block_hash(block_num) == stored_hash:
break
history.pop()
rewind_to = history[-1][0] + 1 if history else query.from_block
rollback_state_to(rewind_to)
query.from_block = rewind_to
continue
process(res.data)
history.append((guard.block_number, guard.hash))
cutoff = guard.block_number - REORG_THRESHOLD
history = [(b, h) for b, h in history if b >= cutoff]
query.from_block = res.next_block
HyperIndex handles all of this for you: it tracks recent block hashes, locates the reorg point, and rolls back database state automatically. See Reorgs Support for details.
Stream and Collect Functions
For continuous data processing or building data pipelines, client libraries provide stream and collect functions that wrap the base query functionality.
These functions are not designed for use at the blockchain tip where rollbacks may occur. For real-time data near the chain tip, implement a custom loop using the get functions and handle rollbacks manually.
Stream Function
The stream function:
- Runs multiple queries concurrently
- Returns a stream handle that yields results as they're available
- Optimizes performance through pipelined decoding/decompression
- Continues until reaching either
to_blockor the chain height at stream start