One of the defining features of the Compound Protocol is its use of algorithmic interest rate models. Interest rate models have been ‘utilized’ by the protocol since its inception. The original whitepaper introduced a basic linear model, based on the idea of utilization , or the percentage of a money market’s supply that is currently being lent out. By and large, this is the model that is still used today in most Compound markets. Interest rate model experimentation will be one of the most exciting things to watch on Compound, but it’s important to understand the differences between existing models before proposing new ones.
For a given cToken, it is important to look at which style of model it uses and make sure that the right one is used. The markets which use the old style are: cBAT, cETH, cUSDC, cREP, cSAI, cUSDC, cWBTC, and cZRX. The markets which currently use the new style are: cDAI and cUSDT. New markets would naturally continue to use the new style. Keep reading for further explanation about the different ‘styles’.
The core idea is that the more cash available in a market to be borrowed, the lower the interest rates should be, and the less cash that is available, the higher the interest rates should be. Importantly, anyone can know exactly what will happen to interest rates, whatever might happen in a market. The interest rate models are designed to economically incentivize liquidity, but not guarantee it. There are many degrees of freedom in choosing a model that provides this incentive, and we have barely scratched the surface, as far as exploring this design space.
cDAI 2-legged rate model: borrow rate vs utilization
With multi-collateral DAI, we introduced the first ‘2-legged’ model, which uses two lines to set rates, instead of one, but is still rather primitive in many ways. The new cDAI was also the first upgradeable cToken contract, which gave us a chance to make some key changes to the core contract, and also paved the way for making future enhancements and optimizations easier.
One of the biggest changes was an interface change to the interest rate models, such that modern models return just a single value which represents the rate in question, and not an antiquated error tuple. This itself was part of an even larger shift of overall mindset, where we started to prefer reverting in general, to propagation of error codes. We could write several articles on the evolution of error-handling within Compound, but for the sake of this one, the important thing to note is that there are fundamentally two ‘styles’ of interest rate models in use today by the protocol.
The selection of parameters thus far has been manual, and somewhat arbitrary, and long have we waited for the day to come where rate model choice could be explored in a more systematic fashion. Historically, we have preferred to launch interest rate models with hard-coded or constructor-only parameters, mainly to reduce the surface area attacks.
Another thing to note about rate models, is that markets have traditionally been tuned independently of one another. The COMP distribution changes the game in many ways, and the lack of standardized rate models has become instantly more apparent. With the USDT suddenly earning the lion-share of COMP, more and more questions are being asked about the fairness of these models.
But with decentralization of the protocol, all this context mostly becomes a footnote. The purpose of this article is to educate COMP-holders and would-be COMP-holders on how we got here, so that together they can make informed decisions about where to take things next.
Rate model styles
The 2 ‘styles’ of rate model signatures are as follows:
getBorrowRate(uint cash, uint borrows, uint _reserves) public view returns (uint, uint)
The return value is a tuple which includes an error code that needs to be checked, and the borrow rate mantissa. Old style markets may emit failure codes, or possibly revert, if anything goes wrong. Reserves were not included in the denominator for utilization calculation.
getBorrowRate(uint cash, uint borrows, uint reserves) public view returns (uint)
getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint)
getSupplyRate is not used by the protocol directly, however new style models should include it. New style markets revert if anything goes wrong. Reserves are generally included in the denominator for the utilization calculation.
At this point in time, the 2-legged model is only implemented in the new style.
Historically we have avoided mutable parameters in the interest rate models. We felt they increased the surface area for vulnerabilities to the protocol, and increased the potency of the admin key and potential for abuse.
However, now that the Compound admin is the governance contract, which is governed by COMP-holders, the potency risk is by and large mitigated.