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 Semantics

    Null Wildcard

    null at any position matches any topic value:
    import { EventLog, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    
    // Match Transfer events with any from/to addresses
    const matches = log.matchesTopics([
      TRANSFER_SIG,  // topic0 must be Transfer signature
      null,          // topic1 can be any address
      null,          // topic2 can be any address
    ]);
    

    Single Hash Match

    Specific hash must match exactly at that position:
    import { EventLog, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const userHash = Hash('0x000000000000000000000000a1b2c3d4...');
    
    // Match Transfer events TO specific user
    const matches = log.matchesTopics([
      TRANSFER_SIG,  // Exact signature
      null,          // from: any
      userHash,      // to: specific user
    ]);
    

    Array of Hashes (OR Logic)

    Matches if log topic equals ANY hash in the array:
    import { EventLog, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const APPROVAL_SIG = Hash('0x8c5be1e5...');
    
    // Match Transfer OR Approval events
    const matches = log.matchesTopics([
      [TRANSFER_SIG, APPROVAL_SIG],  // topic0 can be either
    ]);
    

    Empty Filter Array

    Empty filter matches all logs:
    import { EventLog } from 'tevm';
    
    // Matches all logs
    const matches = log.matchesTopics([]);
    console.log(matches); // true
    

    Usage Patterns

    ERC-20 Transfer Filtering

    import { EventLog, Address, Hash } from 'tevm';
    
    // Transfer(address indexed from, address indexed to, uint256 value)
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const userAddress = Address('0xa1b2c3d4...');
    const userHash = Hash(
      new Uint8Array([...new Uint8Array(12).fill(0), ...userAddress])
    );
    
    // All transfers FROM user
    const outgoing = allLogs.filter(log =>
      log.matchesTopics([TRANSFER_SIG, userHash, null])
    );
    
    // All transfers TO user
    const incoming = allLogs.filter(log =>
      log.matchesTopics([TRANSFER_SIG, null, userHash])
    );
    
    // All transfers involving user (from OR to)
    const userTransfers = allLogs.filter(log =>
      log.matchesTopics([TRANSFER_SIG, userHash, null]) ||
      log.matchesTopics([TRANSFER_SIG, null, userHash])
    );
    
    console.log(`Outgoing: ${outgoing.length}`);
    console.log(`Incoming: ${incoming.length}`);
    console.log(`Total: ${userTransfers.length}`);
    

    Multiple Event Types

    import { EventLog, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const APPROVAL_SIG = Hash('0x8c5be1e5...');
    const SWAP_SIG = Hash('0xd78ad95f...');
    
    // Match any of these event types
    const relevantLogs = allLogs.filter(log =>
      log.matchesTopics([[TRANSFER_SIG, APPROVAL_SIG, SWAP_SIG]])
    );
    
    console.log(`Found ${relevantLogs.length} relevant events`);
    

    Intra-Group Transfers

    import { EventLog, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    
    // Addresses in the group
    const groupHashes = [
      Hash('0x000...addr1'),
      Hash('0x000...addr2'),
      Hash('0x000...addr3'),
    ];
    
    // Transfers between any group members
    const intraGroupTransfers = allLogs.filter(log =>
      log.matchesTopics([
        TRANSFER_SIG,
        groupHashes,  // from: any group member
        groupHashes,  // to: any group member
      ])
    );
    
    console.log(`Intra-group transfers: ${intraGroupTransfers.length}`);
    

    DEX Swap Monitoring

    import { EventLog, Hash } from 'tevm';
    
    // Uniswap V2 Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to)
    const SWAP_SIG = Hash('0xd78ad95f...');
    const routerHash = Hash('0x000...router');
    
    // Swaps initiated by router
    const routerSwaps = allLogs.filter(log =>
      log.matchesTopics([SWAP_SIG, routerHash])
    );
    

    NFT Transfer Tracking

    import { EventLog, Hash } from 'tevm';
    
    // Transfer(address indexed from, address indexed to, uint256 indexed tokenId)
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const zeroHash = Hash('0x0000000000000000000000000000000000000000000000000000000000000000');
    
    // NFT mints (from zero address)
    const mints = allLogs.filter(log =>
      log.matchesTopics([TRANSFER_SIG, zeroHash, null])
    );
    
    // NFT burns (to zero address)
    const burns = allLogs.filter(log =>
      log.matchesTopics([TRANSFER_SIG, null, zeroHash])
    );
    
    console.log(`Mints: ${mints.length}`);
    console.log(`Burns: ${burns.length}`);
    

    Anonymous Event Handling

    import { EventLog } from 'tevm';
    
    // Anonymous events: topic0 is first indexed param, not signature
    const anonymousLog = EventLog({
      address: contractAddress,
      topics: [param1Hash, param2Hash, param3Hash],
      data: Bytes(),
    });
    
    // Match by first indexed parameter (NOT signature)
    const matches = anonymousLog.matchesTopics([
      param1Hash,  // topic0 is first param
      null,        // topic1 is second param (any)
      param3Hash,  // topic2 is third param
    ]);
    

    Advanced Patterns

    Complex Boolean Logic

    import { EventLog, Hash } from 'tevm';
    
    const TRANSFER_SIG = Hash('0xddf252ad...');
    const user1Hash = Hash('0x000...user1');
    const user2Hash = Hash('0x000...user2');
    const user3Hash = Hash('0x000...user3');
    
    // (from:user1 AND to:user2) OR (from:user2 AND to:user3)
    const complexFilter = allLogs.filter(log =>
      (log.matchesTopics([TRANSFER_SIG, user1Hash, user2Hash]) ||
       log.matchesTopics([TRANSFER_SIG, user2Hash, user3Hash]))
    );
    

    Partial Filter (Fewer Topics)

    Filter can have fewer topics than log:
    import { EventLog, Hash } from 'tevm';
    
    const log = EventLog({
      address: contractAddress,
      topics: [topic0, topic1, topic2, topic3], // 4 topics
      data: Bytes(),
    });
    
    // Match only first 2 topics
    const matches = log.matchesTopics([topic0, topic1]);
    console.log(matches); // true (remaining topics ignored)
    

    Empty Topics Check

    import { EventLog } from 'tevm';
    
    const log = EventLog({
      address: contractAddress,
      topics: [], // No topics
      data: Bytes(),
    });
    
    // Filter with topics fails
    const matches1 = log.matchesTopics([Hash('0x...')]);
    console.log(matches1); // false
    
    // Empty filter matches
    const matches2 = log.matchesTopics([]);
    console.log(matches2); // true
    

    Performance

    Uses constant-time hash comparison for security:
    import { EventLog } from 'tevm';
    
    // Comparison time doesn't leak which topics match
    const matches = log.matchesTopics([sig, null, userHash]);
    
    For large datasets, use filterLogs for optimized batch filtering:
    import { EventLog } from 'tevm';
    
    // Efficient batch filtering
    const filtered = EventLog.filterLogs(allLogs, {
      topics: [TRANSFER_SIG, null, userHash],
    });
    

    See Also