The eth_getFilterChanges
method returns an array of logs which occurred since the last poll for the specified filter. This powerful subscription method works with filters created by eth_newFilter
, eth_newBlockFilter
, and eth_newPendingTransactionFilter
, allowing efficient monitoring of blockchain activity without constantly rescanning historical data.
This method takes a filter ID and returns any new logs that match the filter criteria since the last poll, providing the foundation for event-driven blockchain applications.
The filter ID returned by eth_newFilter, eth_newBlockFilter, or eth_newPendingTransactionFilter
Array of log objects, or an empty array if nothing has changed since last poll
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x000000000000000000000000a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0",
"0x00000000000000000000000023a6b9c321aba35d18ca26e66824e917778d9d2b"
],
"data": "0x0000000000000000000000000000000000000000000000003635c9adc5dea00000",
"blockNumber": "0x10892bc",
"transactionHash": "0x56b28388cadcf4da8cbd30aa3c3f126e0513550e6fab6fc20992f3e1435846c8",
"transactionIndex": "0x3",
"blockHash": "0x6b092af2e8fbe2ceba2034ef4f334f3274a1cce5ffe955fa1895565d9278dac7",
"logIndex": "0x7",
"removed": false
}
]
}
Each log object contains the following fields that provide comprehensive event information:
true
if the log was removed due to a chain reorganization (reorg)Some frequently monitored event signatures (first topic):
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
(same as ERC-20)0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822
Here's a complete pattern for effective event polling:
// 1. Create a filter for a specific event
async function monitorTokenTransfers(tokenAddress, fromBlock = 'latest') {
// ERC-20 Transfer event signature
const transferEventSignature = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
// Create the filter
const filterId = await provider.send('eth_newFilter', [{
address: tokenAddress,
topics: [transferEventSignature],
fromBlock,
toBlock: 'latest'
}]);
console.log(`Created filter: ${filterId}`);
return filterId;
}
// 2. Poll for changes
async function pollForTransfers(filterId, interval = 10000) {
setInterval(async () => {
try {
const logs = await provider.send('eth_getFilterChanges', [filterId]);
if (logs.length > 0) {
console.log(`Found ${logs.length} new transfers`);
logs.forEach(log => {
// Decode transfer event data
const from = '0x' + log.topics[1].slice(26);
const to = '0x' + log.topics[2].slice(26);
const value = BigInt(log.data);
console.log(`Transfer: ${from} → ${to}: ${value}`);
});
}
} catch (error) {
console.error('Filter may have expired:', error);
// Recreate the filter if needed
}
}, interval);
}
// 3. Clean up when done
async function stopMonitoring(filterId) {
await provider.send('eth_uninstallFilter', [filterId]);
console.log(`Filter ${filterId} uninstalled`);
}
The response format varies depending on the original filter type:
Log Filter (created with eth_newFilter
):
Block Filter (created with eth_newBlockFilter
):
["0x4b7", "0x4b8", "0x4b9"]
Pending Transaction Filter (created with eth_newPendingTransactionFilter
):
["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"]
removed
flag to handle reorged events properly