Math 1-pager
A practical guide to Ekubo's internal math
Last updated
Was this helpful?
A practical guide to Ekubo's internal math
Last updated
Was this helpful?
Ekubo represents the current state of each pool with two values: sqrt_ratio
and liquidity
. The sqrt_ratio
is the square root of the current price in terms of token1 / token0
, and the liquidity
is a measure of how much of the two tokens is available for trading at the current price.
Ekubo supports pair prices between 2**-128
and 2**128
, which means the square root of the price can be anywhere between 2**-64
and 2**64
. We use a fixed point number type for storing the price with 128 bits after the radix. For example, sqrt_ratio
for the price 1
is represented as 1<<128
.
The value sqrt_ratio
is defined as sqrt(y/x)
and liquidity
is defined as sqrt(x*y)
. This is a different method of tracking x
and y
in x * y = k
that is much easier to think about when we introduce the concept of concentrated liquidity: the act of swapping only changes the price, and adding and removing x
and y
only updates the liquidity. With these two values defined as such, all other formulae can be derived from it (e.g.: the amount of x
in the pool, the differences in x
/y
between prices, etc.)
Ekubo does not consider token decimals in any of its calculations. If token0
and token1
have different decimals, that just means the price of 1
is actually 10**token1_decimals / 10**token0_decimals.
Given sqrt_ratio and liquidity, we can compute the equivalent amount of x
and y
reserves.
A constant-liquidity AMM such as Uniswap V2 can be trivially implemented using these representations instead of x
and y
, and Ekubo with full range liquidity is a more efficient version of the usual AMM implementation that tracks x
and y
without support for concentrated liquidity.
When the price moves due to swapping, positions are entered and exited, and Ekubo adjusts the liquidity mid-trade. Thus, trades must be executed iteratively: a user's swap is broken up into pieces trading through areas of the curve with constant liquidity, a la constant-liquidity AMMs. Each time we cross a position boundary, we update the current liquidity. How do we define position boundaries? That's where ticks come in.
Ticks divide the entire price range into discrete regions. They can be defined however an AMM designer wishes, but in Ekubo prices are divided up logarithmically so that each tick is equidistant from one another. The base of the log for Ekubo's ticks (i.e. tick size) is set to 1.000001
. You can compute the sqrt_ratio
corresponding to ticks using decimal math libraries, for example in TypeScript:
The inverse can be computed (tick
from sqrt_ratio
), by doing taking the logarithm of sqrt_ratio
in base 1.000001
. To get the exact fixed point 64.128 number used by Ekubo to represent a tick's price, you can use one of our open source SDKs (TypeScript, Rust).
Once you've broken up the price range into pieces, positions are just a combination of an amount of liquidity and lower/upper tick boundaries. Users update positions by updating the liquidity that goes in/out of range at these prices, and swappers move the price across position boundaries.