# eth_getFilterLogs - zkSync RPC Method

Returns an array of all logs matching the filter that was previously created with `eth_newFilter` on zkSync Era. Unlike `eth_getFilterChanges` which returns only new logs since the last poll, this method returns the complete set of matching logs for the filter's block range.

> **Why zkSync?** Build on Matter Labs' flagship zkEVM powering the Elastic Network of interoperable hyperchains with ZK Stack modular framework, hyperchain interoperability, native account abstraction, and $1.9B in tokenized real-world assets.

## When to Use This Method

`eth_getFilterLogs` is essential for ZK developers, RWA tokenization teams, and builders launching custom L2/L3 chains:

- **Initial Log Retrieval** - Fetch the complete set of matching logs when you first create a filter on zkSync
- **Backfilling Event Data** - Recover historical events after an indexer restart or gap in polling
- **One-Time Queries** - Retrieve all logs for a specific block range without incremental polling
- **Data Reconciliation** - Compare against incrementally collected data from `eth_getFilterChanges` to detect missed events

## Best Practices

- Prefer `eth_getLogs` for most use cases; this method is designed for filters created with `eth_newFilter`
- Results are subject to node log retention limits; historical queries may return incomplete data
- Always call `eth_uninstallFilter` after retrieving logs to free filter resources

## Request Parameters

- `filterId` (`QUANTITY, required`): The filter ID returned by eth_newFilter. Only log filters are supported - block and pending transaction filters will return an error

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getFilterLogs",
  "params": ["0x1a"],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Address from which the log originated
- `topics` (`Array<DATA>, required`): Array of 0-4 indexed log arguments (32 bytes each)
- `data` (`DATA, required`): Non-indexed log arguments (ABI-encoded)
- `blockNumber` (`QUANTITY, required`): Block number where the log was emitted
- `transactionHash` (`DATA, required`): Hash of the transaction that generated the log
- `transactionIndex` (`QUANTITY, required`): Index position of the transaction in the block
- `blockHash` (`DATA, required`): Hash of the block containing the log
- `logIndex` (`QUANTITY, required`): Log index position in the block
- `removed` (`Boolean, required`): true if the log was removed due to a chain reorganization

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000a7a93fd0a276fc1c0197a5b5623ed117786bac38",
        "0x0000000000000000000000002f3e5f5c0b5e9b0c7e1a0e8b2f6c3d4e5a6b7c8d"
      ],
      "data": "0x00000000000000000000000000000000000000000000000000000000001e8480",
      "blockNumber": "0x1234567",
      "transactionHash": "0xabc123def456789...",
      "transactionIndex": "0x0",
      "blockHash": "0xdef456abc789012...",
      "logIndex": "0x0",
      "removed": false
    },
    {
      "address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x0000000000000000000000001234567890abcdef1234567890abcdef12345678",
        "0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12"
      ],
      "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100",
      "blockNumber": "0x1234568",
      "transactionHash": "0x789abc012def345...",
      "transactionIndex": "0x3",
      "blockHash": "0x012345def678abc...",
      "logIndex": "0x2",
      "removed": false
    }
  ]
}
```

## Error Responses

### Error Response

- Code: `-32000`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "filter not found"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
# First, create a filter
FILTER_ID=$(curl -s -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_newFilter",
    "params": [{
      "fromBlock": "0x1234500",
      "toBlock": "0x1234600",
      "address": "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91"
    }],
    "id": 1
  }' | jq -r '.result')

# Then, get all matching logs
curl -X POST https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d "{
    \"jsonrpc\": \"2.0\",
    \"method\": \"eth_getFilterLogs\",
    \"params\": [\"$FILTER_ID\"],
    \"id\": 2
  }"
```

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY');

// Create a filter for a specific block range
const filterId = await provider.send('eth_newFilter', [{
  fromBlock: '0x1234500',
  toBlock: '0x1234600',
  address: '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}]);

// Get all matching logs at once
const logs = await provider.send('eth_getFilterLogs', [filterId]);
console.log(`Found ${logs.length} matching logs`);

for (const log of logs) {
  console.log(`Block ${parseInt(log.blockNumber, 16)}: ${log.transactionHash}`);
}

// Clean up the filter
await provider.send('eth_uninstallFilter', [filterId]);
```

```python
import requests

RPC_URL = 'https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY'

def rpc_call(method, params):
    response = requests.post(RPC_URL, json={
        'jsonrpc': '2.0',
        'method': method,
        'params': params,
        'id': 1
    })
    return response.json()

# Create a filter for a specific block range
filter_result = rpc_call('eth_newFilter', [{
    'fromBlock': '0x1234500',
    'toBlock': '0x1234600',
    'address': '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'
}])
filter_id = filter_result['result']

# Get all matching logs
logs_result = rpc_call('eth_getFilterLogs', [filter_id])
logs = logs_result.get('result', [])

print(f'Found {len(logs)} matching logs')
for log in logs:
    block = int(log['blockNumber'], 16)
    print(f'  Block {block}: {log["transactionHash"]}')

# Clean up
rpc_call('eth_uninstallFilter', [filter_id])
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-zksync-era-mainnet-full.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(0x1234500),
        ToBlock:   big.NewInt(0x1234600),
        Addresses: []common.Address{contractAddress},
    }

    logs, err := client.FilterLogs(context.Background(), query)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d matching logs\n", len(logs))
    for _, l := range logs {
        fmt.Printf("  Block %d: %s\n", l.BlockNumber, l.TxHash.Hex())
    }
}
```

## Common Use Cases

### 1. Backfill Event Data After Indexer Restart

Recover missed events when your indexer goes down and comes back:

```javascript
async function backfillEvents(provider, contractAddress, topics, lastProcessedBlock) {
  const currentBlock = await provider.getBlockNumber();

  // Create a filter covering the gap
  const filterId = await provider.send('eth_newFilter', [{
    fromBlock: '0x' + (lastProcessedBlock + 1).toString(16),
    toBlock: '0x' + currentBlock.toString(16),
    address: contractAddress,
    topics: topics
  }]);

  // Retrieve all logs in the gap
  const logs = await provider.send('eth_getFilterLogs', [filterId]);
  console.log(`Backfilling ${logs.length} events from blocks ${lastProcessedBlock + 1} to ${currentBlock}`);

  for (const log of logs) {
    await processEvent(log);
  }

  // Clean up and switch to incremental polling
  await provider.send('eth_uninstallFilter', [filterId]);
  return currentBlock;
}
```

### 2. Compare Filter Results with Direct Query

Verify data consistency between filter-based and direct log queries:

```javascript
async function verifyFilterResults(provider, filterParams) {
  // Create filter and get logs via eth_getFilterLogs
  const filterId = await provider.send('eth_newFilter', [filterParams]);
  const filterLogs = await provider.send('eth_getFilterLogs', [filterId]);

  // Get logs directly via eth_getLogs
  const directLogs = await provider.send('eth_getLogs', [filterParams]);

  console.log(`Filter logs: ${filterLogs.length}, Direct logs: ${directLogs.length}`);

  if (filterLogs.length !== directLogs.length) {
    console.warn('Mismatch detected - investigate missing events');
  }

  await provider.send('eth_uninstallFilter', [filterId]);
  return { filterLogs, directLogs };
}
```

### 3. Paginated Historical Event Loader

Load large volumes of historical events in manageable chunks:

```javascript
async function loadHistoricalEvents(provider, contractAddress, startBlock, endBlock, chunkSize = 2000) {
  const allLogs = [];

  for (let from = startBlock; from <= endBlock; from += chunkSize) {
    const to = Math.min(from + chunkSize - 1, endBlock);

    const filterId = await provider.send('eth_newFilter', [{
      fromBlock: '0x' + from.toString(16),
      toBlock: '0x' + to.toString(16),
      address: contractAddress
    }]);

    const logs = await provider.send('eth_getFilterLogs', [filterId]);
    allLogs.push(...logs);

    console.log(`Blocks ${from}-${to}: ${logs.length} events (total: ${allLogs.length})`);

    await provider.send('eth_uninstallFilter', [filterId]);
  }

  return allLogs;
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zksync-era/eth_newFilter) - Create the log filter whose results this method returns
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zksync-era/eth_getFilterChanges) - Poll for only new logs since the last call (incremental)
- [`eth_getLogs`](https://www.dwellir.com/docs/zksync-era/eth_getLogs) - Query logs directly without creating a filter first
- [`eth_uninstallFilter`](https://www.dwellir.com/docs/zksync-era/eth_uninstallFilter) - Remove a filter when no longer needed
