πŸ”„The 2sAMM

"Two AMM Curves??!? What's next, Re-Re-Re staking?" - SBF from Jail.

This gives a lite technical overview of the Two-Sided AMM. Before diving into its mechanics, it would be helpful to understand what Automated Market Making and Automated Market Taking accomplish.

Some History

Automated Market Making was a momentous step for Decentralized Finance. Anyone could now permission-lessly trade tokens on a decentralized exchanged backed by a decentralized pool of market makers through a single smart contract.

Exactly how these AMM smart contracts decide which price traders get to trade at depends on the algorithm it employs. There have been a number of different algorithms based on unique curves, but the most popular algorithm that has stood the test of time is the constant product formula based AMM. So let's review the history of that before getting to Itos's big upgrade.

Generation 1: Constant Product AMMs (Full-Range)

The first AMM smart contracts defined the swapping curve as xβˆ—y=L2x * y = L^2 where xxand yy are the two token amounts. When someone trades against the pool, they give one token and receive an amount of the other token which keeps the value L2L^2 constant, hence the name constant product. We typically call LL the liquidity value.

For example, say you have 100 of token Y and 1 of token X, then the constant they multiply to is 100 and your liquidity is 10. If someone wants to sell 0.1 of token X to the pool, the pool would have 1.1 X afterwards. Since we always multiple to 100, yβˆ—1.1=100y * 1.1 = 100 means y=1001.1=90.9y = \frac{100}{1.1} = 90.9 . So they get 100 - 90.9 = 9.1 of token Y in return for their 0.1 X.

The brilliance of the formula is that it allows people to add their liquidities together into a single pool people can trade against. For example, if you contribute 100 token Y and 1 tokenY and I contribute 200 token Y and 2 token X, the the pool now has an L2=300βˆ—3β†’L=30L^2 = 300 * 3 \rightarrow L = 30. The total liquidity is 30, 10 from you and 20 from me. Then when someone swaps against our pooled tokens, effectively a third of the swap is against you and two thirds is against me. When we charge trading fees, those fees are then split proportionally.

It's a very convenient and simple algorithm for making a market and most importantly it also captures the idea of price impact. The more of X there is in the pool, the cheaper X is. If the pool holds more Y than X, then Y becomes cheaper.

This is often termed V2 LPing, as in Uniswap V2 because they popularized this type of automated market making.

In our previous example, if someone traded a really small amount of X, they would have traded at a price close to 100 which is yx\frac{y}{x}. But the more X they sell the further the price gets pushes down. For our 0.1 X, we sold at a price of 91 and got 9.1. If someone tried to sell 1 whole X, they would have executed at an effective price of 50. We call this slippage. The more liquidity there is in the pool, the smaller slippage becomes. The larger the trade, the larger slippage becomes.

There is risk that comes with providing liquidity to AMMs. Let's say token X is Ethereum and token Y is USDC, and we care about growing our portfolio in terms of USDC.

Then as the price of Ethereum drops the value of our positions also drops, but if the price of Ethereum goes up, we don't actually get as much profits as we would have had we just held ETH. This is because we're the ones being traded against, as the price is moving up, people are buying ETH away from our deposit. As the price moves down, people are selling their devaluing ETH to us. This is the basis of what people term Impermanent Loss (IL).

Here is the payoff graph displayed explicitly:

Compared to holding the ETH and USDC you had at the start, all that red region is the profits you would miss out on. However in return, you get to earn trading fees. So V2 LPing is a balancing act of getting enough trading fees to compensate for your missed profits (Impermanent Loss).

Some people don't care about the profits they missed out on and just see LPing as a way to earn passive income. In that case they just care about profits and losses compared to the USD value of their position at the start which is called Real PnL. If we compare that way, the payoff graph looks like this:

Here the payoff is more palatable. The profits are a little more muted than losses, but that's okay if the yield is high enough.

The main flaw of this first generation of full-range AMMs is that they're not very capital efficient. You have to add liquidity to support the entire range of prices, this means most of your tokens aren't getting traded against most of the time, and they're not collecting fees then. The second generation aimed to fix that.

Generation 2: Concentrated Liquidity AMMs

The second generaiton of AMMs still follow the standard constant product liquidity curve, xβˆ—y=L2x * y = L^2, but instead of supporting the pool no matter what the ratio of X to Y there is, users could now choose to just provide liquidity to a specific price range. In this case you're adding concentrated liquidity. This let's you earn fees in a very specific region and deposit much fewer tokens thus dramatically increasing your potential earnings but also increasing the Impermanent Loss risk.

By concentrating, more of the user's tokens are traded away. The equation for calculating what is traded away is designed such that by the time you are right on the edge of your selected price range you have traded away all of the more valuable token and are left holding the less valuable token. This exposes you to much more losses than full-range liquidity provision would have.

Below is the equation for concentrated liquidity where PaP_ais the lower price and PbP_b is the upper price bound. Knowing the exact details of this equation is not required to use it. It's simply designed so that within the price bounds you've chosen, the AMM uses your position as if you had deposited in an xβˆ—y=L2x*y = L^2 pool. Outside of the price bounds your position is not used at all, and thus earn no fees.

Here is an example payoff from concentrating liquidity from 1600 to 2500.

And the Impermanent Loss graph looks like this:

And the Real Loss payoff graph is as follows.

Hence you expect more losses regardless of the method of accounting you prefer, but in return you earn much higher fees. This was the previous state of the art design. You can often earn more than ten-fold the APR of un-concentrated liquidity by concentrating but it required frequent management to use profitably.

The usual advise was to rebalance when the position goes past your price range. Rebalancing meant withdrawing your position and re-centering it around the new active price. In reality this was not always a good idea and the best way to profitable provide concentrated liquidity is still a hotly debated topic. Results indicate that more than 50% of positions were better off just holding their tokens, meaning they lost to IL. Now let's see how we can improve this situation.

Generation 3: The Two-Sided AMM (2sAMM)

The first full-range AMMs were simple, comparatively safe and easy to use. Concentrated Liquidity AMMs allowed for much higher returns but were comparatively way more difficult to use properly. It was like adding a gas engine to your bicycle. You went much faster, but you could easily get hurt in the process.

At Itos, this third generation is like adding airbags, brakes, GPS, helmets and more to your AMM. We recognize that you can go farther and faster by adding a few safety measures. Safe yield farming is smart yield farming!

Summary

  1. We rebuilt the Uni-V3 style AMM (CLAMM) from the ground up with the ability to short sections of the liquidity curve.

  2. Now the AMM has both Liquidity Providing positions which earn fees and Liquidity Taking positions that pay fees.

  3. The Liquidity Taking positions earn impermanent gain, are totally customizable, have no lockup and are as simple to use as liquidity providing positions.

  4. By combining Liquidity Providing and Liquidity Taking, we can hedge the risks that come from normal concentrated liquidity provisioning and then take advantage of liquidation-free leverage to boost yields even further.

  5. Once we add other positions (like token deposits, borrows, perps, and more) into the mix with our Universal Cross-Margin-er, we can create custom and powerful new DeFi primitives.

2sAMM Details

At a high level, the 2sAMM is composed of two sides, the liquidity providing side and the liquidity taking side. The liquidity providing side's curve is identical to a Generation 2 AMM. The liquidity taking side has an opposing curve and introduces the concept of Automated Market Taking. More details about the concept are found on the dedicated page. Here we'll go into depth about the operational mechanics.

Liquidity Depositing a.k.a Makers

When users deposit liquidity in our 2sAMM, they earn two sources of yield: swap fees and time premiums. Additionally, there are often staking opportunities to earn rewards.

To earn swap fees, users deposits are used to market make just like Uniswap V3 and V2. While we had to write our 2sAMM contract from scratch, we made sure to reuse the core functionality of Uniswap V3 since it's been better tested in the field than any other AMM.

Thus our users earn swap fees in the exact same way. Liquidity is stored in a tick table which swaps traverse and deposit fees into. Users withdrawing liquidity collect those fees on a pro-rata basis. And just like all market making, users are exposed to the same IL risks.

However, deposited liquidity is also stored in The Liquidity Tree which uses a proprietary algorithm to trade liquidity availability in all ticks in logarithmic time. This lets us deposit fees to ticks that aren't currently active in a gas-efficient way on-chain. This is what enables our Time Premium, an extra reward for liquidity providers when liquidity in their ticks are borrowed by Takers.

Liquidity Taking a.k.a Takers

The key concept of Liquidity Taking is that it reserves liquidity away from the public swapping functionality of the AMM to be swapped against privately. So Liquidity Taking also chooses a price range[Pa,Pb)[P_a, P_b) and a liquidity amount to reserve. Because it gets the privilege of swapping privately (essentially guaranteeing an average execution price), it pays both the swap fees and the borrow cost of those underlying tokens.

But Takers don't get everything for free. If the public price swaps back and forth multiple times in the same price range as the Taker, the private liquidity is also swapped back and forth multiple times. This guarantees that the Taker ends up paying the same swap fees as it would have on the public pool, if no one could front-run them. However, if they tried to swap back and forth on the public pool and save themselves the borrow cost, they would get much worse execution.

Under the hood, when a taker is opened that amount of liquidity is removed from the liquidity table swaps use, and the Liquidity Tree tracks the amount of taken liquidity so as to not exceed the amount of available making liquidity.

The Taker position itself is long one token and short the borrowed Maker position. This is where the profitability and leverage comes from. It borrows the making liquidity from a range, sells it in return for either token in the token pair of this AMM. So it ends up holding a large amount of one token, while owing a dynamically changing balance of both tokens.

Afterwards, the held tokens are deposited into a money market to earn some fees which helps offset the cost of the Taker. When a Taker is ready to be closed, the tokens are withdrawn, the amount is swapped back into the borrowed Maker balances, the Maker is repaid including fees, and the excess value is collected by the user as profit.

Trading Fees

Our trading fees are constructed identically to Uniswap. We felt no need to change anything except for the fee rate which is dynamic. That dynamic fee is simply determined on a hyperbolic curve according to the percent of liquidity reserved at the given tick.

Otherwise, everything is the same as Uniswap. Swap fees are collected on swaps by the currently active tick in a running tally and two global variables track the total fees of the outside ranges. By using the table of ticks and their running tallies along with the two globals, we can compute the fees earned per unit of liquidity in any range.

These fees are then given pro-rata to Maker positions.

Time Premiums

Time premiums are what Makers (liquidity providers) earn from having their liquidity borrowed. Liquidity positions are not matched one-to-one with Takers who want to borrow liquidity. This is not peer-to-peer lending, but rather peer-to-pool and all positions in a given tick split the lending yield pro-rata. For example, if 50% of a range's liquidity is borrowed, and the current borrow rate is 5%, then all liquidity in that range earns 2.5%.

Ideally, we split the fees pro-rata perfectly. In reality though, due to gas constraints we use a proprietary approximation. The most important part of this algorithm is that new deposits can't earn fees accrued from before they opened their position. This ensures that bad actors can't exploit the time premium.

A Taker has its borrowed Maker balances frozen and they begin to pay a money market's borrow rate on them. These Taker borrowed balances are pooled together for efficiency and every time an action is taken on the 2sAMM smart contract we update the borrow rate and charge fees to the Taker.

When anyone interacts with the Liquidity Tree, they walk down the tree and distribute those fees to the nodes it passes in such a way that in the limit the fees are distributed fairly. Our Liquidity Tree enables a much better user experience than competitors which is why we'll be keeping most of the details undisclosed for now.

Last updated