eth_newFilter - Flow EVM RPC Method
Create an event log filter on Flow EVM Gateway. Essential for event monitoring, contract activity tracking, and DeFi event streaming for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications.
Creates a filter object on Flow EVM Gateway based on the given filter options, to notify when the state changes (new logs). The filter monitors for log entries that match the specified criteria — contract addresses, topics, and block ranges. Use eth_getFilterChanges to poll for new matching logs or eth_getFilterLogs to retrieve all matching logs at once.
Why Flow EVM? Build on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability with full EVM equivalence on Flow, atomic multi-operation transactions, 40% lower gas fees, and 473% contract growth in 2025.
When to Use This Method
eth_newFilter is essential for NFT developers, gaming studios, and Solidity devs seeking Cadence interoperability:
- Event Monitoring — Subscribe to specific contract events on Flow EVM such as token transfers, approvals, or governance votes
- Contract Activity Tracking — Watch one or multiple contracts for any emitted events relevant to consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications
- DeFi Event Streaming — Monitor swap events, liquidity changes, or oracle price updates in real time
- Incremental Indexing — Build event indexes by creating a filter and polling with
eth_getFilterChangesfor only new logs
Code Examples
Common Use Cases
1. ERC-20 Token Transfer Monitor
Watch for all transfers of a specific token on Flow EVM:
async function monitorTokenTransfers(provider, tokenAddress) {
// keccak256('Transfer(address,address,uint256)')
const transferTopic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
const filterId = await provider.send('eth_newFilter', [{
fromBlock: 'latest',
address: tokenAddress,
topics: [transferTopic]
}]);
console.log(`Monitoring ${tokenAddress} transfers...`);
setInterval(async () => {
try {
const logs = await provider.send('eth_getFilterChanges', [filterId]);
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);
console.log(`Transfer: ${from} -> ${to} (${value})`);
}
} catch (error) {
if (error.message.includes('filter not found')) {
console.log('Filter expired — application should recreate');
}
}
}, 3000);
return filterId;
}2. Multi-Event DeFi Monitor
Track multiple event types across DEX contracts:
async function monitorDeFiEvents(provider, dexRouterAddress) {
// Watch for Swap and LiquidityAdded events
const swapTopic = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822';
const syncTopic = '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1';
const filterId = await provider.send('eth_newFilter', [{
fromBlock: 'latest',
address: dexRouterAddress,
topics: [[swapTopic, syncTopic]] // OR matching — either event type
}]);
setInterval(async () => {
const logs = await provider.send('eth_getFilterChanges', [filterId]);
for (const log of logs) {
const eventType = log.topics[0] === swapTopic ? 'SWAP' : 'SYNC';
console.log(`${eventType} at block ${parseInt(log.blockNumber, 16)}`);
}
}, 2000);
return filterId;
}3. Filter Lifecycle Manager
Manage filter creation, polling, and cleanup with automatic renewal:
class FilterManager {
constructor(provider) {
this.provider = provider;
this.filters = new Map();
}
async createFilter(name, filterParams, callback) {
const filterId = await this.provider.send('eth_newFilter', [filterParams]);
const filter = {
id: filterId,
params: filterParams,
callback,
interval: setInterval(() => this.poll(name), 3000),
lastPoll: Date.now()
};
this.filters.set(name, filter);
console.log(`Filter "${name}" created: ${filterId}`);
return filterId;
}
async poll(name) {
const filter = this.filters.get(name);
if (!filter) return;
try {
const logs = await this.provider.send('eth_getFilterChanges', [filter.id]);
filter.lastPoll = Date.now();
if (logs.length > 0) {
await filter.callback(logs);
}
} catch (error) {
if (error.message.includes('filter not found')) {
console.log(`Filter "${name}" expired — recreating...`);
const newId = await this.provider.send('eth_newFilter', [filter.params]);
filter.id = newId;
}
}
}
async removeFilter(name) {
const filter = this.filters.get(name);
if (!filter) return;
clearInterval(filter.interval);
await this.provider.send('eth_uninstallFilter', [filter.id]);
this.filters.delete(name);
console.log(`Filter "${name}" removed`);
}
async removeAll() {
for (const name of this.filters.keys()) {
await this.removeFilter(name);
}
}
}
// Usage
const manager = new FilterManager(provider);
await manager.createFilter('transfers', {
fromBlock: 'latest',
address: '0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e',
topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
console.log(`${logs.length} new transfer events`);
});Error Handling
Common errors and solutions:
| Error Code | Description | Solution |
|---|---|---|
| -32000 | Filter block range too large | Reduce the range between fromBlock and toBlock |
| -32000 | Too many topics | Limit topics array to 4 entries maximum |
| -32602 | Invalid params | Verify address format (0x-prefixed, 20 bytes) and topic format (0x-prefixed, 32 bytes) |
| -32603 | Internal error | Node may be overloaded — retry with exponential backoff |
| -32005 | Rate limit exceeded | Reduce filter creation frequency |
async function createFilterSafely(provider, params, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const filterId = await provider.send('eth_newFilter', [params]);
return filterId;
} catch (error) {
if (error.message.includes('block range too large')) {
// Narrow the range — split in half
const from = parseInt(params.fromBlock, 16);
const to = parseInt(params.toBlock, 16);
const mid = Math.floor((from + to) / 2);
console.warn(`Block range too large — splitting at ${mid}`);
throw new Error(`Split needed: ${from}-${mid} and ${mid + 1}-${to}`);
}
if (error.code === -32005 && i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000;
await new Promise(r => setTimeout(r, delay));
} else {
throw error;
}
}
}
}Related Methods
eth_getFilterChanges— Poll this filter for new logs since the last polleth_getFilterLogs— Get all logs matching this filter at onceeth_getLogs— Query logs directly without creating a filtereth_uninstallFilter— Remove this filter when no longer neededeth_newBlockFilter— Create a filter for new block notifications instead of logs
eth_getLogs
Query event logs on Flow EVM Gateway. Essential for indexing consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications on the EVM-equivalent layer on Flow blockchain enabling Cadence+Solidity composability.
eth_getFilterChanges
Poll a filter for new results since the last poll on Flow EVM Gateway. Essential for event streaming, real-time monitoring, and efficient log indexing for consumer NFTs (NBA Top Shot, Disney Pinnacle), gaming dApps, and hybrid Cadence-EVM applications.