eth_getLogs - Query Event Logs
Query and filter event logs from smart contracts on Centrifuge Mainnet. Essential for tracking events, monitoring contracts, and building event-driven applications.
Returns an array of all logs matching a given filter object. Essential for querying historical events and monitoring smart contract activity.
Block Range Limits
| Plan | Maximum blocks per request |
|---|---|
| Free | Not available |
| Developer | 500 |
| Growth | 10,000 |
| Scale and above | 10,000 |
Both endpoints count toward the limit: toBlock - fromBlock + 1.
Supply explicit numeric bounds for historical ranges, or use blockHash for one block.
Split longer ranges into requests within your plan limit.
See request rules and errors, including accepted block tags.
When to Use This Method
eth_getLogs is crucial for:
- Event Monitoring - Track smart contract events and state changes
- Historical Queries - Search past events within a block range
- DeFi Analytics - Monitor trades, liquidity events, and protocol activity
- Indexing - Build databases of on-chain events
Implementation Examples
The helpers below take a numeric starting height and a numeric ending height or latest.
They resolve latest once and split historical ranges into 500-block requests.
The JavaScript examples use toQuantity to encode block heights without leading zeroes.
Advanced Usage
Multiple Address Filtering
{
"jsonrpc": "2.0",
"method": "eth_getLogs",
"params": [{
"fromBlock": "0x1",
"toBlock": "0xc8",
"address": [
"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"0x4200000000000000000000000000000000000006"
],
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
]
}],
"id": 1
}Topic Filtering with OR Logic
{
"jsonrpc": "2.0",
"method": "eth_getLogs",
"params": [{
"fromBlock": "0x1",
"toBlock": "0xc8",
"topics": [
[
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"
]
]
}],
"id": 1
}Notes
- Centrifuge supports historical log queries back to genesis block
- Query limits: Maximum 10,000 results per request
- Block range limits: Developer 500; Growth, Scale, and Enterprise 10,000 blocks per request
- Topic arrays: Support up to 4 topics with OR logic within each position
- Performance tip: Use specific address filters to improve query speed
- Event signatures: First topic is always the keccak256 hash of the event signature
Common Use Cases
1. Token Balance History
// Track historical token balance changes
async function getBalanceHistory(tokenAddress, userAddress, fromBlock) {
const monitor = new EventMonitor(provider);
// Get all transfers involving the user
const logs = await monitor.getFilteredTransfers(
tokenAddress,
userAddress,
'both',
fromBlock,
'latest'
);
// Calculate balance changes
const balanceChanges = [];
let currentBalance = 0n;
for (const log of logs) {
const iface = new Interface([
'event Transfer(address indexed from, address indexed to, uint256 value)'
]);
const decoded = iface.parseLog({
topics: log.topics,
data: log.data
});
const change = decoded.args.from.toLowerCase() === userAddress.toLowerCase() ?
-decoded.args.value : decoded.args.value;
currentBalance += change;
balanceChanges.push({
blockNumber: log.blockNumber,
transactionHash: log.transactionHash,
change: change.toString(),
balance: currentBalance.toString(),
type: change < 0 ? 'outgoing' : 'incoming'
});
}
return balanceChanges;
}2. DEX Trade Monitoring
// Monitor DEX trading activity
async function monitorDEXTrades(dexAddress, fromBlock) {
const swapTopic = id('Swap(address,address,int256,int256,uint160,uint128,int24)');
const logs = await new EventMonitor(provider).getPaginatedLogs({
fromBlock: toQuantity(fromBlock),
toBlock: 'latest',
address: dexAddress,
topics: [swapTopic]
});
const trades = logs.map(log => {
// Decode Uniswap V3 swap event
const iface = new Interface([
'event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)'
]);
const decoded = iface.parseLog({
topics: log.topics,
data: log.data
});
return {
sender: decoded.args.sender,
recipient: decoded.args.recipient,
amount0: decoded.args.amount0.toString(),
amount1: decoded.args.amount1.toString(),
price: Number(decoded.args.sqrtPriceX96) ** 2 / (2 ** 192),
blockNumber: log.blockNumber,
transactionHash: log.transactionHash
};
});
return trades;
}3. Contract Event Indexer
// Build an event index for a contract
class EventIndexer {
constructor(provider, contractAddress, abi) {
this.provider = provider;
this.contractAddress = contractAddress;
this.iface = new Interface(abi);
this.eventIndex = new Map();
}
async indexEvents(fromBlock, toBlock) {
// Get all events for the contract
const logs = await new EventMonitor(this.provider).getPaginatedLogs({
fromBlock: toQuantity(fromBlock),
toBlock: toBlock === 'latest' ? 'latest' : toQuantity(toBlock),
address: this.contractAddress
});
for (const log of logs) {
try {
const parsed = this.iface.parseLog({
topics: log.topics,
data: log.data
});
if (!this.eventIndex.has(parsed.name)) {
this.eventIndex.set(parsed.name, []);
}
this.eventIndex.get(parsed.name).push({
args: Object.fromEntries(
Object.entries(parsed.args).filter(([key]) => isNaN(key))
),
blockNumber: log.blockNumber,
transactionHash: log.transactionHash,
logIndex: log.logIndex
});
} catch {
// Unknown event
}
}
return this.getStatistics();
}
getStatistics() {
const stats = {};
for (const [eventName, events] of this.eventIndex) {
stats[eventName] = {
count: events.length,
firstBlock: Math.min(...events.map(e => e.blockNumber)),
lastBlock: Math.max(...events.map(e => e.blockNumber))
};
}
return stats;
}
}