TypeScript-first: In Zig, build JSON payloads with std.json and POST via std.http.Client. Use primitives.EventSignature and primitives.EventLog.parseEventLog to work with topics and decode logs.
Query historical event logs and create filters to monitor new blocks, transactions, and events.
Log Query
eth_getLogs
Query event logs matching filter criteria.
// {"method":"eth_getLogs","params":[{"fromBlock":"earliest","toBlock":"latest","address":"0x...","topics":["0xddf252ad..."]}]}
Parameters:
fromBlock: BlockTag - Starting block (default: ‘latest’)
toBlock: BlockTag - Ending block (default: ‘latest’)
address?: Address | Address[] - Contract address(es) to filter
topics?: Array<Hash | Hash[] | null> - Event topic filters
Usage patterns:
- Query historical events from contracts
- Filter by event signature (topic[0])
- Filter by indexed parameters (topic[1-3])
- Search across multiple contracts
Filter Creation
eth_newFilter
Create a log filter for event monitoring.
// {"method":"eth_newFilter","params":[{"fromBlock":"latest","toBlock":"latest","address":"0x...","topics":[]}]}
// → returns filter id (hex)
Parameters: Same as eth_getLogs
Returns: Filter ID for polling
eth_newBlockFilter
Create a filter for new block hashes.
// {"method":"eth_newBlockFilter","params":[]} → filter id
Monitor new blocks by polling for changes.
eth_newPendingTransactionFilter
Create a filter for pending transaction hashes.
// {"method":"eth_newPendingTransactionFilter","params":[]} → filter id
Monitor mempool activity by polling for new transactions.
Filter Polling
eth_getFilterChanges
Get new entries for a filter since last poll.
// {"method":"eth_getFilterChanges","params":["0xFILTER_ID"]}
Returns:
Log[] - For log filters
Hash[] - For block/transaction filters
Note: Resets the filter’s internal state - subsequent calls only return new changes.
eth_getFilterLogs
Get all logs matching a filter (does not reset state).
// {"method":"eth_getFilterLogs","params":["0xFILTER_ID"]}
Note: Only works with log filters, not block/transaction filters.
Filter Cleanup
eth_uninstallFilter
Remove a filter and free resources.
// {"method":"eth_uninstallFilter","params":["0xFILTER_ID"]}
Always uninstall filters when done to prevent resource leaks.
Usage Example
const std = @import("std");
const primitives = @import("primitives");
// Topic0 for Transfer(address,address,uint256)
const topic0 = primitives.EventSignature.fromSignature(
"Transfer(address,address,uint256)",
);
// After fetching logs (JSON-RPC), decode one Transfer log
pub fn decodeTransfer(
allocator: std.mem.Allocator,
log: primitives.EventLog.EventLog,
) !struct { from: primitives.Address, to: primitives.Address, value: u256 } {
const sig = primitives.EventLog.EventSignature{
.name = "Transfer",
.inputs = &[_]primitives.EventLog.EventInput{
.{ .name = "from", .type = .address, .indexed = true },
.{ .name = "to", .type = .address, .indexed = true },
.{ .name = "value", .type = .uint256, .indexed = false },
},
};
const vals = try primitives.EventLog.parseEventLog(allocator, log, sig);
defer allocator.free(vals);
return .{ .from = vals[0].address, .to = vals[1].address, .value = vals[2].uint256 };
}
Filter Lifecycle
- Create - Use
eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter
- Poll - Call
eth_getFilterChanges periodically to get new entries
- Query - Optionally use
eth_getFilterLogs to re-query all matches
- Cleanup - Call
eth_uninstallFilter when done
Filters expire after 5 minutes of inactivity on most nodes. Poll regularly to keep them alive.