System Parameters
A operational description of Checker’s internal parameters, and operations on them. NOTE: here we focus primarily on the specifics of the calculations; for the meaning of the concepts, see Design.
State
q
: of type (1 / kit).index
: of type tez.protected_index
: of type tez.target
: TODO: said dimensionless, but I think tez/kit? Hmmm. I have to re-check the units of measure.drift_derivative
drift
outstanding_kit
: approximation of the total amount of kit that would be currently required to close all burrows.circulating_kit
: approximation of the total amount of kit that is currently in circulation.last_touched
: the last time the parameters were touched.
And two additional indices, one used in the calculation of burrowing fees and one in the calculation of the imbalance adjustment:
burrow_fee_index
imbalance_index
Initialization
We currently initialize checker with the following parameters:
q = 1
index = 1xtz
protected_index = 1xtz
target = 1
drift = 0
drift_derivative = 0
outstanding_kit = 0kit
circulating_kit = 0kit
last_touched = now
burrow_fee_index = 1
imbalance_index = 1
Price API
tz_minting = max index protected_index (in tez)
tz_liquidation = min index protected_index (in tez)
To calculate the current prices in (tez/kit), we multiply with the current quantity:
minting_price = q * tz_minting
liquidation_price = q * tz_liquidation
Note
The definition of tz_minting
and tz_liquidation
implies that at
any given moment, tz_minting >= tz_liquidation > 0
. Combined with
fminting > fliquidation
, we have that
tz_minting * fminting > tz_liquidation * fliquidation
which is useful in liquidation logic (see burrow-state-liquidations.md).
Adjustment index
The adjustment index, as required by burrowing logic, can be calculated from the system parameters as the product of the burrow fee index and the imbalance index:
adjustment_index = burrow_fee_index * imbalance_index
Touching
Touching the system parameters has the effect of updating all
aforementioned fields, and calculating the burrowing fees that need to
be accrued to the cfmm sub-contract. This is done under the assumption
that we have available the current time now
, the current index
index_now
(calculated by the medianizer), and the current price of
kit in tez kit_in_tez_now
(calculated by the cfmm sub-contract). In
fact, the cfmm sub-contract gives us the one calculated at the end of
the last block, to make manipulation a little harder. We update each
field:
last_touched
Update the timestamp from the last time it was touched to now
new_last_touched = now
index
Update the index from the last time the parameters were touched to the current one
new_index = index_now
protected_index
Update the protected index, by multiplying it with a bounded factor:
new_protected_index = old_protected_index * clamp (current_index / protected_index, low, high)
where low
and high
depend on how much time has passed since the
last time the parameters were touched, effectively limiting how fast
protected_index
can change:
low = exp (-epsilon * (now - last_touched))
high = exp (+epsilon * (now - last_touched))
NOTE: exp (x) = 1 + x
here; we expect the contract to be touched
rather frequently, which keeps the exponent rather small, which makes
this a good approximation of exp
.
drift_derivative
For the calculation of the derivative of drift
,
drift_derivative
, we only use the last-observed target (TODO: show
how we get from the original formula with the logarithms to this?) We
calculate as follows:
new_drift_derivative =
-0.0005 / (secs_in_a_day ^ 2) , if target <= exp (-high_bracket)
-0.0001 / (secs_in_a_day ^ 2) , if exp (-high_bracket) < target <= exp (-low_bracket)
0 , if exp (-low_bracket) < target < exp ( low_bracket)
0.0001 / (secs_in_a_day ^ 2) , if exp ( low_bracket) <= target < exp ( high_bracket)
0.0005 / (secs_in_a_day ^ 2) , if exp ( high_bracket) <= target
drift
For the calculation of the current drift, we use use the following formula:
new_drift = old_drift + (1/2) * (old_drift_derivative + new_drift_derivative) * (now - last_touched)
q
For the calculation of the current quantity q
, we use the
following formula:
new_q = old_q
* exp (
(old_drift + (1/6) * ((2 * old_drift_derivative) + new_drift_derivative) * (now - last_touched))
* (now - last_touched)
)
NOTE: exp (x) = 1 + x
here; TODO: not sure if the exponent is
small enough for this to be a good approximation.
target
new_target = new_q * (new_index / kit_in_tez_now)
burrow_fee_index
The burrow fee index is updated linearly on the number of seconds that have passed since the last time the parameters were touched.
new_burrow_fee_index = old_burrow_fee_index
* (1 + burrow_fee_rate * (now - last_touched) / seconds_in_a_year)
imbalance_index
The imbalance index is also updated linearly on the number of seconds that have passed since the last time the parameters were touched
new_imbalance_index = old_imbalance_index
* (1 + imbalance_rate * (now - last_touched) / seconds_in_a_year)
but imbalance_rate
varies, depending on the difference between
old_outstanding_kit
and old_circulating_kit
:
imbalance_rate =
clamp
( imbalance_scaling_factor * (circulating - outstanding) / circulating,
-imbalance_limit,
+imbalance_limit
)
or, equivalently:
imbalance_rate =
min (imbalance_scaling_factor * (circulating - outstanding) / circulating, +imbalance_limit), if circulating >= outstanding
max (imbalance_scaling_factor * (circulating - outstanding) / circulating, -imbalance_limit), if circulating < outstanding
And in the edge cases the imbalance_rate
is calculated as follows:
if
old_circulating_kit = 0
andold_outstanding_kit = 0
thenimbalance_rate = 0
.if
old_circulating_kit = 0
andold_outstanding_kit > 0
thenimbalance_rate = -imbalance_limit
. (the outstanding kit is infinitely greater than the circulating kit, so the rate is saturated).
Intermediate outstanding_kit
In order to compute the updates for the two remaining fields
(outstanding_kit
and circulating_kit
), we first need to
calculate the current amount of kit outstanding, taking into account the
accrued burrowing fee, thus
outstanding_with_fees = old_outstanding_kit * (new_burrow_fee_index / old_burrow_fee_index)
Accrual to cfmm
The accrued burrowing fees are to be given to the cfmm sub-contract. The total amount we easily compute as
accrual_to_cfmm = outstanding_with_fees - old_outstanding
outstanding_kit
To obtain the updated outstanding_kit
, we need to account for both
the accrued burrowing fees, and the imbalance adjustment
new_outstanding_kit = old_outstanding_kit
* (new_burrow_fee_index / old_burrow_fee_index)
* (new_imbalance_index / old_imbalance_index)
or equivalently
new_outstanding_kit = outstanding_with_fees * (new_imbalance_index / old_imbalance_index)
circulating_kit
Finally, to obtain the up-to-date circulating_kit
, we just need to
record the new kit in circulation, that is, accrual_to_cfmm
:
new_circulating_kit = old_circulating_kit + accrual_to_cfmm
NOTE: If the current timestamp is identical to that stored in the parameters, we do not perform any of the above.
Misc
seconds_in_a_year = 31556952 (= (365 + 1/4 - 1/100 + 1/400) days * 24 * 60 * 60)
seconds_in_a_day = 86400 (= 24 * 60 * 60)
low_bracket = 0.005
high_bracket = 0.05
imbalance_scaling_factor = 0.75
imbalance_limit = 0.05