Skip to main content

Try it Live

Run EventLog examples in the interactive playground

    Usage Patterns

    ERC-20 Transfer Filtering

    import { EventLog, Address, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const userAddress = Address('0xa1b2c3d4...');
    const userHash = Hash(
      Hex.concat(Hex('0x000000000000000000000000'), Address.toHex(userAddress))
    );
    
    // All incoming transfers to user
    const incoming = EventLog.filterLogs(allLogs, {
      address: usdcAddress,
      topics: [TRANSFER_SIG, null, userHash],
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    
    // All outgoing transfers from user
    const outgoing = EventLog.filterLogs(allLogs, {
      address: usdcAddress,
      topics: [TRANSFER_SIG, userHash, null],
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    
    // Calculate net change
    let netChange = 0n;
    for (const log of incoming) {
      const value = new DataView(log.data.buffer).getBigUint64(24, false);
      netChange += value;
    }
    for (const log of outgoing) {
      const value = new DataView(log.data.buffer).getBigUint64(24, false);
      netChange -= value;
    }
    
    console.log(`Net change: ${netChange}`);
    console.log(`Incoming: ${incoming.length} transfers`);
    console.log(`Outgoing: ${outgoing.length} transfers`);
    

    Multi-Token Monitoring

    import { EventLog, Address, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    
    const tokens = [
      Address('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), // USDC
      Address('0x6B175474E89094C44Da98b954EedeAC495271d0F'), // DAI
      Address('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), // WETH
      Address('0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599'), // WBTC
    ];
    
    // All Transfer events from these tokens
    const transfers = EventLog.filterLogs(allLogs, {
      address: tokens,
      topics: [TRANSFER_SIG],
      fromBlock: 18000000n,
    });
    
    // Group by token
    const byToken = new Map();
    for (const log of transfers) {
      const addr = Address.toHex(log.address);
      if (!byToken.has(addr)) {
        byToken.set(addr, []);
      }
      byToken.get(addr).push(log);
    }
    
    console.log(`Total transfers: ${transfers.length}`);
    console.log(`Tokens with activity: ${byToken.size}`);
    

    Multiple Event Types

    import { EventLog, Address, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const APPROVAL_SIG = Hash('0x8c5be1e5...');
    const SWAP_SIG = Hash('0xd78ad95f...');
    
    // Transfer, Approval, or Swap events
    const filtered = EventLog.filterLogs(allLogs, {
      address: usdcAddress,
      topics: [[TRANSFER_SIG, APPROVAL_SIG, SWAP_SIG]],
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    
    // Separate by event type
    const transfers = filtered.filter(log => {
      const sig = log.getTopic0();
      return sig && Hash.equals(sig, TRANSFER_SIG);
    });
    
    const approvals = filtered.filter(log => {
      const sig = log.getTopic0();
      return sig && Hash.equals(sig, APPROVAL_SIG);
    });
    
    const swaps = filtered.filter(log => {
      const sig = log.getTopic0();
      return sig && Hash.equals(sig, SWAP_SIG);
    });
    
    console.log(`Transfers: ${transfers.length}`);
    console.log(`Approvals: ${approvals.length}`);
    console.log(`Swaps: ${swaps.length}`);
    

    Block Range Analysis

    import { EventLog, Address, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    
    // Process in 100k block chunks
    const chunkSize = 100000n;
    const startBlock = 18000000n;
    const endBlock = 18500000n;
    
    for (let from = startBlock; from < endBlock; from += chunkSize) {
      const to = from + chunkSize - 1n;
    
      const chunkLogs = EventLog.filterLogs(allLogs, {
        address: usdcAddress,
        topics: [TRANSFER_SIG],
        fromBlock: from,
        toBlock: to,
      });
    
      console.log(`Blocks ${from}-${to}: ${chunkLogs.length} transfers`);
    
      // Process chunk
      // ...
    }
    

    Specific Block Query

    import { EventLog, Hash } from 'tevm';
    
    const blockHash = Hash('0xabc...');
    
    // All logs in specific block
    const blockLogs = EventLog.filterLogs(allLogs, {
      blockHash: blockHash,
    });
    
    console.log(`Block contains ${blockLogs.length} logs`);
    

    Progressive Filtering

    import { EventLog, Address, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const APPROVAL_SIG = Hash('0x8c5be1e5...');
    
    // Stage 1: Filter by contract
    const tokenLogs = EventLog.filterLogs(allLogs, {
      address: usdcAddress,
    });
    
    // Stage 2: Filter by event type
    const relevantLogs = EventLog.filterLogs(tokenLogs, {
      topics: [[TRANSFER_SIG, APPROVAL_SIG]],
    });
    
    // Stage 3: Filter by block range
    const recentLogs = EventLog.filterLogs(relevantLogs, {
      fromBlock: 18000000n,
    });
    
    console.log(`Stage 1: ${tokenLogs.length} logs`);
    console.log(`Stage 2: ${relevantLogs.length} logs`);
    console.log(`Stage 3: ${recentLogs.length} logs`);
    

    Combining with Sorting

    import { EventLog, Address, Hash } from 'tevm';
    
    const filtered = EventLog.filterLogs(allLogs, {
      address: [usdc, dai, weth],
      topics: [TRANSFER_SIG],
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    
    // Sort chronologically
    const sorted = EventLog.sortLogs(filtered);
    
    // Process in order
    for (const log of sorted) {
      console.log(`Block ${log.blockNumber}, Index ${log.logIndex}`);
      // ... decode and process
    }
    

    Empty Filter

    Empty filter returns all logs:
    import { EventLog } from 'tevm';
    
    // No filtering (returns all)
    const all = EventLog.filterLogs(allLogs, {});
    
    console.log(`All logs: ${all.length}`);
    

    Performance

    filterLogs is optimized for batch operations: Internal optimizations:
    • Single pass through input array
    • Early exit for non-matching logs
    • Efficient address/hash comparisons
    Best practices:
    // Good: Single filterLogs call
    const filtered = EventLog.filterLogs(allLogs, {
      address: [usdc, dai],
      topics: [TRANSFER_SIG, null, userHash],
      fromBlock: 18000000n,
    });
    
    // Less efficient: Multiple passes
    const step1 = allLogs.filter(log => log.matchesAddress([usdc, dai]));
    const step2 = step1.filter(log => log.matchesTopics([TRANSFER_SIG, null, userHash]));
    const step3 = step2.filter(log => log.blockNumber >= 18000000n);
    

    Return Value

    Returns new array (doesn’t modify input):
    import { EventLog } from 'tevm';
    
    const original = [log1, log2, log3];
    const filtered = EventLog.filterLogs(original, { address: usdcAddress });
    
    console.log(original.length); // 3 (unchanged)
    console.log(filtered.length); // 1 (new array)
    

    See Also