Webhooks for EVM events: a new service for developers

Egor Egorov
Ariadne Project
Published in
4 min readJan 16, 2023

tl;dr: properly monitoring events on EVM blockchains is surprisingly complicated. We have developed a service to help you with that.

While developing the new version of Ariadne, a crosschain yield farm aggregator, we have encountered a minor task that seemed straightforward to code: properly watching for Events on EVM blockchains. We soon realized that it was surprisingly complex and it prompted us to create a whole new web service for our fellow developers.

The problem

One might think that watching for Events on Ethereum and other EVM blockchains is as simple as adding an event listener on the contract instance in your code. If you look up the documentation for the excellent ethers.js library, you’ll see an example that leads to code like this:

usdtContract.on('Transfer', amount => {  
if (amount >= 1_000_000) {
console.log("WHALE ALERT");
}
});

But you may be disappointed to find out that this approach doesn’t really cut it for real-life production use cases.

What happens under the hood of an Ethereum RPC library is roughly this: the library creates a filter out of the specified Event and asks RPC endpoint to return new records matching that filter.

However if the RPC connection is disconnected or reconnected, the filter is lost and no new events will be returned. The same happens if your connection is rerouted to another node in the infrastructure of your RPC provider — there is no active filter on the newly connected node, so no updates will be delivered.

Silently.

The same can happen if your app restarts or is down for a non-brief period of time, or if the RPC node fails (which, let’s be honest, happens all the time).

As a result, in any of these scenarios, you could potentially miss blocks containing events of your interest.

Websockets to the rescue?

Unfortunately, the answer is no. Not all providers offer WS RPC endpoints, and even when they do, we’ve seen instances where they hang and fail to deliver updates. This means that you could still encounter issues with reconnections or downtime, and end up missing blocks. In reality, HTTP keepalive does more or less the same, but it is simpler and appears to be more reliable.

The solution

The right way to properly get events is to store local state.

For every block that is produced on the blockchain, you should check if there are events of your interest in that specific block. Then, store the block number in local database to mark it as parsed. The next time you observe a block being produced, compare the block number with the last parsed block and retrieve events for all blocks in between.

But how do you watch for blocks being produced in the first place? It’s very simple: provider.on(‘block’, blockNumber => ()) … Oh wait…

Great, you’ve received an Event! But… are you sure about that? Sometimes, networks do roll back blocks (reorganize), which means that something you thought happened may later turn out to never have happened at all.

Enter network forks.

After observing an event, you have to wait for a certain number of confirmations on each eligible transaction before considering the event as definitely happened. A transaction that has already received a few confirmations could simply disappear on the next block! Hence it’s not enough just to store block numbers — you also need to store transaction hashes and the number of blocks produced after the block that contains the transaction with the target event. 🤯

Depending on the requirement of your project this might be a big deal. While forks don’t happen too often on the Ethereum mainnet or BSC, Polygon does experience multiple forks per day!

But how do you watch for transaction confirmations in the first place? It’s very simple: transactionReceipt.wait(CONFIRMATIONS) … Oh wait…

All of this can easily demand a non-trivial amount of SQL computational power, which you will have to provide and manage. On-premises or in the cloud, this is something that will require your daily attention.

Another consideration is the cost of RPC providers. Properly watching blocks and querying transaction hashes multiple times for confirmations can quickly exhaust your provider’s plan. For example, simply watching a single stablecoin’s Approvals can use up an Infura monthly plan within hours.

Is developing all of this really your priority? Do you really want to spend your team’s limited resources on this quite a secondary task?

This is where 23gate comes in. We are watching for EVM events and deliver simple webhooks to your app. Webhooks are easy to implement on your side, while we take care of managing confirmations, forks, recovery, and running the infrastructure. With our service, you’ll receive a reliable, clean webhook once the event has definitely happened, and we go the extra mile to ensure that we never miss any events.

Register for free and give it a try: https://23gate.com/

PS: Work in developer relations for a public chain? Please talk to us.

--

--