// need to get all the pool addresses // for each pool address, I need to know what protocol // call the contract to populate the pools with the addresses uniswap v3 - at contract level, no differnece in quantity of tokens held in v2 vs v3 pool - complication is at the bookeeeping level - separate and distinct chunks of virtual liquidity exists as artifical construct wihtin larger token pool of real liquidity - price ranges are called tick, tick is bookeeping measure that sllows pool to keep track of how muhc liqudiity has been assigned btween two price points - width of ticks set by pool fee - tick range determined price range of particular chunk of liquidity - variable fee pools, 0.05, 0.3. 1 - tick width is a function of the fee - 0.05 fee -> tick spacing = 10. 0.1 % price difference between ticks - 0.3 fee -> tick spacing = 60. 0.3 % price difference between ticks - 1 fee -> tick spacing = 200. 2 % price difference between ticks - have current tick where next swap will being - trade may make it stay inside tick or it may cross tick boundaries - pool swap is like the following 1) swap input proposed via router/quoter contract 2) router/quoter determines available liquidity, sqrt of current price, current tick of pool 3) router ebgins exchangin input token for output token inside currnet tick, changes sqrt price, but does not chagen liquidity 4) if price change exceeds upper/load boundary, all liquidity in that tick is converted to the input token adn all abailabe output token in that tick is reveresed for th swapper user (all of token0 can be excahngef for token1 insdie a tick) 5) if tick boundary crossed, router determines availbe liqudiity insdie next active tick and repeats process until all of swap input has ben used - v3 pool collects and tracks fees, but not reinvested into pool as additional liquidity, help until lp removes changes position - liquidity values do not change until tick is crossed or lp creates new deposite, sqrt price value only changes after swap L = sqrt(xy) -> liquidty as a function of virtual reserves at the current tick L = delta y / sqrt delta p -> liquidity as a function of change of token1 reserves veeruss change in sqrt price - price and tick have a relationship p(i) = 1.0001 ** i -> price p as a function of tick index i sqrt(p(i)) = 1.0001**(i/2) knowing tick allows us to identify current sqrt price, tickers are centered on zero, can look up info using ticks() truct Info { uint128 liquidityGross; // total position liqudity from deposits that use this tick as a lower or upper bound int128 liquidityNet; // when tick grossed going to right, values for liuqidtNet are added to liquidity at the starting tick uint256 feeGrowthOutside0X128; uint256 feeGrowthOutside1X128; int56 tickCumulativeOutside; uint160 secondsPerLiquidityOutsideX128; uint32 secondsOutside; bool initialized; } ticks chang econtinously with price and can be set to any integer number within allowed range tick indicies are only provided at every integer multiple of tick spacing if swap were executed that moved current price to next adjacent tick, new liuqiidty should equal current_liuqidity + liquidity_net = L_next_tick Positive liquidityNet, increase in tick/price: liquidity increases Positive liquidityNet, decrease in tick/price: liquidity decreases Negative liquidityNet, increase in tick/price: liquidity decreases Negative liquidityNet, decrease in tick/price: liquidity increases uniswapv2 function fee() slot0() sqrtPriceX96: The current price of the pool as a sqrt(token1/token0) Q64.96 value tick: The current tick of the pool observationIndex: The index of the last oracle observation that was written observationCardinality: The current maximum number of observations stored in the pool observationCardinalityNext: The next maximum number of observations, to be updated when the observation feeProtocol: The protocol fee for both tokens of the pool, encoded as two 4 bit values unlocked: Whether the pool is currently locked to re-entrancy So Q64.96 means that our number has 64 bits for the integer, and 96 bits for the fraction. The variable is dened in the struct as a uint160 (a 160 bit unsigned integer), so we know this will t. sqrtPrivceX96 = sqrt(price) * 2 ** 96 sqrt(price) = sqrtPriceX96 * 2 ** -96 (2**-96 is the same as 1/2**96) price = (sqrtPriceX96 * 2 ** -96) ** 2 (sqrt same as raising to the power of 2) // lower tick = tickSpacing * (current_tick // tickSpacing) // upper = tickSpacing * ((current_tick + 1) // tickSpacing + 1) // tick = log(base = sqrtrt(1.0001) sqrt(price)) - pool contract state uint128 liquidity uint160 sqrtPriceX96 int 24 tick uint256 freeGrowthGlobal0x128 uint256 freeGrowthGlobal1x128 uint128 protoolFees.token0 uint128 protoolFees.token1 this is how ammrs does it pub struct UniswapV3Pool { pub address: Address, pub token_a: Address, pub token_a_decimals: u8, pub token_b: Address, pub token_b_decimals: u8, pub liquidity: u128, pub sqrt_price: U256, pub fee: u32, pub tick: i32, pub tick_spacing: i32, pub tick_bitmap: HashMap, pub ticks: HashMap, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Info { pub liquidity_gross: u128, pub liquidity_net: i128, pub initialized: bool, } j // lower tick = tickSpacing * (current_tick // tickSpacing) // upper = tickSpacing * ((current_tick + 1) // tickSpacing + 1) // tick = log(base = sqrtrt(1.0001) sqrt(price)) - Router function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut) function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut) function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn) function exactOutput(ExactOutputParams calldataparams) externalpayablereturns (uint256amountIn - just does swaps struct ExactInputSingleParams { https://www.degencode.com/p/uniswapv3-router-contract?utm_source=profile&utm_medium=reader2 1/11 7/9/24, 6:32 PM UniswapV3 — Router Contract - by BowTiedDevil - Degen Code address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } - listen for swpa evenets for latest sqrtPriceX96, liqudity, and tick - have to encode the path using encode_packed() - address, fee, address, fee, address Quoter contract - give accurate quotes for exact input and output swaps - nearest thing to getAmountsOut is here - function quoteExactInput( bytes memory path, uint256 amountIn ) external returns ( uint256 amountOut ) function quoteExactInputSingle( address tokenIn, address tokenOut, uint24 fee, uint256 amountIn, uint160 sqrtPriceLimitX96 ) external returns ( uint256amountOut ) function quoteExactOutput( bytes memory path, uint256 amountOut ) external returns ( uint256 amountIn ) function quoteExactOutputSingle( address tokenIn, address tokenOut, uint24 fee, uint256 amountOut, uint160 sqrtPriceLimitX96 ) external returns ( uint256amountIn ) - always use call for quoter functions - there is also a quoter v2 contract function quoteExactInput( bytes path, uint256 amountIn https://www.degencode.com/p/uniswapv3-quoter-contract?utm_source=profile&utm_medium=reader2 7/13 7/9/24, 6:32 PM UniswapV3 — Quoter Contract - by BowTiedDevil - Degen Code ) external returns ( uint256 amountOut, uint160[] sqrtPriceX96AfterList, uint32[] initializedTicksCrossedList, uint256 gasEstimate ) function quoteExactInputSingle( struct IQuoterV2.QuoteExactInputSingleParams params ) external returns ( uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate ) function quoteExactOutput( bytes path, uint256 amountOut ) external returns ( uint256 amountIn, uint160[] sqrtPriceX96AfterList, uint32[] initializedTicksCrossedList, uint256 gasEstimate ) function quoteExactOutputSingle( struct IQuoterV2.QuoteExactOutputSingleParams params ) external returns ( uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate ) struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; uint24 fee; uint160 sqrtPriceLimitX96; } struct QuoteExactOutputSingleParams { address tokenIn; address tokenOut; uint256 amount; uint24 fee; uint160 sqrtPriceLimitX96; } A pool contract is divided into ticks, which represent edge boundaries — token price intervals where virtual liquidity can be provided A tick is related mathematically to sqrtPriceX96 A tick occurs at regular intervals called tickSpacing A tick may be initialized or uninitialized Swaps may cross tick boundaries depending on their input size Liquidity and price information may be retrieved for a single tick from the pool, which stores values inside a mapping called ticks ticklens contract - tickBitmap: record of all initalized ticks - can retrieve initalized status for 256 ticks at a time indx = 2 * tickspacing index = tick / tickspacing / 256 ticklens has getPopulatedTicksInWord(address, index) // will return to you all of the populated ticks struct PopulatedTick { int24 tick; int128 liquidityNet; uint128 liquidityGross; } - can use ticklens to retrieve liquidity info very quickly for initlaized tick indicies inside a particual getPopulatedTicksInWord - still need to determine the number of words int24 internal constant MIN_TICK = -887272; int24 internal constant MAX_TICK = -MIN_TICK; num words = 2 * 997272/256/tickspacing "If you are observing a UniswapV3 swap in the mempool, for example, you can retrieve the nearest handful of words in the direction of your swap via multicall on-demand and have access to everything you need.: