Uniswap V3 initializing pools, adding liquidity and tools for calculations - Swiss knife post

Warning, this post is only useful if you tried out adding liquidity both with UI and with code, read about V3 most of the info, and want to have more clearer idea of what is what.

There are lots of books and posts about how to use Uniswap V3 and I will reference the best at the end of the article, yet some info and code on how to set proper values I didn’t find and had to dig out in various places. So let’s begin with some short snippets on how to get ticks and SqrtPriceX96 values depending on what you want to set and your liquidity plans. I could recode this in some solidity but actually, I use this with chatGPT and Python just to get quick results

### Price to tick formula

import math

def price_to_tick(p):
return math.floor(math.log(p, 1.0001))

price_to_tick(1000000)


### Price to sqrtp

q96 = 2**96def price_to_sqrtp(p):
return int(math.sqrt(p) * q96)

price_to_sqrtp(5000)


### From sqrtp to price

def sqrtp_to_price(sqrtp):
return (sqrtp / q96) ** 2


### Sqrtp to tick

q96 = 2**96

def sqrtp_to_tick(sqrtp):
return math.floor(2 * math.log(sqrtp / q96, 1.0001))


So with some practical examples Price = y/x  or token1/token0 so if we want to add 1 eth and 1 000 000 of meme token then it is 1/1000000 or  0.00000001 and if we want to find a tick value for that price we need to put that into the formula above which will become −138,164  and if we convert that to sqrtp value it will be 79224253767016489810214999 when we put it into formula. This 1 / 1000 000 will also give us starting liquidity values, so we put 1 eth and 1 million meme tokens with that starting price, we want to put 2 eth, then calculate 2 / 1000000 and this value will be used in the createAndInitializePoolIfNecessary of NonfungiblePositionManager contract

     pool = nfpm.createAndInitializePoolIfNecessary(
token0,
token1,
fee,
sqrtPriceX96
);


also, we can just use this solidity function to calculate sqrtPriceX96 from amounts of tokens we want to add

function calculateSqrtPriceX96(uint256 tokenAmount, uint256 wethAmount )


Code for that you can find here

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library SqrtPricex96 {
uint256 constant Q96 = 2 ** 96;

function calculateSqrtPriceX96(
uint256 tokenAmount,
uint256 wethAmount
) internal pure returns (uint160 sqrtPriceX96) {
// Ensure non-zero values to prevent division by zero
require(
tokenAmount > 0 && wethAmount > 0,
"Amounts must be greater than zero"
);

// First, multiply wethAmount by Q96^2 to scale it up before division
// Then, divide by tokenAmount and finally calculate the square root
// The multiplication by Q96^2 is done first to avoid loss of precision before the division
uint256 scaledWethAmount = wethAmount * Q96 ** 2;
uint256 priceRatio = scaledWethAmount / tokenAmount;

// Now compute the square root
sqrtPriceX96 = uint160(sqrt(priceRatio));
}

// Basic integer square root function
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
} else {
z = 0;
}
return z;
}

// This function is to illustrate how you would reverse the calculation to find the price
function calculatePriceFromSqrtPriceX96(
uint256 sqrtPriceX96
) internal pure returns (uint256 price) {
uint256 squaredPrice = uint256(sqrtPriceX96) ** 2;
uint256 scaledPrice = squaredPrice / Q96 ** 2;

price = uint160(scaledPrice);
}
}


After that when doing the minting of V3 NFT and adding first liquidity w

nfpm.mint(INonfungiblePositionManager.MintParams({....


we will probably use this parameter to get the full range of ticks and depending on the fee pool type we choose to set these settings

int24 MIN_TICK = -887272;
int24 MAX_TICK = 887272;
uint24 fee = 3000;
int24 TICK_SPACING = 60;
int24 minTick = (MIN_TICK / TICK_SPACING) * TICK_SPACING;
int24 maxTick = (MAX_TICK / TICK_SPACING) * TICK_SPACING;


tick spacing and fees are correlated with this table

### Some other useful info

Uniswap pool will be created with multicall if you use their UI, to read that multicall use this
The first line is the init function
The third line is returning of extra eth