Skip to content

Latest commit

 

History

History
150 lines (117 loc) · 5.77 KB

File metadata and controls

150 lines (117 loc) · 5.77 KB

Cheesy Champagne Shrimp

Medium

Wrong calculated St will result in wrong Mt hence wrong daily USUAL distribution

Summary

In DistributionModule::_calculateSt function, while calculating numerator, p0 (initialPrice) is used instead of pt (current Price) that could result in wrong daily USUAL distribution.

Root Cause

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:

Scenario1 - When p0 == pt --> no cbr

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 USUALs

Internal pre-conditions

Scenario2 - When p0 != pt --> cbr is on

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.

External pre-conditions

No response

Attack Path

No response

Impact

The overall impact of this issue is that daily USUAL emission will be miscalculated.

PoC

No response

Mitigation

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);
        ....
}