How we scaled to serve $50B+ volume on chain | Aditya, Polymarket | ETHTaipei 2026
ETHTaipei·Sat, Oct 3, 2026, 12:00 AM
How we scaled to serve $50B+ volume on chain | Aditya, Polymarket | ETHTaipei 2026
Transcript
Thanks, guys.
Yeah. So So today's talk is more about how we are scaling prediction markets on chain. So like mainly about how we support all the volume that we get and how we able to run on polygon chain and not have our own up chain or not not our own dedicated how we are able to run it on an existing L2 and still serve customers and still have all the volume. And mainly going through all the protocol optimizations that we have been doing to enable that. So before we start on the V2 process, I want to explain how the V1 worked for these like last 5 years.
We built on top of the noses conditional token framework. So this was a contract built by the noses foundation. The same guys who wrote the the noses multi-sig safe. And the primitive was pretty simple, right? You deposit one USDC or one collateral token on any prediction market and it gives you one yes and one no.
And whenever the prediction market gets resolved like let's say will eat Taipei happen in September, it gets resolved to yes. So whoever holds the yes can claim it back to the winning yes. So they can claim it back to the whole USDC. And the person who had the no, their value token value is zero. If the market was like will eat Taipei happen in October, the no will win to like the no will have a payout of $1 and then the person who will hold the yes has practically nothing.
But on the other hand if I have a both yes and a no token, I can still merge them and get the dollar back that I put in. So that way like it's always collateralized. And behind the scenes how we do it is that we have the conditional tokens contract and we create a question on the UMA protocol whether this will happen or not. Uh UMA provides us an answer for the real world event that happens. And based on that, you know, we decide how we want to provide the payouts.
So, if UMA says, "Yeah, this event happened." we will record it on the contract. The answer is here. And then the year wallet that contains the collateral and the positions, you can, you know, go and get it redeemed redeemed from the conditional token. So, in the V1, the biggest bottleneck that we have is we have to do a lot of transactions on chain before we are able to let you trade on the market.
So, on the conditional tokens, we have to create a market. Hey, this is a prediction market saying whether the ETH/USD event will happen or not. On the UMA side, we have to give them a question saying, "Hey, we are creating this market. We want to know this answer whenever this market is solvable." And in case the market has multiple outcomes, for example, um take an election market like we have five different candidates and there's not a binary market, so there's no yes or no.
It's a multiple outcome market as in will candidate A win, B win, C win. That would be a negist market. So, we will have to go to UMA and create five questions. Hey, will candidate A win? Will B win?
Will C win? So, that's a lot of on-chain um transactions that we have to do and that's a lot of overhead that we have to deal with before we can even start trading on the market. So, once you're starting trading on the market, again, you have to do a lot of on-chain reads, which like are S-loads and they cost a lot. So, whenever you split on a condition, split is when you like put put a collateral and you redeem yes and no. Uh you again have to read some storage.
Same with convert and same with redeem. And in the V1, which is the Gnosis version of the protocol, every market is tied to the article. So once we create a market that UMA is going to resolve it, only UMA can provide an answer. And if UMA or any third party dependency for that matter, they go down or something happens which is not under control, users are stuck with the collateral. Users cannot redeem it and users are you know, basically left holding a token that's worthless.
So in V2 we try to split it up. We firstly we modularize the whole architecture in such a way that hey, we have a markets module that controls all our markets and then we allow the possibility of an oracle aggregator that can aggregate multiple oracle sources for us to provide a resolution. So we can switch UMA, we can have Chainlink provide some data. We can have any kind of oracle on chain which provides us data which you we can use to resolve our markets. And the markets module defines all the modules that we have which will define the rules of the prediction contract.
For example, binary module will tell you hey, this is a yes or no market. A negative module which is a negative risk module will tell you hey, this is a market with multiple outcomes. A combinatorial module will have markets where you can take parlays which is essentially combining two or more bets together. For example, I can win on two predictions coming true at the same time and the payout would be much higher. The directional module is more of a directional thing where I can bet on the direction of something.
For example, I can bet on uh will will team X score more than five, more than six, more than seven points in a game? So depending on my direction of the market, I the payout will vary and I can hopefully score a better payout. And it improves the capital efficiency for the market. But behind the scenes there's all position manager which actually records all your balances and we have the collateral token which is PUSD. So everything is very modularized and it allows us to, you know, have better on-chain efficiencies.
Instead of storing everything on-chain, we try to derive everything on-chain. So, what that means is a position ID here is everything we try to pack it in a 256-bit word. The module is the first eight bits. The base hash actually contains the actual crux of the market. So, for example, I can have a market identifier like will ETH 2.
0 happen this September? And I can hash it and I can hash it into 128 bits and everything else will tell me everything about the market like how many conditions does this market have? For example, is it a yes or no? In that case, the ID would be two. If there are multiple outcomes in that market, the ID would be the number of the outcomes that we have.
Then the resolution chain, for example, right now we are based on Polygon, so that would be the Polygon chain ID. The condition index would be the index of the actual token position token that you're holding. For example, are you token holding yes of that market? That would be zero. Are you holding no of that market?
That would be one. So, if we try to pack everything into one word, it reduces the reads and writes for our chain a lot and that's primarily how we are able to, you know, scale without bloating up the chain essentially. So, for example, in the V2, it's very simple from a position ID. A position ID is just the ID of your yes or no token that you hold. Based on that token, we can derive off-chain what what exactly is the market that you're holding, how many conditions this market has, and what kind of payout will this market get based on the contract.
So, it's a very simple read. We just check the module. For example, the negative position will have second module, and we can just get the payout from that module. So, it's just one read instead of having three reads. Earlier, we had to read, hey, what kind of depending on the position that you have, what is the market of your position?
Based on the market, what is the payout of your position? And then how to redeem that payout. Right. So, instead of V1, we had to prepare a condition. So, we had to write on chain.
In V2, we just derived the condition off chain and we start splitting on it immediately. We don't even uh So, yeah. Oracles can be set up way, way later. We don't have to immediately tell UMA that, "Hey, we're creating a market." We don't have to go Chainlink and check, "Do you have a price feed for this market?"
We can just start splitting on the condition. And whenever the time comes to resolve the market, then we can lazily derive the oracle side of things and we can configure that on the oracles that "Hey, we have this market already being traded on. Um we want a resolution for this market and uh let's say in this case, UMA will provide us the resolution. So, we just register the question on UMA and UMA can provide us with the result whenever the market is resolvable." Um in case of the next markets, which is like the multiple outcome markets, earlier [snorts] we had to create questions for all of the outcomes.
If we had, let's say, 20 outcomes, we had to create 20 questions on UMA. Now, with this, uh especially with the lazy initialization, if we know who's the winner, we can just request that particular outcome. And if we get the answer for that, which is guaranteed by the UMA protocol to be uh optimistic and uh it's like they can dispute the uh resolution, so it's pretty safe for us to use it and we can just request, "Hey, what is the outcome of this market?" If this is this is the outcome, yeah, we can just uh store that on chain and everything else just derives automatically because only one outcome can be the yes. So, once we get the yes, everything else resolves to no.
So, this way we don't have to write 20 results on chain. We can just write one and derive the rest. Yeah. So, same thing here. If B wins, we store the event total as one.
A and C automatically gets derived as no. If you're holding the no, you can redeem it for one collateral each. Uh because it's a next market, so it's negative risk in the sense that if I'm holding no of a market, I can uh I I still win because let's say candidate H won and I was holding no of candidate B, I can still redeem my collateral. On the oracle side, we have added support for many many different oracles. We have Uma as the OG which provides us all the real world events.
We started integrating Chainlink, so we have Chainlink price feeds for the 5 and 15-minute crypto markets. We'll also add real world assets pretty soon, so you will be able to we'll be able to create prediction markets on the prices of real world assets, oil, gas, etc. We also have authorized accounts for institutionals and OTC markets. And the aggregator combines it everything into the market module. So we have like a easy way to just lazily initialize the market from the oracle perspective whenever we need to.
And uh on the oracle aggregator side as well, we made sure to keep it trustless and decentralized to the point where people still can go dispute. For example, if you think Chainlink reported a wrong price, something bad happened, although that's we don't expect that to happen, but in case Chainlink went wrong, you can still come to the contracts and you can dispute how Chainlink did something and you will be paid for disputing it if you turn out to be right. So V2 still stores the balances of your collateral [snorts] and positions. It still stores the results, but as I said, the results are much much less heavier to store compared to our previous protocol. Uh the rules and progress is still stored.
The progress of the market is it still initialized? Is it pending resolution? And the combined definition. So combined definition is let's say I'm taking a combinatorial parlay on two markets being connected together. In that case, yeah, I would still prepare the condition that says, "Hey, I want to place a bet on X being right and Y being right."
Yeah. So the parlay here will be A being yes and B being yes. We hash the condition together and we will store this condition underlying in the combinatorial module, but this is only for like again combine combined positions. For your regular positions, we don't need to store that at all and that saves a lot of gas for us. So, generally V2 stores much less data.
The structured ID IDs is something that we can read right from the token IDs. We don't need to look up on chain. If you have a token ID, I can tell you what market you have. Um in case of the latest setup, as I said, we can keep spinning markets. We can So, for example, at Polymarket scale, we create about 30,000 markets every day and we don't need to initialize them on chain.
We only need need to initialize a market on chain whenever it's time to resolve. So, I can create a market today about something happening in December, but on chain transactions can only go in December. And that gives us a lot of head room to actually do our chain executions. One event winner, uh yeah. Based on the markets, we just need to store one result for multiple outcome markets and that provides us the result for every other outcome on the market.
And then the article aggregator provides us uh easy way to separate our article bindings and, you know, have support for multiple types of articles. Uh yeah, that's it for me, guys. Uh any questions?
Yes, Alan. Uh sorry.
Hey, great talk. Um I have two short questions. First one is how did you manage the migration of like V1 and V2? Did you like simultaneously support V1 and V2 or did you convert the V1s into V2?
Yeah, it's simultaneous right now. So, V1 markets that are present, they will keep on ongoing. Meanwhile, we are rolling out V2 markets pretty soon.
I see. So, the long-lived markets are still in V1, right?
Yeah.
Okay. And then second question is, do you have any rough sense of the gas savings? Cuz clearly this should save a lot of gas. So, like um you guys sponsor all the on-chain transactions on Polygon. So, I'm wondering like what the gas footprint looks like today with V1 and V2 versus like when you only had V1 markets.
Has it um decreased the expenses there?
Right. So, on our peak uh we ended up consuming about 70% of all the block space on Polygon. And our current estimate is we will be able to reduce it to about 30%.
30%?
Yeah.
Thank you.
All right. We still have a some time for the last question. Anyone want to raise your hand? Let me count down to from 10 to 1. 10 9
Thanks, guys.
No. Okay. Thank you.
[music]
Automatic transcript — names and jargon may be misspelled.