Life of a Fill: How Market Makers Work on UniswapX | Alan Wu, Uniswap | ETHTaipei 2026
ETHTaipei·Sat, Oct 3, 2026, 12:00 AM
Life of a Fill: How Market Makers Work on UniswapX | Alan Wu, Uniswap | ETHTaipei 2026
Transcript
Hey everyone. Uh metallics are pretty tough act to follow, so bear with me. But um but yeah, I'm Alan. I'm a protocol engineer at Uniswap. Um it's great to be back here.
Um I've given previous talks in the past about Uniswap X auction design and the protocol itself. But today I wanted to talk to about something that isn't um shown as much, and it's the Uniswap RFQ, and specifically what it's like to be a market maker in that protocol. So, today we're going to be following a trade through the system and seeing how market makers um work in Uniswap X and how they fill trades for swappers. First thing is Uniswap X uses intents. So, with a typical AMM swap, you're going to have some kind of routing algorithm that finds a path of pools for you to trade through.
Then the swapper themselves are going to use the call data and then execute it on chain. With Uniswap X instead, the swapper would sign a message off chain describing the trade that they want. So, it would look something like a minimum amount and a deadline on the trade. That's called an intent. So, they ultimately don't care what path it takes.
The filler, which is the person that we're calling the market maker, is going to figure out how to satisfy that trade and send the transaction on chain to settle it. Because the filler is the one who's sending the transaction, Uniswap X swaps are effectively gasless for swappers. Intent-based trading is a general pattern, but in it says what outcome the user wants and what conditions must be met, but it doesn't necessarily specify anything about price discovery. So, we can put different mechanisms behind it, which includes an RFQ, a Dutch auction, or a MEV tax, which is what my talk last year was about. Um today we're going to be focusing on the RFQ, and more specifically, what it's like to be a market maker that interacts with that protocol.
This one's a little bit special because it's pretty distinct from the other auction mechanisms because it has a significant off-chain component that we'll be discussing today. So, let's start with what an RFQ allows us to do. So, AMM liquidity gets updated in blocks, and during the time between the blocks, the state of the pools are staying the same even though the market price is actually changing. The same AMM route that you might be quoting through is going to go through the same state and give you the same stale price while the market is still moving just because of the block time. And this is particularly pronounced on mainnet because of the long block times.
What we can do is run RFQs off-chain, which we can do continuously instead of needing to wait for a block. And this is going to give us finer-grained price discovery. So, we ultimately are still going to settle the trade on-chain, but we just don't need to do the pricing part on-chain. So, think of a market price like a continuous process, and AMM routing is just looking at discrete snapshots of that. Um with an RFQ, we won't need to restrict ourselves to um price discovery in those moments.
So, that's the RFQ pattern. Basically, we discover the price off-chain and then execute the agreed trade on-chain. And this is going to allow market makers to um return fresh offers between blocks. And once the trade is ready, the winner of the RFQ is responsible for sending the transaction on-chain to execute it in the next block. This way, we get fresh off-chain price discovery while also using smart contracts on-chain to enforce the trades.
To make this more concrete, let's look at what an RFQ quote actually looks like in this system. So, let's say a swapper wants to sell one ETH for USDC. The RFQ quote they see is 2990. And that's what I mean by a quote here. It's the amount of USDC a market maker is willing to offer the swapper for one ETH.
And that's not a transaction yet at this stage. This is still off-chain. This is just the price that they're naming. So, where did that price come from? It starts like this.
The swapper's request is going to reach the Uniswap X off-chain RFQ system, and then it's sent to a set of market makers. So, market maker one says quotes 2980. Market maker two, which is going to serve as the example today, um offers 2990. And then let's say a third market maker chooses not to quote. And um the best quote wins in this, which is why 2990 is ultimately the quote.
So, this is a blind first price auction. So, the other market makers can't see what the other people are quoting, and the highest price of that set is going to be selected as the quote. Let's zoom in to one of the market makers see what it looks like from their end. So, each market maker is going to receive a request for a trade. Here it's one ETH to USDC on mainnet.
And within 500 milliseconds, they have to respond to the system with a quote or respond with something called a no quote. And this is important because this is distinguishing the case of the failure being alive and participating versus like timing out and potentially being broken. Then the best quote among all the makers who do this is going to go back to the swapper as a quote. If the swapper likes what they see, then they can sign a message saying that they want to take that trade, and that uses permit two. And now at this stage, the market maker is going to be responsible for executing this trade on chain in the next block.
So, that's the simple flow. You have a quote, the swapper likes it, they'll sign it, and then the filler is going to execute it on chain for them in the next block. But, the issue is the swapper might pause, or they might need to connect a hardware wallet, or they just might be slow. So, a price that they saw before that they're signing in their wallet might be old. And then they shouldn't be able to force the market maker to honor some old price just because they sent the message later.
So, we need to add a second quote after the signature to get a fresh price right before execution. And so, we call this the soft quote and the hard quote. And this is what the final trade parameters are based on with the user's signed constraints in their permit two message. So, putting that together, we have the swap soft quote, the user signing, and then a hard quote, and then all these actions happen off chain. Once the hard quote gives us the final trade with the final price and the filler, who is the RFQ winner, that person is supposed to fill the trade on chain in the next block.
If they don't do it, then the order will go into an open Dutch fallback, which is just running a permissionless Dutch auction on chain. We'll talk about the consequences of that later, but we can continue this example um from the market maker's perspective. So, imagine we're market maker two, and then we win this fresh hard quote um round with 2990 USDC. Now we're the selected filler. We need to send a transaction the next block that delivers the USDC to the swapper in exchange for their ETH.
Before we go into how they came up with 2990, let's actually just look at um what they need to do to execute the transaction. So, there's two broad families of market makers that we see. One is using on-chain liquidity. Um this is like they would take the one ETH from the swapper in a transaction, they'll route it through a bunch of pools, and then try to get more than what they need to pay. They want to get more than 2990 from the ETH, and then 2990 goes to the swapper, and then they can keep the rest of the money as their um gross profit.
The second um approach is using inventory. And this is where the market maker is going to pay from their own balances and handle that exposure. So, whether it's like carrying the exposure, rebalancing, and hedging, um this follows general market making more closely. So, this is the example we're going to go through today. For this inventory strategy, our market maker needs to have an on-chain component, um which is a smart contract that we're going to call an executor contract.
This is a contract that's going to hold the market maker's inventory on-chain, so that they can service the trades of the swappers. Um so, if we're the market maker, we're going to send a transaction to our executor contract, which is going to call the Uniswap X contract, and then there's going to be a callback back into our own contract where we can have our own arbitrary strategies run um and safety checks. Like one example could be if um in the middle of a transaction, we're going to fulfill the trade um with um deposits that we had in some lending protocols. So, we can take that out immediately, fulfill the trade, and then put the proceeds back in lending, so we're earning yield um even when we're not actually trading. So, this is Uniswap X smart contract is the bridge between the off-chain quotes and the assets actually changing hands on chain.
So, let's look at the rest of the inventory book behind that quote. The point is that the smart contract that holds the inventory isn't the only place our capital lives as a market maker. We might also have spot inventory on Binance or it might have collateral supporting some kind of perp hedge on Hyperliquid. So, ultimately we need to price the whole book including where we can use that capital and accounting the fact that our capital might be split up on Binance and on chain and having collateral on Hyperliquid. And this is important because transfers between these venues are going to take time, they're going to take fees and then we also have to do the work of it.
The collateral on Hyperliquid also has an opportunity cost, right? If it's sitting there and also needing to account for the funding rates on those which could help us or hurt us. So, we need account for all of these things when we quote. So, before we quote we need to think about the cost and the risk of exposure from taking on the trade. We also need to think about what edge we get from quoting which is the value we expect from the trade and these economics need to work out for us and we also ultimately obviously need to have the capital on chain to deliver the funds to the swapper.
Let's turn this into an actual quote. So, the swapper wants to sell one ETH. We're going to buy it from them. How much USDC should we offer? A good starting point is like having some kind of reference price which is some kind of model or feed that gives an us an idea of fair value.
This is just a starting point and then it's not what we should quote. How we should think about it is in terms of a spread which is a price we're willing to buy at and a price we're willing to sell at. So, how much spread do we need? First, we want to think about the width of our spread. If the execution is expensive or there's a lot of uncertainty, we may need a larger spread.
If we have better execution or um cheaper hedging, then we can quote more tightly. The spread basically has to support the costs and the risks of winning the trade. It also affects how our offer's going to compare to the other market makers. And this is just a simple symmetric example, but the actual like real-life policy may be more complex. The second thing to think about is the centering of the spread.
We need to think about the movement of capital between our different venues. And this is because one ETH on Binance is not worth exactly the same as one ETH on mainnet or um plus one ETH of exposure on Hyperliquid. So, we need to account for the cost of carrying that exposure and moving positions between these different venues. And that's the structural basis part of the problem. Um separately, we might want to accumulate or um reduce exposure to balance the inventory so that we can surface service both sides of a trade.
So, on top of the structural basis, the inventory management strategy also can bias our quotes. Here's an example of that. One example is shifting the spread. So, imagine that our book is long ETH. In this example, we can shift our spread down because when a user so that when a user sells ETH to us, um we bid less because we're less competitive about going even more long if we're already long.
And if a user wants to buy ETH from us, we can offer it for less because we're more keen and competitive about reducing our exposure to be a little bit more neutral. So, the idea is that future order flow can help us rebalance instead of needing to hedge every single time and incur the costs of that. But this is obviously statistical. It's not guaranteed. We need to account for like what order flow is going to come in the future and how long we're comfortable holding risk in a non-neutral position.
External hedging is the other tool, but as I'm alluding to, it's not costless and it requires work. We can sell existing spot on Binance right away, but that's going to have us cross the spread and pay fees. Or we might leave a limit order, but a limit order isn't guaranteed to fill. Or we can just hedge part of the exposure. We can like hedge it over time gradually.
And ultimately, even if we have a spot hedge and our book is now delta neutral, it might result in us only having ETH on chain and only having USDC on Binance and then needing to rebalance that. So, we still have to move capital between the venues and we have to account for withdrawals and fees and delays because that can affect what we're able to quote. And for perps, we're going to have to manage the collateral and the funding rates instead. So, when we do this, we have to account for all of these things. And there is no single answer for how you should be managing inventory and hedging.
We don't know what every market maker is doing. Everyone has their own strategies. Everything I've discussed is just possibilities and ideas, not a blueprint that everybody's following. A simple example to tie it together is we're going to do a carry in a quote skew around some kind of target inventory. And then as we deviate from that, we're going to start hedging.
And then maybe at a certain point, we'll just stop gaining more exposure in a certain direction, not quote trades in those directions anymore. And all the parameters for that would just be based on measurements or certain thresholds. Now, let's do another exercise. Imagine the request wasn't one ETH anymore, but it's now 100 ETH. At first, this might sound like we're going to give a strictly worse price because it's more exposure and it's going to be harder to hedge.
And the curve here is going to show that is capturing that intuition, but that only looks at this order in isolation. We need to take a more holistic view on what this trade means in the context of our current book before concluding that bigger just necessarily means worse. So, here's what I mean by that. Imagine we had our book with plus 20 ETH of exposure. After the trade, it's going to be even greater at plus 120.
And then imagine another world where we're 90 ETH short and then taking this trade is going to bring us to plus 10 ETH of exposure. So, winning this trade would bring the book closer to neutral for us. So, we have more of a reason to want this order and then pass some of that value back as a better price. So, for this specific book on the right, this trade of 100 ETH will simultaneously solve an exposure problem for us. And that's why the same request might get really different responses from different market makers.
So, bringing it all together, we're effectively just creating some kind of pricing surface that helps us decide how much to quote for a trade. And this is just an illustration. This is not a formula everyone is using, but basically we just need to come up with a price when we're asked to give one. And we'll have a model with rules, statistics, and whatever optimizations. So, going back to the example, now we understand the work of what it takes to quote and the number behind what we're quoting.
Assuming that our hard quote won, we want to ask the question of if that's good. We won maybe because we actually have an advantage, but we have to think about why we beat the other market makers. Why did market maker one quote less than we did? And got that gets into the idea of winners curse and adverse selection. So we saw earlier how um the same trade can be genuinely worth more to one market maker than another, but we have to think about why the other market makers gave worse prices.
Do they know something? Does the swapper know something that we don't? Um this is just adverse selection and being wrong could make us actually win, which could actually have consequences because winning isn't always a good sign. So we thought through how we quote and um what winning is telling us. At this point, we still need to execute the trade and hedge.
So let's see what that looks like. Now we need to get the fill transaction on chain and successfully executed. So what we're going to do is we're going to read the order and then we're going to build our transaction that starts in our executor smart contract and then that contract is going to call into the Uniswap X contract and then when the callback reaches our contract, we can do whatever on chain strategies and safety checks that we need to do and the Uniswap X contract will finish the settlement of the trade. Because we're um the person sending the transaction as a market maker, uh we have to account for gas and so um the cost of gas also needs to be reflected in our pricing. We also need to account for annoying things like reorgs, especially if we're hedging.
So speaking of hedging, um say we bought the one ETH on the fill. Now we need to hedge that. Is it as simple as just um taking the opposite side of the trade somewhere else? It's a little harder than that because even though the on chain transaction is atomic, um our hedging off chain is not atomic with that um because our quote used a hedge estimate that was based on whatever we saw before we quoted. And by the time we win, that estimate might already be stale.
And the next thing we think about is should we hedge before the trade where like if we fail the trade, we're still stuck with the exposure on the hedge or if we decide to hedge after the trade, the cost of that hedging might have changed by the time we get there. So these are risks that need to be accounted for in our quotes and obviously hedging is a very very big space and these are just some example thoughts of what a market maker might be thinking about when they're doing it for Uniswap X. Moving on, there's like an important question that pops up when we think about this interaction. So the market maker, the filler, is ultimately the person sending the transaction on chain. So there's something else in the second interval where before submitting the transaction on chain, they can keep watching the market.
And if the market moves against them, what if they just break their promise and then they don't send the transaction on chain? What stops them from doing that? Because without consequences, this is a free option for them. In the 10-second example before the next block, if the market moves favorably for them, they can fill it and then if it moves adversely to them, they can just like break their promise and not fill it. So this is So this is generally an option for whoever has last look.
And in Uniswap X, the filler or the market maker is the one with last look and that's why this risk exists. There can be another failure mode where it's like the the filler is just quoting really good quotes and then the swapper always accepts it, but then the market maker never actually delivers it on chain. So this is why backing out of filling even though you made a promise and commitment in the RFQ needs some kind of cost to it. When we call when we see a failure to settle a trade, we call that a fade. And if you fade too much, there is a circuit breaker mechanism in the off-chain RFQ system that basically will pause order flow to a market maker if it detects that it's fading too many trades.
And this is a kind of exponential back-off to discourage this type of behavior. And then during this timeout, they're not going to be able to see new order flow and thus won't have the opportunity to fill those trades. So, what they really need to think about um if they want to decide to fade is what is the what is the amount of money or value they're um saving by avoiding this trade right now versus the value of being able to continue to capture future order flow in whatever timeout period it would cause them. So, from a design perspective, we want to make sure these quotes are commitments to the swapper for good UX, and that's why walking away from them as a market maker should come with some form of cost. So, everything we meet we use to make these quotes had some kind of assumptions about execution, inventory, order flow, hedging, and the risks of um between quoting and actual settlement time.
So, these assumptions aren't static because the markets are evolving, um your swappers are evolve are evolving, uh the competition of your market makers, they're getting better. So, you need to get better as well. So, analytics isn't just about analyzing how you did on a single trade, it's about a more continuous learning process. So, how do we know if we're doing well? Well, we can um compare the edge we modeled, the market the mark out after the trade, and then look at how our hedges executed.
For the simple example, our model used a 3,000 um reference price and we quoted 2990. This implies that our modeled edge was 10. And then another commonly used metric is markout. So, a markout compares our fill price with a market reference a certain amount of time later. So, if we bought one ETH at 2990 and then 5 seconds later it's at 2980, the 5-second markout is minus 10.
And the last thing we should look at is the actual hedge receipt. So, assuming that we sold that ETH at 3,000 um on the hedge 1 second after the fill, we basically want to check if the um price it executed at and the timing and costs um actually aligned with what we expected and calculated when we made the quote. And this is going to tell us how well we realized our hedge. So, a market maker needs some kind of analytics to update on and improve. And zooming out, this is the big picture of the things that a market maker might need to do when they're filling with inventory on Uniswap X.
So, today we covered everything on here, not in super deep detail, but I just wanted to give a broad overview of this landscape. Because when we Because when we typically talk about an RFQ, it sounds like a simple concept and it feels straightforward, but clearly there's just so much beneath the surface. I want to end on putting this system in context. So, when you use the Uniswap interface or API, it's going to kick off two different quotes. One is the classic AMM routing that you're familiar with, and then two, it's going to be the RFQ process.
And then it's going to compare these two quotes, and then whichever is the better one, that's the one that's going to be offered to the swapper. So, all of that prior to execution is happening off-chain. And just to put some numbers on this, in August Uniswap X handled about $800 million of volume, and then this month we've been averaging about $45 million dollars volume. So, something cool I want to point out is that we've seen the RFQ value provide value across blue chips and even meme coins and lately tokenized assets with the rise of RWAs. I know we went through a lot of things today, but thank you for listening.
I'm happy to take any questions now. Thank you.
Automatic transcript — names and jargon may be misspelled.