> ## 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.

# EventLog.matchesFilter

> Check if log matches complete filter with address, topics, and block range

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=primitives/event-log.ts">
  Run EventLog examples in the interactive playground
</Card>

<Tabs />

## Filter Fields

### Address Filter

Single address or array (OR logic):

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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

* [matchesAddress](/primitives/eventlog/matchesaddress) - Address filtering
* [matchesTopics](/primitives/eventlog/matchestopics) - Topic filtering
* [filterLogs](/primitives/eventlog/filterlogs) - Batch filtering (recommended for arrays)
* [Fundamentals](/primitives/eventlog/fundamentals) - Filter semantics
