MIP-16 query methods
MIP-16 adds RPC query methods that filter on the server, return only the fields you select, and can join related objects, such as each log's transaction and block. HyperRPC serves them on every supported network, mainnets and testnets alike, alongside the standard methods.
Methods
| Method | Filters | Status |
|---|---|---|
eth_queryBlocks | miner | Live |
eth_queryTransactions | from, to, function selector | Live |
eth_queryLogs | address, topics | Live |
eth_queryTraces | Coming soon | |
eth_queryTransfers | Coming soon |
See the MIP-16 spec and its latest revision for every filter and field.
Endpoints
Send MIP-16 requests to the same HyperRPC endpoint you use for standard methods on any network:
https://<network>.rpc.hypersync.xyz/<api-token>
Find the endpoint for each network on the supported networks page. Requests need an API token. See API Tokens for how to create one.
Example
The request works the same way on every network. This one runs on Monad and returns the most recent WMON deposit() calls, newest first. It filters by the WMON contract address and the deposit() function selector.
curl https://monad.rpc.hypersync.xyz/<api-token> \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_queryTransactions",
"params": [{
"filter": {
"to": "0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A",
"selector": "0xd0e30db0"
},
"fields": {
"transactions": ["hash", "from", "value", "blockNumber"]
},
"order": "desc"
}]
}'
The first page may be empty, so keep paging (see below). A page with a match looks like this:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"data": {
"transactions": [
{
"blockNumber": "0x725e079",
"from": "0x39c06b54686b0540d6d57a254b976b1df4310df1",
"hash": "0xb22654167eb03199c54907d11bc0757003576ee90f41232394bb596c80e2d49f",
"value": "0x1b1ae4d6e2ef500000"
}
]
},
"fromBlock": {
"number": "0x725e3d2",
"hash": "0xbb79588ba79c36ab2768ead580c0e84175f29cfd229d714aa1ca7b1b1e1a0cbb",
"parentHash": "0x9c021696e3622c938b0f5b0ff8311c7f1e4a2181b8f712a8951072680b1b46a5"
},
"toBlock": {
"number": "0x0",
"hash": "0x0c47353304f22b1c15706367d739b850cda80b5c87bbc335014fef3d88deaac9",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
"cursorBlock": {
"number": "0x725dfeb",
"hash": "0x94a8412730cffc4c3ce9b2c6b0eefd8fbef93b50f664646d8e0c0d3d2dfdd7f9",
"parentHash": "0x778b1459435ef59b8b1c9ec8c90023126bec785b1bffe52032a699ea0347104c"
}
}
}
Request parameters
| Parameter | Required | Description |
|---|---|---|
fromBlock | No | Start of the range, as a hex block number such as 0x725e079 or a tag such as latest or earliest. With desc, this is the newest block |
toBlock | No | End of the range, as a hex block number or a tag. With desc, this is the oldest block |
order | No | asc (default, oldest first) or desc (newest first) |
target | No | Target number of results per page, as hex (for example 0x64). Joined objects don't count towards it |
filter | No | Method-specific filters, such as to and selector for transactions |
fields | No | Fields to return, and related objects to join. If you set it, include the method's own type, such as logs for eth_queryLogs |
Response fields
| Field | Description |
|---|---|
data | The matching results, with only the fields you selected, plus any joined objects |
fromBlock | The first block of the page, with its hash and parent hash |
toBlock | The last block of the requested range |
cursorBlock | The last block this page covers |
Paging
Every page ends on a whole block, reported as cursorBlock. To get the next page, repeat the request with a new fromBlock:
| Order | Next fromBlock |
|---|---|
asc (default) | cursorBlock + 1 |
desc | cursorBlock - 1 |
A page can return fewer results than target, or none. Keep paging from cursorBlock until you have the results you need or reach toBlock.
Reorg detection
When you page forwards near the chain tip, compare each page's fromBlock.parentHash with the previous page's cursorBlock.hash. If they differ, a reorg has replaced blocks you already read, so roll back to the newest block you hold that still matches, and page again from the block after it.
Errors
| Code | Meaning |
|---|---|
-32602 | Invalid params, such as an unknown request field or fields without the method's own type |
-32001 | Some or all of the requested range, including blocks not yet produced, is outside the blocks HyperRPC serves |
-32004 | The method isn't supported yet |
-32005 | The first block of the range was too large to return in one page |
HTTP 429 | Rate limited. Wait before retrying |
Hand this to your coding agent
Using the MIP-16 method eth_queryLogs on Envio HyperRPC, write a Node.js script
that collects every Transfer event from the token contract I name, over the block
range I give, with the sender of each transaction and the timestamp of each block.
- Use https://<network>.rpc.hypersync.xyz/$ENVIO_API_TOKEN for the network I name
- Filter by address and the Transfer topic
- Request logs, transactions and blocks in one call with fields.logs,
fields.transactions and fields.blocks
- Include the join fields: fields.logs needs transactionHash and blockNumber,
fields.transactions needs hash and from, fields.blocks needs number and
timestamp
- Join them with logs.transactionHash = transactions.hash and
logs.blockNumber = blocks.number
- Send block numbers as 0x-prefixed hex
- Page with cursorBlock: the next request starts at cursorBlock + 1, until
cursorBlock reaches toBlock
- If the response is HTTP 429, wait and retry
Docs: https://docs.envio.dev/docs/HyperRPC/mip-16
Spec: https://github.com/monad-crypto/MIPs/blob/main/MIPs/MIP-16.md