compound-finance / comet

An efficient money market protocol for Ethereum and compatible chains (aka Compound III, Compound v3).
Other
259 stars 151 forks source link

`SupplyRate > BorrowRate` in some cases where `utilizationRatio > 1` #253

Closed Itay-gradenwits closed 2 years ago

Itay-gradenwits commented 2 years ago

SupplyRate and BorrowRate are being calculated as following:

function getSupplyRate() public view returns (uint64) {
        uint utilization = getUtilization();
        uint reserveScalingFactor = utilization * (FACTOR_SCALE - reserveRate) / FACTOR_SCALE;
        if (utilization <= kink) {
            // (interestRateBase + interestRateSlopeLow * utilization) * utilization * (1 - reserveRate)
            return safe64(mulFactor(reserveScalingFactor, (perSecondInterestRateBase + mulFactor(perSecondInterestRateSlopeLow, utilization))));
        } else {
            // (interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink)) * utilization * (1 - reserveRate)
            return safe64(mulFactor(reserveScalingFactor, (perSecondInterestRateBase + mulFactor(perSecondInterestRateSlopeLow, kink) + mulFactor(perSecondInterestRateSlopeHigh, (utilization - kink)))));
        }
    }

function getBorrowRate() public view returns (uint64) {
        uint utilization = getUtilization();
        if (utilization <= kink) {
            // interestRateBase + interestRateSlopeLow * utilization
            return safe64(perSecondInterestRateBase + mulFactor(perSecondInterestRateSlopeLow, utilization));
        } else {
            // interestRateBase + interestRateSlopeLow * kink + interestRateSlopeHigh * (utilization - kink)
            return safe64(perSecondInterestRateBase + mulFactor(perSecondInterestRateSlopeLow, kink) + mulFactor(perSecondInterestRateSlopeHigh, (utilization - kink)));
        }
    }

Note that getBorrowRate() * utilization * (1 - reserveRate) = getSupplyRate(), That is because the protocol wants to keep part of the borrow rate to the reserves and not to give it all to the suppliers. The problem is that in some cases where utilization > 1 , utilization * (1 - reserveRate) is greater than 1 and then getSupplyRate() > getBorrowRate() and all the borrowRate income will go to the suppliers and the difference between the interestRate for the suppliers to this income would come from the reserves.

We made a graph in demos that shows what is this transition point (utilization ratio) where getSupplyRate() > getBorrowRate(). We restricted the kink to be lower than 1 (k), the percentage that goes to the reserves to be lower than 1 (P), and the high slope to be GE to the low slope (i think this is a reasonable assumption). You can play with it and try out concrete values and limits. https://www.desmos.com/calculator/x6onz1rrpt

We also came to the conclusion that this transition point where getSupplyRate() > getBorrowRate() is = 1/(1-p) where p is the reserveRate.

jflatow commented 2 years ago

See #251