Introduction

https://github.com/Jeiwan/uniswapv3-code/blob/main/unimath.py

Calculating liquidity

Now, we can find corresponding ticks. We know that prices and ticks are connected via this formula:

$$ \sqrt{P(i)} = 1.0001^{\frac{i}{2}} $$

Thus, we can find tick i via:

$$ i = \log_{ \sqrt{1.0001}}\sqrt{P(i)} $$

Q64.96 Number

Q (number format)

Last thing to note here is that Uniswap uses Q64.96 number to store √P. This is a fixed-point number that has 64 bits for the integer part and 96 bits for the fractional part.

In our above calculations, prices are floating point numbers: 70.71, 67.42, and 74.16.

We need to convert them to Q64.96. Luckily, this is simple: we need to multiply the numbers by 2^96 (Q-number is a binary fixed-point number, so we need to multiply our decimals numbers by the base of Q64.96, which is 2^96).

Math operations

Q numbers are a ratio of two integers: the numerator is kept in storage, the denominator 𝑑 is equal to 2^n.

Consider the following example:

  • The Q8 denominator equals 2^8 = 256
  • 1.5 equals 384/256
  • 384 is stored, 256 is inferred because it is a Q8 number.

Example

$$ float : 12.625 \\ binary \ representation : 1100.101 \\ integer \ part : 1*2^3(=8)+1*2^2(=4)+0*2^1(=2)+0*2^0(=1) = 12 \\ decimal \ part : 1*2^{-1}0.5)+0*2^{-2}(=0.25)+1*2^{-3}(=0.125) = 0.625 $$$$ Q64.96 format \\ we \ store \ only \ the \ numerator \\ Multpliying \ by \ 2^{96} \ allows \ to \ shifts \ our \ binary \ representation \\ 96 \ bits \ to \ the \ left \ -> \ keep \ 96 \ bits \ for \ decimals \\ 12.65 = \frac{numerator}{2^{96}} \ (Q64.96 \ format) \\ numerator = 1000255551742587262118492372992 \\ binary \ representation : 1100101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \\ binary \ representation \ (with \ decimal \ point) : \\ 1100.101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \\ we \ can \ see \ that \ we \ have \ 96 \ bits \ of \ decimals $$$$ Reminder \\ number = 9 \\ binary = 1001 \\ Shift \ by \ 2 : 1001 << 2 = 100100 = 36 \\ Multply \ by \ 4 : 9*4 = 36 \\ Shift \ by \ n \ bits \Longleftrightarrow multiply \ by \ 2^n $$$$ number : 10.53646097288583405316 \\ binary : 1010.10001001010101011000000110011110001 \ (35 \ bits \ for \ decimals) \\ Can't \ store \ in \ EVM \\ So \ we \ shift \ 96 \ bits \ to \ store \ it \ properly \\ number * 2^{96} = 834784442285002590670139949056 \\ binary : 1010100010010101010110000001100111100010000000000000000000000000000000000000000000000000000000000000 \\ The \ decimal \ binary \ point \ disappear \\ 61 \ of \ 0 \ bits \ added\ (already \ 35 \ bits \ were \ used \ for \ decimal \ part) $$

Liquidity Amount Calculation

To calculate L for a price range, let’s look at one interesting fact we have discussed earlier: price ranges can be depleted. It’s possible to buy the entire amount of one token from a price range and leave the pool with only the other token.

At the points a and b, there’s only one token in the range: ETH at the point a and USDC at the point b. That being said, we want to find an L that will allow the price to move to either of the points. We want enough liquidity for the price to reach either of the boundaries of a price range. Thus, we want L to be calculated based on the maximum amounts of Δx and Δy.

Now, break the curve from the image above into two segments: one to the left of the start point and one to the right of the start point. We’re going to calculate two L’s, one for each of the segments. Why? Because each of the two tokens of a pool contributes to either of the segments: the left segment is made entirely of token x, and the right segment is made entirely of token y. This comes from the fact that, during swapping, the price moves in either direction: it’s either growing or falling. For the price to move, only either of the tokens is needed.

Thus, the liquidity in the segment of the curve to the left of the current price consists only of token x and is calculated only from the amount of token x provided. Similarly, the liquidity in the segment of the curve to the right of the current price consists only of token y and is calculated only from the amount of token y provided.

First Swap

Calculating Swap Amounts

In Uniswap V3, we choose the price we want our trade to lead to (recall that swapping changes the current price, i.e. it moves the current price along the curve). Knowing the target price, the contract will calculate the amount of input token it needs to take from us and the respective amount of output token it’ll give us.

$$ \Delta \frac{1}{\sqrt{P}} =\frac{1}{\sqrt{P_{target}}}-\frac{1}{\sqrt{P_{current}}} \\ Don't \ forget \ that \ we \ need \ to \ put \ Q64.96 \ in \ good \ format \\ \Delta \frac{1}{\sqrt{P}} =\frac{1}{\frac{\sqrt{P_{target}}}{2^{96}}}-\frac{1}{\frac{\sqrt{P_{current}}}{2^{96}}} \\ \Delta \frac{1}{\sqrt{P}} =(\frac{1}{\sqrt{P_{target}}}-\frac{1}{\sqrt{P_{current}}}) * 2^{96} $$

Manager Contract

Deployment

User Interface

Not done → not interesting for me

Code

Check repo