Cheesy Champagne Shrimp
Medium
In DistributionModule::_calculateSt
function, while calculating numerator
, p0
(initialPrice) is used instead of pt
(current Price) that could result in wrong daily USUAL distribution.
In order to distribute USUAL token emissions to on-chain and off-chain buckets, DistributionModule::distributeUsualToBuckets
function is called, ideally every 24 hours. This function calls _calculateUsualDistribution
function, that further calls _calculateSt
function which calculates and returns the st
(supply factor). In _calculateSt
function, the numerator
is calculated using initialSupply
and p0
(initial price).
Source
uint256 numerator = Math.mulDiv($.initialSupplyPp0, $.p0, SCALAR_ONE);
Source The docs say that "... we would still use the initial supply and current price of USD0 for the numerator ..."
As we can see that there is conflict between what the docs (research paper) says and what code does. Let's consider below scenarios:
block.timestamp
= 230,000
lastOnChainDistributionTimestamp
= 140,000
initialSupplyPp0
= 1000e18
supplyUSD0PP
= 2000e18
p0
= 1e18
pt
= 1e18
ratret
= 600
p90Rate
= 1000
rateMin
= 50
rate0
= 545
baseGamma
= 10000
m0
= 10e18
d
= 2500
st
is calculated as below: DistributionModule::_calculateSt
...
uint256 numerator = Math.mulDiv($.initialSupplyPp0, $.p0, SCALAR_ONE);
= 1000e18 * 1e18 / 1e18 ==> 1000e18
uint256 denominator = Math.mulDiv(supplyUSD0PP, pt, SCALAR_ONE);
= 2000e18 * 1e18 / 1e18 ==> 2000e18
uint256 result = Math.mulDiv(SCALAR_ONE, numerator, denominator, Math.Rounding.Floor);
= 1e18 * 1000e18 / 2000e18 ==> 0.5e18
return result < SCALAR_ONE ? result : SCALAR_ONE;
= 0.5e18 < 1e18 ? 0.5e18 : 1e18 ==> 0.5e18
...
The calculation of rt
, gamma
, and kappa
will not be affected, so with all the above variables below will be the values:
rt
= 1.1009e18
gamma
= 0.96e18
kappa
= 11.467e18
mt
is calculated as below: DistributionModule::_calculateMt
...
uint256 numerator = Math.mulDiv($.m0, st, SCALAR_ONE, Math.Rounding.Floor);
= 10e18 * 0.5e18 / 1e18 ==> 5e18
numerator = Math.mulDiv(numerator, rt, SCALAR_ONE, Math.Rounding.Floor);
= 5e18 * 1.1009e18 / 1e18 ==> 5.5045e18
uint256 result = Math.mulDiv(numerator, SCALAR_ONE, _calculateGamma($));
= 5.5045e18 * 1e18 / 0.96e18 ==> 5.7339e18
return result < kappa ? result : kappa;
= 5.7339e18 < 11.467e18 ? 5.7339e18 : 11.467e18 ==> 5.7339e18
...
usualDistribution
is calculated as below: DistributionModule::_calculateDistrubtion
uint256 result = Math.mulDiv($.d, mt, BPS_SCALAR, Math.Rounding.Floor);
= 2500 * 5.7339e18 / 10000 ==> 1.4334e18
result = Math.mulDiv(result, supplyPpt, SCALAR_ONE, Math.Rounding.Floor);
= 1.4334e18 * 2000e18 / 1e18 ==> 2866.79e18
result = Math.mulDiv(result, pt, SCALAR_ONE, Math.Rounding.Floor);
= 2866.79e18 * 1e18 / 1e18 ==> 2866.79e18
return Math.mulDiv(result, 1, 365, Math.Rounding.Floor);
= 2866.79e18 * 1 / 365 ==> 7.8547e18
As we can see from the above scenario, per day emission will be 7.8547e18 USUAL
s
Because CBR is on, so the current price pt
will be changed.
cbr
= 0.8e18
block.timestamp
= 230,000
lastOnChainDistributionTimestamp
= 140,000
initialSupplyPp0
= 1000e18
supplyUSD0PP
= 2000e18
p0
= 1e18
pt
= 0.8e18
ratret
= 600
p90Rate
= 1000
rateMin
= 50
rate0
= 545
baseGamma
= 10000
m0
= 10e18
d
= 2500
With all of the above variables same and change in cbr
and pt
below will be the new values of st
, mt
, and usualDistribution
. rt
, gamma
, and kappa
will not be affected due to this change.
new st
= 0.625e18
new mt
= 7.1674e18
new usualDistribution
= 7.8547e18
In scenario2, we can observe that pt
and mt
both are changed but usualDistribution
remains the same because change in price has exact offsetting effect as mt
. Point to note here is that, in the calculation of numerator
in DistributionModule::_calculateSt
we have used p0
not pt
as suggested by the research doc.
Scenario3 - When p0 != pt and we have used pt
for the calculation of numerator
in DistributionModule::_calculateSt
--> cbr is on
new st
= 0.5e18
new mt
= 5.7739e18
new usualDistribution
= 6.2837e18
In scenario3, we can observe that supply factor st
and minting rate mt
are same as scenario1, but usualDistribution
is reduced that reflects the change in price which is due to cbrCoef
.
No response
No response
The overall impact of this issue is that daily USUAL emission will be miscalculated.
No response
In DistributionModule::_calculateSt
, while calculating numerator
, use pt
instead of p0
in compliance with the research paper.
function _calculateSt(DistributionModuleStorageV0 storage $, uint256 supplyUSD0PP, uint256 pt)
internal
view
returns (uint256)
{
....
-- uint256 numerator = Math.mulDiv($.initialSupplyPp0, $.p0, SCALAR_ONE);
++ uint256 numerator = Math.mulDiv($.initialSupplyPp0, pt, SCALAR_ONE);
....
}