Tick and Ranges

Arbidex's Quantum enables liquidity providers to supply liquidity within specific price ranges, or "ticks," resulting in more efficient use of their funds by concentrating liquidity around the current price. The system manages liquidity using various parameters and calculations to ensure providers earn their proportional share of fees while their liquidity is active within the chosen price range. This allows for precise and flexible liquidity provision, but also requires careful management of gas costs associated with swaps.

To enable custom liquidity provision, the range of potential prices is divided into discrete ticks. Liquidity providers can supply liquidity between any two ticks, which need not be adjacent. Each range can be defined as a pair of signed integer tick indices: a lower tick (𝑖𝑙) and an upper tick (𝑖𝑒). Ticks represent prices where the contract's virtual liquidity can change. Prices are always expressed as the price of one tokenβ€”token0β€”in terms of the other tokenβ€”token1. The assignment of tokens to token0 and token1 is arbitrary and only affects the contract's logic through possible rounding errors.

Conceptually, there is a tick at every price 𝑝 that is an integer power of 1.0001. Identifying ticks by an integer index 𝑖, the price at each tick is given by:

𝑝(𝑖)=1.0001𝑖.𝑝(𝑖) = 1.0001^𝑖.

This results in each tick being a .01% (1 basis point) price movement away from its neighboring ticks. However, due to technical reasons explained in 6.2.1, pools actually track ticks at every square root price that is an integer power of √1.0001. Consider the transformed equation in square root price space:

βˆšπ‘(𝑖)=1.0001(𝑖/2)βˆšπ‘(𝑖) = 1.0001^(𝑖/2)

For example, βˆšπ‘(0)β€”the square root price at tick 0β€”is 1, βˆšπ‘(1) is √1.0001 β‰ˆ 1.00005, and βˆšπ‘(βˆ’1) is 1/√1.0001 β‰ˆ 0.99995.

When liquidity is added to a range, if one or both ticks are not already used as bounds in an existing position, that tick is initialized. Not every tick can be initialized. The pool is instantiated with a parameter, tickSpacing (𝑑𝑠); only ticks with indexes divisible by tickSpacing can be initialized. For instance, if tickSpacing is 2, only even ticks (...-4, -2, 0, 2, 4...) can be initialized. Smaller tickSpacingchoices allow for tighter and more precise ranges but may increase the gas cost for swaps, as each initialized tick crossed by a swap imposes a gas cost on the swapper.

When the price crosses an initialized tick, virtual liquidity is either added or removed. The gas cost of crossing an initialized tick is constant and does not depend on the number of positions being added or removed at that tick. To ensure the correct amount of liquidity is added or removed from the pool when ticks are crossed and that each position earns its proportional share of fees accrued while within range, some accounting is required within the pool. The pool contract uses storage variables to track state at a global (per-pool) level, a per-tick level, and a per-position level.

Last updated