Try it Live
Run EventLog examples in the interactive playground
Usage Patterns
Practical patterns for filtering, parsing, and processing Ethereum event logs.Log Filtering
Filter by Event Signature
Copy
Ask AI
import * as EventLog from 'tevm/EventLog';
import * as Event from 'tevm/Event';
// Define Transfer event
const transferEvent = {
type: "event",
name: "Transfer",
inputs: [
{ type: "address", name: "from", indexed: true },
{ type: "address", name: "to", indexed: true },
{ type: "uint256", name: "value", indexed: false }
]
};
// Get logs for specific event
async function getTransferLogs(
provider: Provider,
tokenAddress: string,
fromBlock: number,
toBlock: number
): Promise<EventLog[]> {
const topic0 = Event.getSelector(transferEvent);
const logs = await provider.getLogs({
address: tokenAddress,
fromBlock,
toBlock,
topics: [topic0]
});
return logs.map(log => EventLog(log));
}
Filter by Indexed Parameters
Copy
Ask AI
// Filter Transfer events from specific address
async function getTransfersFrom(
provider: Provider,
tokenAddress: string,
fromAddress: string
): Promise<EventLog[]> {
const topic0 = Event.getSelector(transferEvent);
const topic1 = Event.encodeIndexed(
{ type: "address" },
fromAddress
);
const logs = await provider.getLogs({
address: tokenAddress,
topics: [topic0, topic1] // topic0 = event sig, topic1 = from
});
return logs.map(log => EventLog(log));
}
// Filter by multiple addresses (OR condition)
async function getTransfersFromMultiple(
provider: Provider,
tokenAddress: string,
addresses: string[]
): Promise<EventLog[]> {
const topic0 = Event.getSelector(transferEvent);
const topics1 = addresses.map(addr =>
Event.encodeIndexed({ type: "address" }, addr)
);
const logs = await provider.getLogs({
address: tokenAddress,
topics: [topic0, topics1] // Multiple options for topic1
});
return logs.map(log => EventLog(log));
}
Log Parsing
Decode Event Data
Copy
Ask AI
// Parse Transfer event
function parseTransferLog(log: EventLogType): {
from: string;
to: string;
value: bigint;
} {
// Decode indexed topics
const from = EventLog.getIndexed(log, 0); // First indexed param
const to = EventLog.getIndexed(log, 1); // Second indexed param
// Decode non-indexed data
const decoded = Event.decodeLog(transferEvent, log.data, log.topics);
return {
from: decoded.from,
to: decoded.to,
value: decoded.value
};
}
// Batch parsing
function parseTransferLogs(logs: EventLogType[]): Array<{
from: string;
to: string;
value: bigint;
blockNumber: number;
transactionHash: string;
}> {
return logs.map(log => ({
...parseTransferLog(log),
blockNumber: log.blockNumber,
transactionHash: log.transactionHash
}));
}
Multi-event Parsing
Copy
Ask AI
// Parse mixed event types
interface EventRegistry {
[signature: string]: {
name: string;
definition: any;
};
}
function createEventRegistry(events: any[]): EventRegistry {
const registry: EventRegistry = {};
for (const event of events) {
const sig = Event.getSelector(event);
registry[sig] = {
name: event.name,
definition: event
};
}
return registry;
}
// Parse with registry
function parseLog(
log: EventLogType,
registry: EventRegistry
): { name: string; args: any } | null {
const signature = EventLog.getSignature(log);
const event = registry[signature];
if (!event) return null;
const args = Event.decodeLog(event.definition, log.data, log.topics);
return {
name: event.name,
args
};
}
Log Filtering and Sorting
Filter by Address
Copy
Ask AI
// Check if log is from specific address
function isFromAddress(
log: EventLogType,
address: string
): boolean {
return EventLog.matchesAddress(log, address);
}
// Filter logs by address
function filterByAddress(
logs: EventLogType[],
address: string
): EventLogType[] {
return logs.filter(log => EventLog.matchesAddress(log, address));
}
// Filter by multiple addresses
function filterByAddresses(
logs: EventLogType[],
addresses: string[]
): EventLogType[] {
return logs.filter(log =>
addresses.some(addr => EventLog.matchesAddress(log, addr))
);
}
Filter by Topics
Copy
Ask AI
// Create topic filter
interface TopicFilter {
topic0?: string;
topic1?: string | string[];
topic2?: string | string[];
topic3?: string | string[];
}
function matchesTopicFilter(
log: EventLogType,
filter: TopicFilter
): boolean {
return EventLog.matchesTopics(log, [
filter.topic0,
filter.topic1,
filter.topic2,
filter.topic3
]);
}
// Filter logs
function filterLogs(
logs: EventLogType[],
filter: TopicFilter
): EventLogType[] {
return logs.filter(log => matchesTopicFilter(log, filter));
}
Sort Logs
Copy
Ask AI
// Sort by block number and log index
function sortLogs(logs: EventLogType[]): EventLogType[] {
return EventLog.sortLogs(logs);
}
// Sort in reverse (newest first)
function sortLogsDescending(logs: EventLogType[]): EventLogType[] {
return EventLog.sortLogs(logs).reverse();
}
// Group by block
function groupByBlock(
logs: EventLogType[]
): Map<number, EventLogType[]> {
const groups = new Map<number, EventLogType[]>();
for (const log of logs) {
const blockLogs = groups.get(log.blockNumber) ?? [];
blockLogs.push(log);
groups.set(log.blockNumber, blockLogs);
}
return groups;
}
Reorg Handling
Detect Removed Logs
Copy
Ask AI
// Check if log was removed due to reorg
function checkForReorgs(logs: EventLogType[]): {
valid: EventLogType[];
removed: EventLogType[];
} {
const valid: EventLogType[] = [];
const removed: EventLogType[] = [];
for (const log of logs) {
if (EventLog.isRemoved(log)) {
removed.push(log);
} else {
valid.push(log);
}
}
return { valid, removed };
}
// Filter out removed logs
function filterRemoved(logs: EventLogType[]): EventLogType[] {
return logs.filter(log => !EventLog.isRemoved(log));
}
Reorg-safe Log Processing
Copy
Ask AI
// Process logs with reorg handling
async function processLogsWithReorgHandling(
provider: Provider,
fromBlock: number,
toBlock: number,
confirmations: number = 12
): Promise<void> {
const confirmedBlock = await provider.getBlockNumber() - confirmations;
const actualToBlock = Math.min(toBlock, confirmedBlock);
const logs = await provider.getLogs({
fromBlock,
toBlock: actualToBlock
});
// Process only confirmed logs
const validLogs = filterRemoved(logs.map(EventLog.from));
for (const log of validLogs) {
await processLog(log);
}
}
Real-time Monitoring
Subscribe to Events
Copy
Ask AI
// Monitor Transfer events in real-time
async function monitorTransfers(
provider: Provider,
tokenAddress: string,
callback: (log: EventLogType) => void
): Promise<() => void> {
const topic0 = Event.getSelector(transferEvent);
// Subscribe to logs
const filter = {
address: tokenAddress,
topics: [topic0]
};
provider.on(filter, (rawLog) => {
const log = EventLog(rawLog);
callback(log);
});
// Return unsubscribe function
return () => provider.off(filter);
}
// Usage
const unsubscribe = await monitorTransfers(
provider,
tokenAddress,
(log) => {
const { from, to, value } = parseTransferLog(log);
console.log(`Transfer: ${from} → ${to}: ${value}`);
}
);
Batch Processing
Copy
Ask AI
// Process logs in batches
async function processLogsBatched(
provider: Provider,
fromBlock: number,
toBlock: number,
batchSize: number = 10000
): Promise<void> {
for (let start = fromBlock; start <= toBlock; start += batchSize) {
const end = Math.min(start + batchSize - 1, toBlock);
const logs = await provider.getLogs({
fromBlock: start,
toBlock: end
});
const eventLogs = logs.map(EventLog.from);
await processBatch(eventLogs);
console.log(`Processed blocks ${start} to ${end}`);
}
}
Aggregation
Calculate Totals
Copy
Ask AI
// Sum transfer amounts
function calculateTotalTransferred(
logs: EventLogType[]
): bigint {
let total = 0n;
for (const log of logs) {
const { value } = parseTransferLog(log);
total += value;
}
return total;
}
// Group by sender
function groupBySender(
logs: EventLogType[]
): Map<string, bigint> {
const totals = new Map<string, bigint>();
for (const log of logs) {
const { from, value } = parseTransferLog(log);
const current = totals.get(from) ?? 0n;
totals.set(from, current + value);
}
return totals;
}
Track Balances
Copy
Ask AI
// Build balance map from Transfer events
function buildBalanceMap(
logs: EventLogType[]
): Map<string, bigint> {
const balances = new Map<string, bigint>();
const sorted = EventLog.sortLogs(logs);
for (const log of sorted) {
const { from, to, value } = parseTransferLog(log);
// Debit from sender
if (from !== "0x0000000000000000000000000000000000000000") {
const fromBalance = balances.get(from) ?? 0n;
balances.set(from, fromBalance - value);
}
// Credit to receiver
const toBalance = balances.get(to) ?? 0n;
balances.set(to, toBalance + value);
}
return balances;
}
Testing
Mock Logs
Copy
Ask AI
// Create test log
function createTestLog(overrides?: Partial<EventLog>): EventLogType {
return EventLog.create({
address: "0x1234567890123456789012345678901234567890",
topics: [
Event.getSelector(transferEvent),
Event.encodeIndexed({ type: "address" }, "0xalice"),
Event.encodeIndexed({ type: "address" }, "0xbob")
],
data: Event.encode([{ type: "uint256" }], [1000n]),
blockNumber: 100,
transactionHash: "0xabc123",
transactionIndex: 0,
blockHash: "0xblock",
logIndex: 0,
removed: false,
...overrides
});
}
// Create batch of test logs
function createTestLogs(count: number): EventLogType[] {
return Array({ length: count }, (_, i) =>
createTestLog({
blockNumber: 100 + i,
logIndex: i
})
);
}
Related
- filterLogs - Log filtering
- matchesFilter - Filter matching
- sortLogs - Log sorting
- isRemoved - Reorg detection
- Fundamentals - Event log basics

