CenturionDEX

Ticks

Last modified:

Ticks

In CenturionDEX v3, a liquidity position is defined over a bounded price interval. The endpoints of that interval are not arbitrary real numbers; they must coincide with protocol ticks. Ticks are indexed by integers iZi \in \mathbb{Z}, and the price associated with tick ii is

p(i)=1.0001i.p(i)=1.0001^i.

We refer to ii as the tick index of the price level p(i)p(i). Since adjacent ticks differ by 0.01%0.01\%, the grid of admissible prices is extremely fine and, in practice, covers a very broad range of relevant market prices.

For the concentrated-liquidity model, it is convenient to use canonical notation. Let xx and yy denote the virtual reserves of tokens XX and YY, let LL denote the liquidity parameter, and let pp denote the spot price of token XX in units of token YY. These quantities satisfy

xy=L2,p=yx.x \cdot y = L^2, \qquad p=\frac{y}{x}.

Therefore, the virtual reserves can be written as

x=Lp,y=Lp.x=\frac{L}{\sqrt{p}}, \qquad y=L\sqrt{p}.

Hence, the pair (L,p)(L,\sqrt{p}) completely determines the virtual state of the position.

Since

p(i)=1.0001i/2,\sqrt{p(i)}=1.0001^{i/2},

the tick index associated with a price p>0p>0 is the largest integer ii such that p(i)pp(i)\le p. Equivalently,

i(p)=log1.0001(p)=2log1.0001(p).i(p)=\left\lfloor \log_{1.0001}(p)\right\rfloor = \left\lfloor 2\log_{1.0001}(\sqrt{p})\right\rfloor.

Here, \lfloor \cdot \rfloor denotes the floor function.

Example

Consider a CenturionDEX v3 pool between CTN and USDC. Suppose that its current virtual balances are

x=24(CTN),y=60,000(USDC).x=24 \quad \text{(CTN)}, \qquad y=60{,}000 \quad \text{(USDC)}.

Then the current spot price is

p0=yx=60,00024=2,500USDC/CTN.p_0=\frac{y}{x}=\frac{60{,}000}{24}=2{,}500 \quad \text{USDC/CTN}.

The corresponding liquidity parameter is

L=xy=2460,000=1,200.L=\sqrt{xy}=\sqrt{24\cdot 60{,}000}=1{,}200.

Using the tick-index formula above, the current price is associated with the tick index

i(p0)=log1.0001(2500)=78,244.i(p_0)=\left\lfloor \log_{1.0001}(2500)\right\rfloor = 78{,}244.

Indeed, the neighboring tick prices are

p(78,244)=1.000178,2442499.906990,p(78{,}244)=1.0001^{78{,}244}\approx 2499.906990,

and

p(78,245)=1.000178,2452500.156980.p(78{,}245)=1.0001^{78{,}245}\approx 2500.156980.

Now suppose that a liquidity provider wants to create a position over the target price interval

[pa,pb]=[2300,3100].[p_a,p_b]=[2300,3100].

To obtain a tick-aligned interval that contains this target range, we choose the lower boundary as the greatest tick price not exceeding 23002300, and the upper boundary as the smallest tick price not below 31003100. Thus,

ia=log1.0001(2300)=77,410,ib=log1.0001(3100)=80,396.i_a=\left\lfloor \log_{1.0001}(2300)\right\rfloor = 77{,}410, \qquad i_b=\left\lceil \log_{1.0001}(3100)\right\rceil = 80{,}396.

The neighboring tick prices around these bounds are

p(77,410)2299.881723,p(77,411)2300.111711,p(77{,}410)\approx 2299.881723, \qquad p(77{,}411)\approx 2300.111711,

and

p(80,395)3099.816056,p(80,396)3100.126037.p(80{,}395)\approx 3099.816056, \qquad p(80{,}396)\approx 3100.126037.

These values are summarized in the following table:

Tick index77,41077,41180,39580,396Tick price (approx.)2299.8822300.1123099.8163100.126\begin{array}{c|cccc} \text{Tick index} & 77{,}410 & 77{,}411 & 80{,}395 & 80{,}396 \\ \hline \text{Tick price (approx.)} & 2299.882 & 2300.112 & 3099.816 & 3100.126 \end{array}

Therefore, a tick-aligned interval that contains the desired range [2300,3100][2300,3100] is

[p(77,410),p(80,396)][2299.882,  3100.126].[p(77{,}410),\,p(80{,}396)] \approx [2299.882,\;3100.126].

Thus, in practice, the liquidity provider would implement the position using these discrete tick bounds rather than the continuous target interval [2300,3100][2300,3100].