Docs
Docs
Home
Getting Started
Agent Tooling
CLI
Supported Chains
Acala
Aptos
Arbitrum
Arc
Asset Hub
Astar
Avalanche
Base
Berachain
Bifrost
Binance Smart Chain
Bittensor
Blast
Boba Network
Bridge Hub
Celo
Centrifuge
Chiliz
Cronos
Enjin
Ethereum
Etherlink
Flow EVM Gateway
Gnosis
Hydration
Hyperliquid
Immutable
Ink
IoTeX
Kusama
Linea
LISK
Manta Atlantic
Manta Pacific
Mantle
MegaETH
Monad
Movement
Neuroweb
opBNB
Optimism
Plasma
Polkadot
Polygon
Pulsechain
Robinhood
Ronin
Scroll
Sonic
Starknet
Taiko
Tempo
Sui
TRON
Unichain
Viction
World Chain
XDC Network
XX Network
Zetachain
zkSync Era
Zora
Supported ChainsPlasmaJSON-RPC APISmart Contract Methods

eth_newFilter - Plasma RPC Method

Create an event log filter on Plasma. Essential for event monitoring, contract activity tracking, and DeFi event streaming for stablecoin transfers, payment apps, and wallets that need 1 second confirmation.

Plasma RPC endpoint: endpoint URLs, plans and pricing.

Creates a filter object on Plasma 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 Plasma? Build on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution with 1 second blocks, XPL gas, full EVM JSON-RPC, and debug plus txpool on Dwellir.

When to Use This Method

eth_newFilter is essential for payment app developers, wallet teams, and teams shipping Solidity contracts for dollar transfers:

  • Event Monitoring - Subscribe to specific contract events on Plasma such as token transfers, approvals, or governance votes
  • Contract Activity Tracking - Watch one or multiple contracts for any emitted events relevant to stablecoin transfers, payment apps, and wallets that need 1 second confirmation
  • 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_getFilterChanges for only new logs

The filter's block range follows the same plan limits and validation rules as eth_getLogs. See Rate Limits before creating a filter over historical blocks.

Best Practices

  • Prefer eth_getLogs for one-time queries instead of creating and then immediately uninstalling a filter
  • Always call eth_uninstallFilter when a filter is no longer needed to free node resources
  • Handle timeout errors gracefully; filters expire after approximately 5 minutes of inactivity on most nodes
  • Limit the block range in filter options to avoid query errors on nodes with range restrictions
JSON-RPC request
{
  "jsonrpc": "2.0",
  "method": "eth_newFilter",
  "params": [{
    "fromBlock": "latest",
    "toBlock": "latest",
    "address": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "id": 1
}

Code Examples

Common Use Cases

1. ERC-20 Token Transfer Monitor

Watch for all transfers of a specific token on Plasma:

JavaScript
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:

JavaScript
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:

JavaScript
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: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb',
  topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}, (logs) => {
  console.log(`${logs.length} new transfer events`);
});

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32000Filter block range too largeReduce the range between fromBlock and toBlock
-32000Too many topicsLimit topics array to 4 entries maximum
-32602Invalid paramsVerify address format (0x-prefixed, 20 bytes) and topic format (0x-prefixed, 32 bytes)
-32603Internal errorNode may be overloaded - retry with exponential backoff
-32005Rate limit exceededReduce filter creation frequency
JavaScript
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 poll
  • eth_getFilterLogs - Get all logs matching this filter at once
  • eth_getLogs - Query logs directly without creating a filter
  • eth_uninstallFilter - Remove this filter when no longer needed
  • eth_newBlockFilter - Create a filter for new block notifications instead of logs

eth_getLogs

Query event logs on Plasma. Essential for indexing stablecoin transfers, payment apps, and wallets that need 1 second confirmation on an EVM Layer 1 for stablecoin payments with PlasmaBFT consensus and Reth execution.

eth_getFilterChanges

Poll a filter for new results since the last poll on Plasma. Essential for event streaming, real-time monitoring, and efficient log indexing for stablecoin transfers, payment apps, and wallets that need 1 second confirmation.

On this page

When to Use This MethodBest PracticesCode ExamplesCommon Use Cases1. ERC-20 Token Transfer Monitor2. Multi-Event DeFi Monitor3. Filter Lifecycle ManagerError HandlingRelated Methods