How to Architect Event-Driven Ethereum Apps | Aditi Polkam | ETHMumbai 2026
ETHMumbai·Thu, Jul 9, 2026, 12:00 AM
We’ll walk through a production-ready, event-driven architecture for AI-powered dApps: indexing events, queueing, inference services, and on-chain execution. You’ll see how to handle chain reorganizations, non-deterministic model outputs, idempotency, and why inference results must be treated as state. You’ll leave with practical patterns for building scalable, reliable AI-powered Ethereum applications and a clear mental model for why the bottleneck isn’t your model, it’s your architecture. Follow Aditi on X: https://x.com/aditipolkam Follow ETHMumbai on X: https://x.com/ethmumbai ETHMumbai 2026 is the BEST Ethereum Conference & Hackathon hosted on 12th – 15th March 2026 in Mumbai.
Transcript
I'm Aditi. I am a back-end and infrastructure engineer at Offline Protocol. And today I'll walk you all through how to architect event-driven uh blockchain app uh dapps using off-chain microservices. Yeah. So, I was saying uh when we talk about Ethereum applications, what we usually think as new developers is we the user sends a contract uh sorry, transaction to the contract.
The contract updates the state, and then the front end reads back the data from the blockchain. So, the mental model here becomes write to the chain and read from the chain. But the reality of production Ethereum applications is quite different. The modern dapps that we use on a daily basis, like uh you DeFi dashboards, leaderboards, notification systems, or analytics uh a platform, social feeds, etc., those are uh powered through like they're not actually querying the blockchain on every refresh.
These uh applications are powered through off-chain a pipeline of off-chain services um which are in indexing event data blockchain event data and then processing it into a useful application state. So, um smart contracts don't run uh applications alone. Infrastructure does. Which means uh we have a couple of uh
[snorts]
services that are running full time to provide you the data uh instantly, which involves event listeners that are uh listening to the chain, that are tracking events, queues that are buffering blockchain data, and worker services that are picking that data from the queues, and then processing however you require, and then we have APIs that serve fast responses to the user. For example, uh Uniswap doesn't query uh the blockchain on every refresh or any other application that you use uh does not query the blockchain for any read transaction. So, um why when when we can actually query, why do we uh have to build all these off-chain services, all this complex infrastructure? Because, first of all, Ethereum is not request-response. You cannot ask the chain, you cannot ask the chain that give me all of the user transactions for this particular smart contract or the the last Uh you cannot ask the chain give me uh all of the borrow positions for this protocol or anything like that.
Because the you'd have to store that in the contract and that requires gas. But, we don't need to do that. We have events for that. For example, in an ERC-20 contract, this transfer event uh becomes the only efficient way to track token balances, to detect payments, and monitor activity. Um so, yeah.
Now, these events uh the example that I showed for the ERC-20 was written in Solidity. Uh taking the example of Solidity, it's events are somewhat like this. Um we can see that some events some parameters are have a field called indexed. We'll come back to that later, but to on on a overview, Solidity events make a data layer that that uh that is structured, efficient, and immutable, meaning that it has a defined format. Um efficient means it is queryable via Bloom filters.
Um and immutable means, of course, every on the blockchain is immutable and stored permanently as transaction receipts. Okay, so why do index events matter? First of all, you cannot continuously scan the chain for whatever data you want. When you index index a particular field, you can just if for example, you want a particular user's transactions. So those you can initialize a filter for that using the index events.
Now, I'll not get into the programming details over here, but yeah, you can use use the index fields to basically filter your events however you like. Now, but the only constraints that the index fields here are you can only index three fields per event. There can be no range queries. That means you are not allowed to query based on numbers. That That means you need an amount greater than 10,000 or something like that.
And you must filter off-chain, of course. So for this filtering off-chain, you can write um event listeners using Rust, Go, Python, or TypeScript, any any language that you prefer. So I would divide the architecture into three phases. First phase being ingestion, which means capturing blockchain events, uh and this architecture basically involves the first is the Ethereum node that is of course the source of truth for our transactions. Second would be the event listener, which of course I mentioned that we can write that using any language preferred.
Um this this event listener will constantly listen for the transactions happening on chain, and then it will transfer it to the queue, which is the message broker over here. And that queue is basically responsible for absorbing the spikes that can happen in your system or anything like your workers can consume it through the queue. So The phase two would be processing, transforming events into application state. Here what we do is pick up applications from the message broker and the worker services can process it however you require. Suppose it is a lending protocol and you want to uh you want to group transaction based on a particular user.
So worker services could do that and then put it into a state database from where your front end would actually use it. Now worker services can be horizontally scaled, meaning each worker could there could be multiple workers and those could process events asynchronously and parallelly. Okay, next. The phase three in the final stage of this architecture would be consumption and this happens basically on the front end side where a user needs particular data and they query the whatever API endpoint they have. This is then fetched through the state database.
For example, leaderboards. So top 10 users of this week it's fetched through the database and then showed it on the front end. This also involves web sockets optionally if you want real-time data, which could be price feeds or anything like that. So yeah. The Talking about the performance and reliability over here, there are certain problems to handle while designing for scale and that is there could be duplicate events.
This can happen because of RPC nodes going down or you are using suppose different the multiple RPC nodes to index transactions and one of them or two of them just miss the transactions uh in your event listener. So, it is important that the solution here be item potent workers means every if if you compute the same event again and again, the output should result in the same thing. Suppose you're calculating like token balances and there is a transfer event from my account to your account. So, it is important that if the event is processed again, it should not result in my balance being um double twice minus and then yours would be like gained two times. So, that is why item potent workers are important.
Then the there could be out of order logs just as duplicate events. They do these could happen and then event versioning is important for that. Then there are chain reorganizations uh that take place. So, we also have to maintain like block number checkpoints. Like we processed suppose a 10,000 number block the last time.
So, if our event goes our event listener goes down or suppose RPC node goes down, we have to start processing from the 10,001 block again. So, making sure this is done and then there are RPC node inconsistencies again. So, we'll also have to maintain uh replayable pipelines means uh you you should be able to compute the state again as it was earlier. So, considering a lending protocol example, how this would work is um we've we've all used a lending protocol at some point. So, the user transacts with the lending protocol.
The contract processes the transaction, the event is emitted, and then the listener detects it. After the listener is listener detects it, it puts it into a queue where it can be there in for some time, and then whatever worker is present is idle can pick it up. It recalculates all of the processing, and then flags if there is a risk involved, or updates the API dashboard accordingly. And then, yeah, I mean this data can be queried multiple times by the front end. It would still be the same as it is in the state database, and also it will be cost efficient, and also fast.
So, thank you.
Automatic transcript — names and jargon may be misspelled.