State variables
Last modified:
To keep notation consistent with the previous sections, we continue to denote the two pool assets by and , even though smart-contract implementations often refer to them as token0 and token1.
We will be interested in the variables listed in the table below. The entries marked by are tick-indexed variables; that is, a separate value is stored for each initialized tick.
Table. State variables used by the CenturionDEX v3 pool contract
| Variable | Notation | Type |
|---|---|---|
| Current tick index | ||
| Current square-root price | ||
| Total active liquidity | ||
| Net liquidity at tick | ||
| Gross liquidity at tick | ||
| Global fee growth in tokens and | ||
| Fee growth outside tick in tokens and |
Current tick index
The current tick index is the integer tick index associated with the current market price. Since the price grid is defined by
the current tick index is given by
Thus, identifies the greatest tick whose associated price does not exceed the current price .
Square root of the current price and total active liquidity
Rather than tracking the real reserves of the pool directly, the CenturionDEX v3 contract tracks the current square-root price together with the total active liquidity . This is sufficient because the corresponding virtual reserves satisfy
Hence, the pair completely determines the virtual state of the active portion of the pool. Once these two quantities are known, the swap equations and the local trading geometry are fully determined.
Net liquidity
For each initialized tick index , the net-liquidity variable measures the jump in active liquidity when the price crosses that tick from left to right, that is, from lower prices to higher prices. Accordingly:
- if the price crosses tick from left to right, then
- if the price crosses tick from right to left, then
To illustrate this rule, consider three positions:
where are initialized ticks. Moving from low prices to high prices, we obtain
Thus, the active liquidity increases when a position begins, decreases when a position ends, and changes by the algebraic sum of those effects when multiple positions begin or end at the same tick.
Gross liquidity
For each initialized tick , the gross-liquidity variable is defined as the sum of the liquidity parameters of all positions that reference tick as one of their two boundaries.
This variable serves a different purpose from net liquidity. Net liquidity tells the contract how the total active liquidity changes when the price crosses a tick. Gross liquidity, by contrast, tells the contract whether the tick is still needed at all. If the last position that references a tick is removed, then becomes zero, and the tick may be uninitialized.
It is crucial to note that gross liquidity cannot be reconstructed from net liquidity alone. A tick may have zero net liquidity and nevertheless still be referenced by one or more positions.
Example (Net and gross liquidity)
Consider a CenturionDEX v3 pool with four positions:
where
These are the only initialized ticks in the pool.
Moving from lower prices to higher prices, the net-liquidity updates are obtained as follows:
- at , position becomes active, so ;
- at , position ends and position begins, so
- at , position begins, so
- at , position ends, so
- at , position ends and position begins, so
- at , position ends, so
The corresponding gross-liquidity values are determined by summing the liquidity parameters of all positions that reference each tick:
- , since only references ;
- , since and both reference ;
- , since only references ;
- , since only references ;
- , since and both reference ;
- , since only references .
These values are summarized below:
| Initialized tick | ||||||
|---|---|---|---|---|---|---|
| Net liquidity | ||||||
| Gross liquidity |
In particular, notice that
This shows that zero net liquidity at a tick does not imply that the tick can be discarded. The tick is still referenced by two active position boundaries and must therefore remain initialized.
Global fee growth
Because trading fees are stored outside the active liquidity rather than reinvested into it, the protocol must keep separate track of the total fees collected in each token. It does so through the global fee-growth variables
These quantities measure cumulative fees per unit of liquidity in tokens and , respectively. Storing fee growth on a per-unit-liquidity basis is essential: if the contract stored only absolute fee totals, then any change in active liquidity would make it difficult to determine how much of the accumulated fees belongs to a given position.
Fee growth outside a tick
Let be an initialized tick index, and let
be the corresponding tick price. The tick partitions the positive price axis into the two intervals
Given the current price , we define the outer interval associated with tick to be the one of these two intervals that does not contain . Equivalently:
- if , then the current price is at or above the tick, so the outer interval is
- if , then the current price is below the tick, so the outer interval is
For each initialized tick , the protocol stores
which represent the cumulative fee growth per unit liquidity in the outer interval associated with tick , in tokens and , respectively.
For example, consider the tick from the earlier section whose index is
so that
If the current price is , then , and the outer interval is
If instead the current price is , then , and the outer interval is
Whenever the price crosses an initialized tick , the outer interval switches from one side of the tick to the other. Consequently, the contract updates the stored outside-fee variables by the rule
This works because the total fee growth is the sum of the fee growth on the two sides of the tick.
When a tick is initialized for the first time, its outside-fee variables are assigned the values
This initialization convention should not be interpreted as a literal decomposition of previously accumulated fees. Rather, and are auxiliary bookkeeping variables whose purpose is to ensure that the future fee share of each position can be computed correctly.