UniswapV3 — TickLens Contract
That Tick Thicc
Before we explore TickLens, let us review the basics covered in the Pool contract lesson:
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
A tick occurs at regular intervals called
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 are very useful markers, but it is impossible to know anything about the initialization of a particular pool’s ticks without querying multiple possible values. This can be done with an expensive multicall lookup, by reading the pool’s
tickBitmap, or by using the TickLens accessory contract. The multicall is impractical and wasteful so we will skip it, but will review how to retrieve and decode the
tickBitmap before moving to querying the tickLens.
Each pool holds a record of all initialized ticks into a special mapping named
tickBitmap, which is described in the documentation as:
… a packed mapping of tick index to its initialized state.
The mapping uses int16 for keys since ticks are represented as int24 and there are 256 (2^8) values per word.
The UniswapV3Pool.sol source defines:
using TickBitmap for mapping(int16 => uint256);
Which means simply that any reference to
TickBitmap instructs Solidity to reference the mapping of int16 values to uint256 values.
But What is a Bitmap?
A bitmap is an efficient data structure that uses binary numbers to represent status. Recall that
TickBitmap is a mapping of
int16 numbers to
uint256 numbers. The
int16 number is the index, and it maps to
uint256 number has a maximum value of 2**256-1. The decimal value of this number is 115792089237316195423570985008687907853269984665640564039457584007913129639935
What about that same number in binary?
>>> bin(2**256-1) '0b1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'
And how long is that string of digits?
>>> len(bin(2**256-1)[2:]) 256
NOTE: the slice
[2:] removes the
'0b' prefix, which functions like the
'0x' prefix for hexadecimal numbers.
A 256 bit number has a string length of 256, and the maximum value of that
uint256 number has all of the bit positions set to 1.
If we use this 256-bit number to indicate status and position, it becomes a bitmap. Imagine that I wanted to keep track of the 0 or 1 status of 256 items that were always in the same order.
I could just work from the 1st value to the 256th value, set the 0 or 1 appropriately, and then store that single binary number.