ELI5: Constant Product AMMs

Matthew Taylor
10 min readDec 8, 2023

Welcome to a series of posts where I attempt to ELI5 (Explain Like I’m 5) some of the concepts that are central to Decentralized Finance (DeFi) and some that are specific to Maverick Protocol. I hope that these explanations will be of some help to users who are new to DeFi.

These posts are provided solely for educational purposes and should not be understood to constitute financial advice.

So far in this series we’ve learned what an Automated Market Maker or AMM is, and what it means to be a Liquidity Provider or LP. Let’s quickly recap some of the fundamental ideas:

  • An AMM is a smart contract that offers trades permissionlessly according to a predefined set of rules
  • An LP is a user who provides tokens (i.e., liquidity) to an AMM for it to offer to traders
  • AMMs are dumb

Remember, calling AMMs dumb doesn’t mean they aren’t sophisticated or capable of complicated calculations. It’s just our shorthand for remembering that all they know how to do is follow the set of rules with which they’ve been programmed. This simple fact explains why an AMM is prepared to offer tokens for trade at a price that might be different from the wider market.

In the first post on AMMs, I promised that later we’d learn a little more about how AMMs set prices. That’s what I’m going to talk about in this post. I’m going to do my best to stick to the ELI5 ethos of this series, but it’s difficult to engage with this topic without at least using a couple of math-y words. So if you’re math-averse, please take a deep breath before continuing.

Ready?

In that first post, we imagined what might be the simplest pricing rule we could give to an AMM: just swap all tokens on a 1:1 basis. Meaning that if Alice brings 1 ABC token to the AMM, she should get 1 XYZ token back.

We also immediately saw why this rule would be too simple. For one thing, if the price of XYZ in the open market starts increasing relative to ABC, the AMM’s rule could easily be exploited and no LP would want to give it any tokens to trade. For another, even without market moves we don’t expect all assets to trade 1:1. At time of writing, 1 ETH is valued at just over $2200 USDC, for example.

So clearly, if we want to give an AMM a set of immutable rules it can use to facilitate trades permissionlessly, we need something a little bit more clever than “always swap 1 ABC for 1 XYZ.”

Fortunately, DeFi is full of very clever people, and in 2017 they started working on a pretty straightforward set of rules that would allow a fully permissionless AMM to operate a relatively efficient market for two tokens.

WARNING: INCOMING MATH TERMS

These rules were based on a bit of math (deep breath!) called a constant product formula. As a result, AMMs of this type are referred to as constant product AMMs. You might also have seen them referred to as (deeper breath!) xy = k AMMs. Uniswap V1 and V2 are both examples of constant product AMMs.

To keep things friendly, I’m going to refer to constant product as CP for the rest of the article.

CP is a relatively simple mathematical formula that tells an AMM how to balance and price tokens in a pool. I think it’s still possible to get a sense of how this works without worrying about any of the math. But if you want to know a little more, you can skip to the end of this post for a short appendix that explains the idea in a little more detail.

We already noted that a simple, unvarying 1:1 exchange rate isn’t clever enough to make efficient markets. What’s required is a set of rules that enables price to be dynamic while providing sufficient liquidity that it doesn’t get too dynamic.

What do I mean by too dynamic? Well, first let’s talk about price ranges. Basically every AMM pool is organized according to a price range. In the case of CP, this range stretches from zero to infinity (don’t ask me how–that’s too much math even for me!). What’s important to recognize is that this price range runs in two directions:

In the diagram above, as we move towards the left of the range the price of ABC goes up and the price of XYZ goes down; as we move towards the right, the price of ABC goes down and the price of XYZ goes up.

Using a range like this is the first step towards dynamic pricing in an AMM: if we distribute token liquidity across this range, we can let supply and demand dictate how the price in the pool changes.

Basically, we fill one side with ABC and the other with XYZ. Where the two tokens meet is the current price. If a trader comes and swaps XYZ for ABC, the supply of XYZ in the pool will increase and the supply of ABC will decrease:

In this case, the demand for ABC will create a change in the supply of ABC in the pool, which will cause the price of ABC in the pool to increase. This is good: it means the AMM will react to the basic principles of supply and demand and the price will be updated accordingly. This process is called price discovery, because the AMM is able to “discover” the correct price by adjusting in response to demand from the market.

The next trader who swaps XYZ for ABC will find the price is higher than it was for the first trader, because the pool now has less ABC and more XYZ in it than it did before.

But this still isn’t smart enough, and it’s pretty easy to see why: if we just spread our tokens out equally across the whole range, the price in the pool is going to change very rapidly. Let’s imagine the liquidity in this pool is distributed so there’s 1 token (either ABC or XYZ) at every price point (these price points are commonly referred to as ticks).

In the diagram above, the price of 1 ABC would be 1 XYZ. A trader who comes to the pool will probably expect to get a rate of 1:1 for their swap. But if they want to get 10 ABC, it’s actually going to cost them slightly more than 10 XYZ.

Why’s that?

Without getting too math-y, look at the diagram again:

You can see there’s only 1 ABC available at the first price tick. Meaning there’s 1 ABC available at the price of 1 XYZ. If the AMM wants to fulfill a 10 ABC swap, it’s going to have to move to the next tick to find more ABC. In this case, it will find 1 ABC priced at 1.01 XYZ. At this point, the trader is already having to pay 2.01 XYZ for 2 ABC. And the AMM is going to have to keep moving left to find enough ABC for this trader’s swap.

Skipping ahead, in order to fulfill the trader’s order of 10 ABC, the AMM is going to discover that it has to charge the trader 10.45 XYZ (trust me). This may not seem like the end of the world, but the trader was probably expecting to pay something closer to 10 XYZ!

This difference between the current price and the price the trader actually pays for their swap is commonly referred to as price impact.

Obviously, the bigger the swap, the larger the price impact is likely to be. In our example, it’s easy to see how a swap for 5 ABC would have had a lower price impact, since the AMM would only have had to cross five ticks to get the tokens required.

So in order to build an AMM that could facilitate real markets, we need something that allows for price discovery while also limiting price impact.

CP was the first good solution to this problem to be widely adopted by DeFi. Again, without getting into the math, CP uses a relatively simple formula to help the AMM arrange liquidity along the price range in a more efficient manner.

One way of understanding what CP does would be to imagine that the price ticks at the center of the range are wider than the ticks at either end, meaning more tokens need to be sold at the center before the price changes:

The ticks effectively get narrower the further the price moves from the center. This means that the price changes more quickly the further trading action moves from the center.

This helps protect the pool (and its LPs!) from getting drained entirely, since every time the AMM changes ticks the price goes up, and with progressively less liquidity at each tick the price will go up faster and faster. Anyone looking to drink the LPs’ milkshake is going to find they have to pay a LOT to do so.

Would Daniel Plainview have been a Maxi?

While still a fairly blunt instrument, CP was a genuine gamechanger in the story of DeFi. Given a simple formula, an AMM smart contract was now capable of managing tokens in a way that ensured stable pricing in periods of low volatility, while also reacting to higher volatility with increasingly aggressive pricing–basically mimicking the core functions of a traditional market maker.

Of course, builders have spent the years since the advent of CP finding ways to refine and innovate AMM smart contracts. But CP has been the foundation of most–if not all–of the AMMs that followed.

Quick recap of some of the jargon we learned today:

  • Constant product or xy = k — a magic formula that tells an AMM how to price liquidity while minimizing price impact
  • Price discovery — how an AMM finds the correct market value for assets it manages by responding to trading demand
  • Price impact — any difference between the AMM price and the price a trader is quoted for an actual swap, caused by the impact of their swap on the liquidity in a pool
  • Tick — an individual price point along the price range in an AMM pool

That’s it for this post! Unless you want to have a go at understanding CP in a little more detail. But that requires a little more math. You have been warned!

Like I said above, we’re going to talk about some math now.

So this is your last chance if you want to avoid all of that stuff.

Final warning.

Okay, if you’re still with me, that means you’re curious to learn a little more about how a constant product AMM manages tokens and sets prices. As we already covered, this is all facilitated by a simple mathematical formula. This formula operates as perhaps the first and most basic rule in the constant product AMM.

And that formula or rule simply states: xy = k.

If you’re new to math, this simply means that if we take the value x and the value y and multiply them together, the answer should always be k.

In the context of an AMM, x and y are the respective amounts of the two tokens in a given pool. So x could be USDC and y could be ETH. Let’s continue thinking in terms of our imaginary ABC and XYZ tokens, and assume x = the amount of ABC and y = the amount of XYZ.

The k is something called an invariant. This just means it’s a value that never changes (it doesn’t vary). The formula tells the AMM to keep k constant. That means that the amount of ABC multiplied by the amount of XYZ should always produce the same value for the invariant.

This simple rule is all that’s needed for the AMM to do the magical pricing we explored above.

Instead of swapping tokens 1:1, when a trader asks for a swap with a pool, the AMM uses this formula to determine the appropriate input and output for the swap. Remember, any change to the token amounts in the pool still has to produce the same invariant. So if a user offers 10 ABC to the pool, the AMM runs a quick calculation for how much XYZ needs to be removed from the pool to keep k the same. This supplies the price for the swap.

A quick example, then we’ll be done. Imagine a constant product AMM pool that starts with 100 ABC and 100 XYZ in it. That means our x and y values are each 100. 100 multiplied by 100 produces 10,000.

That’s our k, and the big rule states that this number cannot change.

Whatever else happens in the pool, the dumb AMM only knows one thing: keep k at 10,000.

If a user wants to trade 10 ABC into the pool, the AMM knows the ABC amount will increase by 10, so our x will become 110. In order to keep k the same, the amount of XYZ (our y), will have to be decreased.

The math here is quite simple: k/x = y. The invariant divided by the new ABC amount will yield the required XYZ amount. 10,000 divided by 110 is 90.909. So to keep k constant, we’ll need to reduce the current amount of XYZ to 90.909.

We started at 100. 100 minus 90.909 is 9.091. The AMM knows to give the trader 9.091 XYZ back.

If you’ve been following everything so far, you’ll notice that this swap had quite a high price impact: the user swapped 10 ABC and only got 9.091 XYZ. But our pool had relatively low liquidity (100 ABC and 100 XYZ), so their swap of 10 ABC had a large impact on the price. In a pool with higher liquidity, the price impact would be lower.

--

--