Events – How to Gather Historical Events Emitted by Any Contract Using JSON-RPC and Ethers.js

ethers.jseventsjson-rpcqueryrpc

I am trying to gather all events of a specific type on the entire chain, regardless of what contract emitted them.

When trying to find solutions online, I came across code like the following (source):

const filterId = await provider.send('eth_newFilter', [{
  address: ['0x123..', '0x456...'],
  fromBlock, toBlock, topics
}])

const logs = await provider.send('eth_getFilterChanges', [filterId]);

Here, multiple contract addresses can be stated. This, however, is not what I am looking for as I do not know the addresses of the contracts that emitted the events I am trying to gather.

I am looking for a version of the following code that gives me historical events, not events that are just coming in:

const provider = new ethers.providers.Web3Provider(window.ethereum);
const filter = {
  address: null,
  topics: [
    ethers.utils.id('MyEvent(address)')
  ]
};
provider.on(filter, event => {
  console.log(event);
});

Note that setting address to null means that the contract's address is not a criterion, i.e. I am accepting events regardless of the address of the contract that emitted it.

I would prefer a solution using ethers.js but a low-level solution using an explicit RPC call or a solution using a different library would also be fine.


Edit: I have tried to combine the two code blocks above as follows:

const filter = {
  address: null,
  topics: [
    ethers.utils.id('MyEvent(address)')
  ]
};
const filterId = await provider.send('eth_newFilter', [{
  address: null,
  fromBlock: '0x11',
  toBlock: '0x9819f0',
  topics: filter.topics,
}]);
const logs = await provider.send('eth_getFilterChanges', [filterId]);
console.log(logs);

However, this always yields the empty array.


Edit 2:

The following code is based on an answer:

const filter0 = {
  address: null,
  topics: [
    ethers.utils.id('MyEvent(address)')
  ]
};
const filter12 = myContract.filters.MyEvent();

const response0 = await provider.getLogs(filter0);
const response1 = await provider.getLogs(filter12);
const response2 = await myContract.queryFilter(filter12);

console.log('response0', response0);
console.log('response1', response1);
console.log('response2', response2);
console.log(filter12);

However, response0 and response1 are the empty array. Only response2 contains an event. I used a contract that was recently deployed and that only ever emitted 1 event of the specified kind. From the output of the filter, I can see that filter12 is indeed restricted to the correct address, so I do not understand why even response1 was empty.

Best Answer

Did you try using eth_getLogs. This is also exposed via the Ethers provider: https://docs.ethers.io/v5/api/providers/provider/#Provider-getLogs.

The syntax for the parameter is the same as for eth_newFilter.