Skip to main content

Documentation Index

Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt

Use this file to discover all available pages before exploring further.

Try it Live

Run EventLog examples in the interactive playground

    Filter Fields

    Address Filter

    Single address or array (OR logic):
    import { EventLog, Address } from 'tevm';
    
    // Single address
    const matches1 = log.matchesFilter({
      address: usdcAddress,
    });
    
    // Multiple addresses
    const matches2 = log.matchesFilter({
      address: [usdcAddress, daiAddress, wethAddress],
    });
    
    // Undefined: matches all addresses
    const matches3 = log.matchesFilter({
      topics: [TRANSFER_SIG],
    });
    

    Topics Filter

    Array with null wildcards and OR logic:
    import { EventLog, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const userHash = Hash('0x000...user');
    
    const matches = log.matchesFilter({
      topics: [
        TRANSFER_SIG,  // topic0: exact match
        null,          // topic1: any value
        userHash,      // topic2: exact match
      ],
    });
    

    Block Range Filter

    Inclusive bounds on block number:
    import { EventLog } from 'tevm';
    
    // Blocks 18M to 18.5M (inclusive)
    const matches = log.matchesFilter({
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    
    // Only requires log.blockNumber to be defined
    

    Block Hash Filter

    Exact block match:
    import { EventLog, Hash } from 'tevm';
    
    const blockHash = Hash('0xabc...');
    
    const matches = log.matchesFilter({
      blockHash: blockHash,
    });
    
    // Only requires log.blockHash to be defined
    

    Filter Combinations

    All specified filters use AND logic:
    import { EventLog, Address, Hash } from 'tevm';
    
    // Must match ALL conditions
    const matches = log.matchesFilter({
      address: [usdc, dai],              // AND address is USDC or DAI
      topics: [TRANSFER_SIG, null, userHash],  // AND is Transfer to user
      fromBlock: 18000000n,               // AND block >= 18M
      toBlock: 18500000n,                 // AND block <= 18.5M
    });
    

    Usage Patterns

    Complete RPC-Style Filter

    import { EventLog, Address, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const userHash = Hash('0x000...user');
    
    // Equivalent to eth_getLogs filter
    const filtered = allLogs.filter(log =>
      log.matchesFilter({
        address: [
          Address('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), // USDC
          Address('0x6B175474E89094C44Da98b954EedeAC495271d0F'), // DAI
        ],
        topics: [
          TRANSFER_SIG,      // Transfer events
          null,              // from any
          userHash,          // to user
        ],
        fromBlock: 18000000n,
        toBlock: 18500000n,
      })
    );
    
    console.log(`Found ${filtered.length} matching logs`);
    

    Partial Filters

    Omit unnecessary fields:
    import { EventLog } from 'tevm';
    
    // Only address filter
    const byAddress = log.matchesFilter({
      address: tokenAddress,
    });
    
    // Only topics filter
    const byTopics = log.matchesFilter({
      topics: [TRANSFER_SIG, null, userHash],
    });
    
    // Only block range
    const byBlock = log.matchesFilter({
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    

    Block Hash vs Block Range

    Block hash is alternative to from/to block:
    import { EventLog, Hash } from 'tevm';
    
    // Option 1: Block range
    const range = log.matchesFilter({
      fromBlock: 18000000n,
      toBlock: 18000000n,  // Same block
    });
    
    // Option 2: Block hash (more precise)
    const hash = log.matchesFilter({
      blockHash: Hash('0xabc...'),
    });
    
    // Don't mix: blockHash takes precedence
    const mixed = log.matchesFilter({
      blockHash: Hash('0xabc...'),
      fromBlock: 18000000n,  // Ignored
      toBlock: 18500000n,    // Ignored
    });
    

    Multi-Stage Filtering

    import { EventLog, Address, Hash } from 'tevm';
    
    // Stage 1: Coarse filter (address + block range)
    const coarse = allLogs.filter(log =>
      log.matchesFilter({
        address: [usdc, dai, weth],
        fromBlock: 18000000n,
        toBlock: 18500000n,
      })
    );
    
    // Stage 2: Refined filter (specific event + parameters)
    const refined = coarse.filter(log =>
      log.matchesFilter({
        topics: [TRANSFER_SIG, null, userHash],
      })
    );
    
    console.log(`Coarse: ${coarse.length}, Refined: ${refined.length}`);
    

    Validating Log Completeness

    import { EventLog } from 'tevm';
    
    function requiresBlockNumber(filter: Filter): boolean {
      return filter.fromBlock !== undefined || filter.toBlock !== undefined;
    }
    
    function requiresBlockHash(filter: Filter): boolean {
      return filter.blockHash !== undefined;
    }
    
    // Check if log has required fields
    const filter = { fromBlock: 18000000n };
    
    if (requiresBlockNumber(filter) && log.blockNumber === undefined) {
      console.error('Log missing blockNumber for filter');
    }
    

    Batch Filtering

    For multiple logs, use filterLogs instead:
    import { EventLog } from 'tevm';
    
    // Efficient: Single pass with optimizations
    const filtered = EventLog.filterLogs(allLogs, {
      address: [usdc, dai],
      topics: [TRANSFER_SIG, null, userHash],
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    
    // Less efficient: Multiple passes
    const filtered2 = allLogs.filter(log =>
      log.matchesFilter({
        address: [usdc, dai],
        topics: [TRANSFER_SIG, null, userHash],
        fromBlock: 18000000n,
        toBlock: 18500000n,
      })
    );
    

    Missing Optional Fields

    Filter checks only apply if log has required fields:
    import { EventLog } from 'tevm';
    
    const pendingLog = EventLog({
      address: contractAddress,
      topics: [TRANSFER_SIG],
      data: Bytes(),
      // No blockNumber, blockHash, etc.
    });
    
    // Block range filter ignored (no blockNumber)
    const matches1 = pendingLog.matchesFilter({
      fromBlock: 18000000n,
      toBlock: 18500000n,
    });
    console.log(matches1); // true (block filters skipped)
    
    // Block hash filter ignored (no blockHash)
    const matches2 = pendingLog.matchesFilter({
      blockHash: Hash('0xabc...'),
    });
    console.log(matches2); // true (block hash filter skipped)
    

    See Also