CenturionDEX

Fee accounting

Last modified:

CenturionDEX v3 charges a fee on the input token of each trade. The contract may also specify a protocol fee, namely a fixed fraction of the trading fee retained by the protocol rather than distributed to liquidity providers. This parameter is fixed at pool creation.

For clarity, we assume throughout this section that the protocol fee is zero. This assumption does not affect the structure of the accounting rules; it only removes one layer of proportional rescaling from the fee-growth variables.

To determine the fees earned by an individual position, it is useful to decompose cumulative fee growth relative to each boundary tick.

Fee growth above and below a tick

Let ii be an initialized tick index, and let α{X,Y}\alpha\in\{X,Y\}. We define:

[t(i),+);[t(i),+\infty); [0,t(i)).[0,t(i)).

Because foα(i)f_o^\alpha(i) stores the fee growth in the outer interval, the values of faα(i)f_a^\alpha(i) and fbα(i)f_b^\alpha(i) depend on the relative position of the current price with respect to tick ii. Specifically,

faα(i)={fgαfoα(i),ici,foα(i),ic<i,f_a^\alpha(i)= \begin{cases} f_g^\alpha-f_o^\alpha(i), & i_c\ge i,\\[4pt] f_o^\alpha(i), & i_c<i, \end{cases}

and

fbα(i)={foα(i),ici,fgαfoα(i),ic<i.f_b^\alpha(i)= \begin{cases} f_o^\alpha(i), & i_c\ge i,\\[4pt] f_g^\alpha-f_o^\alpha(i), & i_c<i. \end{cases}

These formulas are the basic bridge between global fee accounting and position-level fee accounting.

For a position with lower/upper boundary ticks (ia,ib)(i_a,i_b), the fee growth inside the position range is

finα=fgαfbα(ia)faα(ib),α{X,Y}.f_{\mathrm{in}}^\alpha = f_g^\alpha - f_b^\alpha(i_a) - f_a^\alpha(i_b), \qquad \alpha\in\{X,Y\}.

Example (Evolution of fee-accounting variables)

Consider a CenturionDEX v3 pool with initialized ticks

t1<t2<t3,t_1<t_2<t_3,

and focus on the fee-accounting variables associated with the middle tick t2t_2. We track the global fee-growth variables

fgX,fgYf_g^X,\quad f_g^Y

and the tick-level quantities

foX(i2),foY(i2),faX(i2),fbX(i2),faY(i2),fbY(i2),f_o^X(i_2),\quad f_o^Y(i_2),\quad f_a^X(i_2),\quad f_b^X(i_2),\quad f_a^Y(i_2),\quad f_b^Y(i_2),

where i2i_2 denotes the tick index of t2t_2.

Assume that the pool begins with the current price below t2t_2, and that the following sequence of events occurs:

  1. a trade below t2t_2 generates 1212 units of fee growth in token YY;
  2. the price crosses t2t_2 upward;
  3. a trade above t2t_2 generates 88 units of fee growth in token YY;
  4. another trade above t2t_2 generates 66 units of fee growth in token XX;
  5. the price crosses t2t_2 downward;
  6. a trade below t2t_2 generates 44 units of fee growth in token XX.

The resulting evolution of the variables is shown in the table below.

Table. Example of updates of fgαf_g^\alpha, foα(i2)f_o^\alpha(i_2), faα(i2)f_a^\alpha(i_2), and fbα(i2)f_b^\alpha(i_2) for α{X,Y}\alpha\in\{X,Y\}

StepPrice locationCollected feefgXf_g^XfgYf_g^YfoX(i2)f_o^X(i_2)foY(i2)f_o^Y(i_2)faX(i2)f_a^X(i_2)fbX(i2)f_b^X(i_2)faY(i2)f_a^Y(i_2)fbY(i2)f_b^Y(i_2)
Initial statebelow t2t_2-0000000000000000
Trade 1below t2t_2(12,Y)(12,Y)00121200000000001212
Tick crossabove t2t_2-0012120012120000001212
Trade 2above t2t_2(8,Y)(8,Y)0020200012120000881212
Trade 3above t2t_2(6,X)(6,X)6620200012126600881212
Tick crossbelow t2t_2-66202066886600881212
Trade 4below t2t_2(4,X)(4,X)1010202066886644881212

This table illustrates the logic of the bookkeeping:

These variables are the ingredients from which the fee growth inside a position range is subsequently computed, and therefore they form the core of the position-level fee-accounting mechanism in CenturionDEX v3.