eth_getLogs
Returns an array of logs matching specified filter criteria on Avalanche C-Chain.
When to Use This Method
eth_getLogs
is essential for:
- Event Monitoring - Track contract events in real-time
- DeFi Analytics - Analyze trading, lending, and yield farming activities
- Audit Trails - Create comprehensive transaction histories
- Data Indexing - Build custom indexing solutions for dApps
Parameters
Filter Object with the following fields:
fromBlock
- (optional) Earliest block to search (hex or "latest")toBlock
- (optional) Latest block to search (hex or "latest")address
- (optional) Contract address or array of addressestopics
- (optional) Array of topic filtersblockhash
- (optional) Specific block hash to search
{
"jsonrpc": "2.0",
"method": "eth_getLogs",
"params": [{
"fromBlock": "0x1",
"toBlock": "0x2",
"address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
]
}],
"id": 1
}
Returns
Array
- Array of log objects matching the filter:
address
- Address of the contract that generated the logtopics
- Array of indexed event parametersdata
- Non-indexed event datablockNumber
- Block number in hextransactionHash
- Transaction hashtransactionIndex
- Transaction index in blockblockHash
- Block hashlogIndex
- Log index in blockremoved
- True if log was removed due to chain reorganization
Implementation Examples
- cURL
- JavaScript
- Python
- Go
curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getLogs",
"params": [{
"fromBlock": "0x1",
"toBlock": "latest",
"address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
]
}],
"id": 1
}'
import { JsonRpcProvider, Contract, Interface } from 'ethers';
const provider = new JsonRpcProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc');
// ERC20 Transfer event signature
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
// Get ERC20 transfer events for a specific token
async function getTokenTransfers(tokenAddress, fromBlock = 'earliest', toBlock = 'latest') {
const filter = {
address: tokenAddress,
topics: [TRANSFER_TOPIC],
fromBlock: fromBlock,
toBlock: toBlock
};
const logs = await provider.getLogs(filter);
return logs.map(log => ({
transactionHash: log.transactionHash,
blockNumber: parseInt(log.blockNumber, 16),
from: '0x' + log.topics[1].slice(26),
to: '0x' + log.topics[2].slice(26),
value: BigInt(log.data).toString(),
address: log.address
}));
}
// Monitor transfers for a specific address
async function getAddressTransfers(address, tokenAddresses = []) {
// Convert address to topic format (padded to 32 bytes)
const addressTopic = '0x000000000000000000000000' + address.slice(2).toLowerCase();
const filter = {
address: tokenAddresses.length > 0 ? tokenAddresses : undefined,
topics: [
TRANSFER_TOPIC,
[addressTopic, null], // from address (sent)
[null, addressTopic] // to address (received)
],
fromBlock: 'earliest',
toBlock: 'latest'
};
const logs = await provider.getLogs(filter);
return logs.map(log => {
const from = '0x' + log.topics[1].slice(26);
const to = '0x' + log.topics[2].slice(26);
const isSent = from.toLowerCase() === address.toLowerCase();
return {
transactionHash: log.transactionHash,
blockNumber: parseInt(log.blockNumber, 16),
tokenAddress: log.address,
from: from,
to: to,
value: BigInt(log.data).toString(),
direction: isSent ? 'sent' : 'received'
};
});
}
// Get DEX trading events (example with Trader Joe)
async function getDEXTrades(pairAddress, fromBlock = 'earliest', toBlock = 'latest') {
// Swap event signature
const SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const filter = {
address: pairAddress,
topics: [SWAP_TOPIC],
fromBlock: fromBlock,
toBlock: toBlock
};
const logs = await provider.getLogs(filter);
return logs.map(log => {
// Decode swap data (simplified)
return {
transactionHash: log.transactionHash,
blockNumber: parseInt(log.blockNumber, 16),
pairAddress: log.address,
sender: '0x' + log.topics[1].slice(26),
rawData: log.data
};
});
}
// Real-time event monitoring
async function monitorEvents(contractAddress, eventTopics, callback) {
let lastBlock = await provider.getBlockNumber();
setInterval(async () => {
const currentBlock = await provider.getBlockNumber();
if (currentBlock > lastBlock) {
const filter = {
address: contractAddress,
topics: eventTopics,
fromBlock: `0x${(lastBlock + 1).toString(16)}`,
toBlock: `0x${currentBlock.toString(16)}`
};
try {
const logs = await provider.getLogs(filter);
if (logs.length > 0) {
callback(logs);
}
} catch (error) {
console.error('Error fetching logs:', error);
}
lastBlock = currentBlock;
}
}, 2000); // Check every 2 seconds
}
from web3 import Web3
from eth_abi import decode
w3 = Web3(Web3.HTTPProvider('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc'))
# ERC20 Transfer event signature
TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
def get_token_transfers(token_address, from_block='earliest', to_block='latest'):
"""Get ERC20 transfer events for a specific token"""
filter_params = {
'address': token_address,
'topics': [TRANSFER_TOPIC],
'fromBlock': from_block,
'toBlock': to_block
}
logs = w3.eth.get_logs(filter_params)
transfers = []
for log in logs:
# Decode transfer data
from_addr = '0x' + log['topics'][1].hex()[26:]
to_addr = '0x' + log['topics'][2].hex()[26:]
value = int(log['data'], 16)
transfers.append({
'transaction_hash': log['transactionHash'].hex(),
'block_number': log['blockNumber'],
'from': from_addr,
'to': to_addr,
'value': value,
'token_address': log['address']
})
return transfers
def get_address_activity(address, token_addresses=None):
"""Get all transfer activity for a specific address"""
# Convert address to topic format
address_topic = '0x000000000000000000000000' + address[2:].lower()
filter_params = {
'topics': [
TRANSFER_TOPIC,
[address_topic, None], # from (sent)
[None, address_topic] # to (received)
],
'fromBlock': 'earliest',
'toBlock': 'latest'
}
if token_addresses:
filter_params['address'] = token_addresses
logs = w3.eth.get_logs(filter_params)
activity = []
for log in logs:
from_addr = '0x' + log['topics'][1].hex()[26:]
to_addr = '0x' + log['topics'][2].hex()[26:]
value = int(log['data'], 16)
direction = 'sent' if from_addr.lower() == address.lower() else 'received'
activity.append({
'transaction_hash': log['transactionHash'].hex(),
'block_number': log['blockNumber'],
'token_address': log['address'],
'from': from_addr,
'to': to_addr,
'value': value,
'direction': direction
})
return activity
def monitor_contract_events(contract_address, event_topics, callback):
"""Monitor contract events in real-time"""
import time
last_block = w3.eth.block_number
while True:
current_block = w3.eth.block_number
if current_block > last_block:
filter_params = {
'address': contract_address,
'topics': event_topics,
'fromBlock': last_block + 1,
'toBlock': current_block
}
try:
logs = w3.eth.get_logs(filter_params)
if logs:
callback(logs)
except Exception as e:
print(f"Error fetching logs: {e}")
last_block = current_block
time.sleep(2) # Check every 2 seconds
def analyze_dex_volume(pair_addresses, from_block, to_block):
"""Analyze DEX trading volume"""
# Swap event signature (Uniswap V2 style)
SWAP_TOPIC = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822'
total_volume = {}
for pair_address in pair_addresses:
filter_params = {
'address': pair_address,
'topics': [SWAP_TOPIC],
'fromBlock': from_block,
'toBlock': to_block
}
logs = w3.eth.get_logs(filter_params)
total_volume[pair_address] = len(logs)
return total_volume
package main
import (
"context"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial("https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc")
if err != nil {
log.Fatal(err)
}
// ERC20 Transfer event signature
transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))
// Create filter query
query := ethereum.FilterQuery{
FromBlock: big.NewInt(1),
ToBlock: nil, // latest
Addresses: []common.Address{
common.HexToAddress("0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"),
},
Topics: [][]common.Hash{
{transferTopic},
},
}
// Get logs
logs, err := client.FilterLogs(context.Background(), query)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d transfer events\n", len(logs))
for _, vLog := range logs {
fmt.Printf("Block: %d, TxHash: %s\n", vLog.BlockNumber, vLog.TxHash.Hex())
// Decode transfer data
if len(vLog.Topics) >= 3 {
from := common.HexToAddress(vLog.Topics[1].Hex())
to := common.HexToAddress(vLog.Topics[2].Hex())
value := new(big.Int).SetBytes(vLog.Data)
fmt.Printf(" From: %s, To: %s, Value: %s\n", from.Hex(), to.Hex(), value.String())
}
}
}
func getAddressTransfers(client *ethclient.Client, address common.Address) error {
transferTopic := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))
// Convert address to topic format
addressTopic := common.Hash{}
copy(addressTopic[12:], address[:])
query := ethereum.FilterQuery{
FromBlock: big.NewInt(1),
ToBlock: nil,
Topics: [][]common.Hash{
{transferTopic},
{addressTopic, common.Hash{}}, // from or to
{common.Hash{}, addressTopic}, // to or from
},
}
logs, err := client.FilterLogs(context.Background(), query)
if err != nil {
return err
}
fmt.Printf("Found %d transfers for address %s\n", len(logs), address.Hex())
return nil
}
Response Example
Successful Response
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"address": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebcccc",
"0x000000000000000000000000eff8bf1e28ffb1bfa76b6dc3e619d5a6e3b6b9b9"
],
"data": "0x000000000000000000000000000000000000000000000000000000000000000a",
"blockNumber": "0x2",
"transactionHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0",
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"logIndex": "0x0",
"removed": false
}
]
}
Common Use Cases
1. DeFi Portfolio Tracking
Track user's DeFi activities across protocols:
async function trackDeFiPortfolio(userAddress, protocolAddresses) {
const activities = [];
// Common DeFi event signatures
const eventSignatures = {
transfer: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
deposit: '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c',
withdrawal: '0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65',
swap: '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822'
};
const userTopic = '0x000000000000000000000000' + userAddress.slice(2).toLowerCase();
for (const [protocolName, protocolAddress] of Object.entries(protocolAddresses)) {
const filter = {
address: protocolAddress,
topics: [
Object.values(eventSignatures),
[userTopic, null],
[null, userTopic]
],
fromBlock: 'earliest',
toBlock: 'latest'
};
try {
const logs = await provider.getLogs(filter);
for (const log of logs) {
const eventType = Object.keys(eventSignatures).find(
key => eventSignatures[key] === log.topics[0]
);
activities.push({
protocol: protocolName,
eventType: eventType || 'unknown',
transactionHash: log.transactionHash,
blockNumber: parseInt(log.blockNumber, 16),
address: log.address,
topics: log.topics,
data: log.data
});
}
} catch (error) {
console.error(`Error fetching ${protocolName} logs:`, error);
}
}
return activities.sort((a, b) => b.blockNumber - a.blockNumber);
}
2. Token Analytics Dashboard
Build comprehensive token analytics:
async function analyzeTokenActivity(tokenAddress, timeframe = 24) {
const currentBlock = await provider.getBlockNumber();
const currentTime = Math.floor(Date.now() / 1000);
const timeframeStart = currentTime - (timeframe * 3600); // hours to seconds
// Estimate block number for timeframe start
const avgBlockTime = 2; // Avalanche ~2 second blocks
const blocksInTimeframe = Math.floor((timeframe * 3600) / avgBlockTime);
const fromBlock = Math.max(1, currentBlock - blocksInTimeframe);
const filter = {
address: tokenAddress,
topics: [TRANSFER_TOPIC],
fromBlock: `0x${fromBlock.toString(16)}`,
toBlock: 'latest'
};
const logs = await provider.getLogs(filter);
// Analyze the data
const analytics = {
totalTransfers: logs.length,
uniqueAddresses: new Set(),
totalVolume: 0n,
topHolders: new Map(),
hourlyActivity: new Array(timeframe).fill(0)
};
for (const log of logs) {
const from = '0x' + log.topics[1].slice(26);
const to = '0x' + log.topics[2].slice(26);
const value = BigInt(log.data);
analytics.uniqueAddresses.add(from);
analytics.uniqueAddresses.add(to);
analytics.totalVolume += value;
// Track holder balances (simplified)
if (from !== '0x0000000000000000000000000000000000000000') {
analytics.topHolders.set(from, (analytics.topHolders.get(from) || 0n) - value);
}
if (to !== '0x0000000000000000000000000000000000000000') {
analytics.topHolders.set(to, (analytics.topHolders.get(to) || 0n) + value);
}
}
return {
...analytics,
uniqueAddresses: analytics.uniqueAddresses.size,
totalVolume: analytics.totalVolume.toString(),
topHolders: Array.from(analytics.topHolders.entries())
.sort(([,a], [,b]) => Number(b - a))
.slice(0, 10)
};
}
3. Cross-Chain Bridge Monitoring
Monitor bridge activities:
async function monitorBridgeActivity(bridgeAddresses) {
// Common bridge event signatures
const DEPOSIT_EVENT = '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c';
const WITHDRAWAL_EVENT = '0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65';
const bridgeActivity = [];
for (const bridgeAddress of bridgeAddresses) {
const filter = {
address: bridgeAddress,
topics: [
[DEPOSIT_EVENT, WITHDRAWAL_EVENT]
],
fromBlock: 'earliest',
toBlock: 'latest'
};
const logs = await provider.getLogs(filter);
for (const log of logs) {
const isDeposit = log.topics[0] === DEPOSIT_EVENT;
bridgeActivity.push({
bridgeAddress: log.address,
type: isDeposit ? 'deposit' : 'withdrawal',
transactionHash: log.transactionHash,
blockNumber: parseInt(log.blockNumber, 16),
user: '0x' + log.topics[1].slice(26),
amount: BigInt(log.data).toString()
});
}
}
return bridgeActivity.sort((a, b) => b.blockNumber - a.blockNumber);
}
4. NFT Marketplace Analytics
Track NFT trading activity:
async function analyzeNFTMarketplace(marketplaceAddress) {
// ERC721 Transfer event and marketplace specific events
const ERC721_TRANSFER = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
const SALE_EVENT = '0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb';
const filter = {
address: marketplaceAddress,
topics: [
[ERC721_TRANSFER, SALE_EVENT]
],
fromBlock: 'earliest',
toBlock: 'latest'
};
const logs = await provider.getLogs(filter);
const analytics = {
totalSales: 0,
totalVolume: 0n,
uniqueCollections: new Set(),
topCollections: new Map(),
recentSales: []
};
for (const log of logs) {
if (log.topics[0] === SALE_EVENT) {
analytics.totalSales++;
// Decode sale data (simplified)
const collection = log.address;
const price = BigInt(log.data);
analytics.totalVolume += price;
analytics.uniqueCollections.add(collection);
analytics.topCollections.set(
collection,
(analytics.topCollections.get(collection) || 0n) + price
);
analytics.recentSales.push({
collection,
price: price.toString(),
transactionHash: log.transactionHash,
blockNumber: parseInt(log.blockNumber, 16)
});
}
}
return {
...analytics,
uniqueCollections: analytics.uniqueCollections.size,
totalVolume: analytics.totalVolume.toString(),
topCollections: Array.from(analytics.topCollections.entries())
.sort(([,a], [,b]) => Number(b - a))
.slice(0, 10),
recentSales: analytics.recentSales
.sort((a, b) => b.blockNumber - a.blockNumber)
.slice(0, 50)
};
}
Performance Optimization
Batch Log Queries
Query logs efficiently with proper batching:
async function batchLogQueries(queries) {
const batch = queries.map((query, i) => ({
jsonrpc: '2.0',
method: 'eth_getLogs',
params: [query],
id: i
}));
const response = await fetch('https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(batch)
});
const results = await response.json();
return results.map(r => r.result || []);
}
Block Range Optimization
Split large block ranges for better performance:
async function optimizedLogQuery(filter, maxBlockRange = 5000) {
const fromBlock = typeof filter.fromBlock === 'string' ?
parseInt(filter.fromBlock, 16) : filter.fromBlock;
const toBlock = typeof filter.toBlock === 'string' ?
(filter.toBlock === 'latest' ? await provider.getBlockNumber() : parseInt(filter.toBlock, 16)) : filter.toBlock;
const allLogs = [];
for (let start = fromBlock; start <= toBlock; start += maxBlockRange) {
const end = Math.min(start + maxBlockRange - 1, toBlock);
const batchFilter = {
...filter,
fromBlock: `0x${start.toString(16)}`,
toBlock: `0x${end.toString(16)}`
};
try {
const logs = await provider.getLogs(batchFilter);
allLogs.push(...logs);
} catch (error) {
console.error(`Error fetching logs for blocks ${start}-${end}:`, error);
}
}
return allLogs;
}
Error Handling
Common errors and solutions:
Error Code | Description | Solution |
---|---|---|
-32602 | Invalid parameters | Check filter object format |
-32005 | Rate limit exceeded | Reduce query frequency |
-32000 | Query timeout | Reduce block range or add more filters |
async function safeLogs(filter, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const logs = await provider.getLogs(filter);
return { success: true, logs };
} catch (error) {
if (error.message.includes('query timeout')) {
// Reduce block range
const fromBlock = parseInt(filter.fromBlock || '0x1', 16);
const toBlock = parseInt(filter.toBlock || 'latest', 16);
const range = toBlock - fromBlock;
if (range > 1000) {
return optimizedLogQuery(filter, 1000);
}
}
if (i === maxRetries - 1) {
return { success: false, error: error.message };
}
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
Need help? Contact our support team or check the Avalanche documentation.