# eth_getLogs - Zetachain RPC Method

Returns an array of all logs matching a given filter object on Zetachain.

> **Why Zetachain?** Build on the universal omnichain blockchain enabling cross-chain smart contracts across 50+ chains including Bitcoin with native Bitcoin support, 50+ chain interoperability via UNISON, no bridging required, and partnerships with Curve and SushiSwap.

## When to Use This Method

The `eth_getLogs` method serves these key scenarios for cross-chain dApp developers, Bitcoin DeFi builders, and teams requiring native multi-chain interoperability:

- **Index smart contract events** - Track transfers, swaps, and approvals emitted by any contract on Zetachain for use in indexed databases
- **Monitor DeFi protocol activity** - Watch for liquidity changes, price updates, and position events in real time across omnichain DeFi, native Bitcoin smart contracts, cross-chain asset management, and unified liquidity aggregation
- **Build analytics pipelines** - Extract on-chain event data for dashboards, reporting, and trend analysis on Zetachain
- **Track token holder activity** - Monitor whale movements and large transfers to detect significant market activity

## Common Use Cases

### 1. Monitor ERC20 Transfer Events

Track all transfer events for a specific token contract within a defined block range. The Transfer event signature hash filters for exactly this event type, and you can optionally filter by sender or recipient address using indexed topics.

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

const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');
const tokenAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getRecentTransfers(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [transferTopic]
  });

  const transfers = logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount: BigInt(log.data).toString(),
    txHash: log.transactionHash
  }));

  console.log(`Found ${transfers.length} transfers`);
  return transfers;
}

const recentTransfers = await getRecentTransfers('latest', 'latest');
```

### 2. Track DEX Swap Events

Capture swap events from a DEX to analyze trading volume, price impact, and liquidity flow. Each swap emits event parameters that include the amounts and addresses involved - ideal for building price feeds and volume aggregators.

```javascript
const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const pairAddress = '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf';

async function getRecentSwaps(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: pairAddress,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [SWAP_TOPIC]
  });

  return logs.map(log => ({
    sender: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    amount0In: BigInt('0x' + log.data.slice(2, 66)).toString(),
    amount1In: BigInt('0x' + log.data.slice(66, 130)).toString(),
    amount0Out: BigInt('0x' + log.data.slice(130, 194)).toString(),
    amount1Out: BigInt('0x' + log.data.slice(194, 258)).toString(),
    txHash: log.transactionHash
  }));
}

const swaps = await getRecentSwaps('latest', 'latest');
console.log(`Found ${swaps.length} swaps`);
```

### 3. Multi-Contract Event Aggregation

Query events from multiple contracts simultaneously by passing an array of addresses. This is useful for cross-protocol analytics - aggregating lending, borrowing, and liquidation events from multiple DeFi protocols in a single query on Zetachain.

```javascript
const provider = new JsonRpcProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY');

const contracts = [
  '0xContractA...',
  '0xContractB...',
  '0xContractC...'
];

const EVENT_TOPIC = '0x...';

async function aggregateEvents(fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: contracts,
    fromBlock: fromBlock,
    toBlock: toBlock,
    topics: [EVENT_TOPIC]
  });

  const grouped = {};
  for (const log of logs) {
    const contract = log.address;
    if (!grouped[contract]) grouped[contract] = [];
    grouped[contract].push(log);
  }

  for (const [contract, events] of Object.entries(grouped)) {
    console.log(`${contract}: ${events.length} events`);
  }

  return grouped;
}

aggregateEvents('0x100000', '0x1000c7');
```

## Block-range limits

Each request can cover up to 500 blocks on Developer or 10,000 on Growth, Scale, and Enterprise by default.
The Free plan does not include `eth_getLogs`.
Both endpoint blocks count: `toBlock - fromBlock + 1`. Address and topic filters do not increase this allowance.
Individual networks may enforce lower limits.

Supply block bounds or a `blockHash`. Do not combine a non-null hash with non-null bounds.
Missing or null bounds default to `latest`. Equal tags request one block.
Numeric ranges ending at `latest` or `pending` use the observed endpoint head plus a 6-block margin for validation.
Use explicit numeric bounds for exact pagination. Mixed ranges involving `safe` or `finalized` are rejected.
The `earliest` tag means block zero.

Range errors return HTTP 200 with a JSON-RPC error body.
Oversized ranges use code `-32005`, invalid bounds use `-32602`, and an unavailable endpoint head uses `-32000`.
WebSocket uses the same JSON-RPC codes.
The same range validation applies to `eth_newFilter`.
A rejected log query rejects its entire batch before any member executes.
See [request examples and pagination guidance](https://www.dwellir.com/docs/getting-started/rate-limits#eth_getlogs-block-range-limits).

## Best Practices

- Split historical ranges into chunks within your plan limit, using smaller chunks if Zetachain enforces a lower limit.
- Use topic filters for efficient log filtering: the node filters at the storage level before returning results
- For high-volume monitoring, use `eth_newFilter` with polling instead of repeatedly calling `eth_getLogs`
- Store the last processed block number for incremental indexing rather than re-scanning the full chain
- Budget for the split: each chunk is a separate request billed as one response at the standard 1 credit, so a wide backfill costs proportionally more on a plan with a smaller limit
- For long backfills on Zetachain, follow the [`eth_getLogs` limits guide](https://www.dwellir.com/guides/eth-getlogs-limits) to size windows from the error messages instead of guessing

## Request Parameters

- `fromBlock` (`QUANTITY|TAG, optional`): Starting block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `toBlock` (`QUANTITY|TAG, optional`): Inclusive ending block as a hexadecimal height or supported tag. Missing or null defaults to "latest"
- `address` (`DATA|Array, optional`): Contract address(es) to filter
- `topics` (`Array, optional`): Array of topic filters
- `blockHash` (`DATA, optional`): Filter one block by hash. Cannot be combined with non-null fromBlock or toBlock

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_getLogs",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}
```

## Response Fields

- `address` (`DATA, required`): Contract that emitted the log
- `topics` (`Array, required`): Array of indexed topics
- `data` (`DATA, required`): Non-indexed log data
- `blockNumber` (`QUANTITY, required`): Block number
- `transactionHash` (`DATA, required`): Transaction hash
- `logIndex` (`QUANTITY, required`): Log index in block

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [{
    "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x...", "0x..."],
    "data": "0x...",
    "blockNumber": "0x5BAD55",
    "transactionHash": "0x...",
    "logIndex": "0x0"
  }]
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_getLogs",
    "params": [{
      "fromBlock": "latest",
      "toBlock": "latest",
      "address": "0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf",
      "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
    }],
    "id": 1
  }'
```

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

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

// Get Transfer events
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function getTransferEvents(tokenAddress, fromBlock, toBlock) {
  const logs = await provider.getLogs({
    address: tokenAddress,
    topics: [TRANSFER_TOPIC],
    fromBlock: fromBlock,
    toBlock: toBlock
  });

  return logs.map(log => ({
    from: '0x' + log.topics[1].slice(26),
    to: '0x' + log.topics[2].slice(26),
    blockNumber: log.blockNumber,
    transactionHash: log.transactionHash
  }));
}

const events = await getTransferEvents(
  '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
  'latest',
  'latest'
);
console.log('Transfer events:', events);
```

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY'))

TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

def get_transfer_events(token_address, from_block, to_block):
    logs = w3.eth.get_logs({
        'address': token_address,
        'topics': [TRANSFER_TOPIC],
        'fromBlock': from_block,
        'toBlock': to_block
    })

    events = []
    for log in logs:
        events.append({
            'from': '0x' + log['topics'][1].hex()[26:],
            'to': '0x' + log['topics'][2].hex()[26:],
            'block': log['blockNumber'],
            'tx': log['transactionHash'].hex()
        })

    return events

events = get_transfer_events(
    '0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf',
    'latest',
    'latest'
)
print(f'Found {len(events)} transfer events')
```

```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-zetachain-mainnet.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    contractAddress := common.HexToAddress("0x5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf")
    transferTopic := common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")

    query := ethereum.FilterQuery{
        FromBlock: big.NewInt(100),
        ToBlock:   big.NewInt(599),
        Addresses: []common.Address{contractAddress},
        Topics:    [][]common.Hash,
    }

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

    fmt.Printf("Found %d events\n", len(logs))
}
```

## Related Methods

- [`eth_newFilter`](https://www.dwellir.com/docs/zetachain/eth_newFilter) - Create a filter for logs
- [`eth_getFilterChanges`](https://www.dwellir.com/docs/zetachain/eth_getFilterChanges) - Poll filter for new logs
