I hope all is well. I have a specific use case that I'm working through right now that essentially follows a factory pattern:
I deploy a Factory contract that deploys new instances of another contract that users interact with. My challenge is that because there are potentially hundreds of these spawned contracts, trying to react to events that are emitted from them is not feasible using the Contract API as normal. It would require an ever growing list of open connections for each contract instance.
I wanted to see if I can use the Event / Topics functionality to do this, where I can catch ANY event that matches the Topic regardless of contract address? Basically, I need a global event handler that can run in a process and respond to various events across all the instances of the user contract.
For example, let's say I emit these events from the contracts users use:
event HelloWorld(string greeting)
event CreateElement(string elementId, address sender)
In a Node.js API for example, could I use Ethers to watch the logs for any events that match these criteria and pull the values out of those event emissions?
Notionally, I tried to use the provider.on() syntax which was able to react to the event, but I didn't see any of the data points to extract from the event.
let filter = {
topics: [
ethers.utils.id("HelloWorld(string)"),
ethers.utils.id("CreateElement(string,address)")
]
}
provider.on(filter, (log, event) => {
// Emitted whenever the above topic(s) occur
console.log("results of event logging", log, event)
})
If this is the proper syntax above, how can I extract the contents of the event in the callback? Thanks for the help in advance :)
You can add options in topic filter by using array of arrays:
let filter = {
topics: [
[ethers.utils.id("HelloWorld(string)"), ethers.utils.id("CreateElement(string,address)")]
]
}
Both HelloWorld and CreateElement should match to this filter. But can you try if this works in the provider.on? Just in case if it didn't work, provider.getLogs should.
You can add options in topic filter by using array of arrays:
let filter = { topics: [ [ethers.utils.id("HelloWorld(string)"), ethers.utils.id("CreateElement(string,address)")] ] }Can you try if this works in the
provider.on?
It will catch these events, yes, but what is captured in the callback (log, event) is just the transaction object and event is undefined. My issue now is figuring out how to get the values out of these events when they are indeed caught.
Oh yeah, I just noticed that you had (log, event) => { there. I assume event is the parsed version of the log. I don't think provider can give you a parsed log, as provider does not know how to parse it (it needs an interface) so it cannot technically parse it and give you. You will only get a log and then you need an interface to parse it:
provider.on(filter, (log) => {
// Emitted whenever the above topic(s) occur
const event = interface.parseLog(log);
console.log("results of event logging", log, event)
})
Edit: Just curious on where did you see (log, event) => {? Or was it something you were trying?
Makes perfect sense, that's what I was looking for I must have missed it in the documentation. This should work. I will report back ASAP
thank you!
this works, thanks so much for the help. I missed the interface fragment stuff in docs.
Oh yeah, I just noticed that you had
(log, event) => {there. I assumeeventis the parsed version of the log. I don't think provider can give you a parsed log, as provider does not know how to parse it (it needs an interface) so it cannot technically parse it and give you. You will only get a log and then you need an interface to parse it:provider.on(filter, (log) => { // Emitted whenever the above topic(s) occur const event = interface.parseLog(log); console.log("results of event logging", log, event) })Edit: Just curious on where did you see
(log, event) => {? Or was it something you were trying?
BTW, (log,event) are args in the new v5 docs for provider event handling. Example ---> https://docs.ethers.io/v5/api/providers/provider/#Provider--event-methods
excerpt from that section:
// This filter could also be generated with the Contract or
// Interface API. If address is not specified, any address
// matches and if topics is not specified, any log matches
filter = {
address: "dai.tokens.ethers.eth",
topics: [
utils.id("Transfer(address,address,uint256)")
]
}
provider.on(filter, (log, event) => {
// Emitted whenever a DAI token transfer occurs
})
Most helpful comment
Oh yeah, I just noticed that you had
(log, event) => {there. I assumeeventis the parsed version of the log. I don't think provider can give you a parsed log, as provider does not know how to parse it (it needs an interface) so it cannot technically parse it and give you. You will only get a log and then you need an interface to parse it:Edit: Just curious on where did you see
(log, event) => {? Or was it something you were trying?