Deploying idle collateral to stable-stable pairs on Uni v3 with FRAX

The key innovation of Uniswap v3's AMM algorithm allowing for LPs to deploy liquidity between specific price ranges allows for stablecoin-to-stablecoin pairs (e.g. FRAX-USDC) to accrue extremely deep liquidity within a tight peg. Compared to Uniswap v2, range orders in Uniswap v3 concentrate the liquidity instead of spreading out over an infinite price range.

The Uniswap v3 Liquidity AMO puts FRAX and collateral to work by providing liquidity to other stablecoins against FRAX. Since the AMO is able enter any position on Uni v3 and mint FRAX against it, it allows for expansion to any other stablecoin and later volatile collateral on Uni v3. Additionally, the function `collectFees()`

can be periodically called to allocate AMO profits to market operations of excess collateral.

Decollateralize - Deposits idle collateral and newly minted FRAX into the a Uni v3 pair.

Market operations - Accrues Uni v3 transaction fees and swaps between collateral types.

Recollateralize - Withdraws from the Uni v3 pairs, burns FRAX and returns USDC to increase CR.

FXS1559 - Daily transaction fees accrued over the CR.

All prices exist as ratios between one entity and another. Conventially, we select a currency as the shared unit-of-account in the denominator (e.g. USD) to compare prices for everyday goods and services. In Uniswap, prices are defined by the ratio of the amounts of reserves of $x$ to reserves of $y$ in the pool.

Uniswap v3's range-order mechanic fits into the existing $x*y = k$ constant-product market-making invariant (CPMM) by "virtualizing" the reserves at a specific price point, or `tick`

. Through specifying which ticks a liquidity position is bounded by, range-orders are created that follow the constant-product invariant without having to spread the liquidity across the entire range$(0, \infty)$for a specific asset.

A price in Uniswap v3 is defined by the value `1.0001`

to the tick value $i$. The boundaries for the prices of ticks can be represented by the algebraic group $G = \{ g^i \mid i \in \mathbb{Z}, g = 1.0001\}$. This mechanism allows for easy conversion of integers to price boundaries, and has the convenience of discretiating each tick-price-boundary as one basis point (`0.01%`

) in price from another.

Virtual reserves are tracked by tracking the `liquidity`

and `tick`

bounds of each position. Crossing a tick boundary, the liquidity $L$ available for that tick may change to reflect positions entering and leaving their respective price ranges. Within the tick boundaries, swaps change the price $\sqrt{P}$ according to the virtual reserves, i.e. it acts like the constant-product ($x*y=k$) invariant. The virtual reserves `x`

and `y`

can be calculated from the liquidity and price:

Note that the actual implementation uses a square root of the price, since it saves a square-root operation from calculating intra-tick swaps, and thus helps prevent rounding errors.

Liquidity can be thought of as a virtual $k$ in the $x*y=k$ CPMM, while $\Delta Y$ corresponds to amount of asset $Y$ and $\Delta\sqrt P$ represents the intra-tick price slippage.

Since $L$ is fixed for intra-tick swaps, $\Delta X$ and $\Delta Y$ can be calculated from the liquidity and square root of the price. When crossing over a tick, the swap must only slip until the $\sqrt P$ boundary, and then re-adjust the liquidity available for the next tick.

The Uniswap v3 Liquidity AMO (stable-stable) contract is deployed at: `0x3814307b86b54b1d8e7B2Ac34662De9125F8f4E6`