Compound 101-利率模型
WhitePaperInterestModel
基本的数据:
- cash:资金池余额
- borrows:总借款数
- reserves:储备金
在此基础之上,衍生出的费率:
- utilizationRate:资金利用率
- borrowRate:借款利率
- supplyRate:存款利率
资金利用率
$$ utilizationRate = borrows / ( cash + borrows - reserves ) $$
借款利率
这里借款利率与资金利用率成正比,即资金利用率越高,说明资金池中被借出的资金占比越高,需要通过提升借款利率来抑制借款需求
$$ borrowRate = k * utilizationRate + b $$
具体看这里的k和b怎么计算,以及分别代表什么含义
- 当资金里利用率为0时,借款利率=b,则说明b代表的是基准利率,后续随着资金利用率提升,整体的借款利率都将大于这个数
- k这里代表的是斜率,由协议方控制
值得注意的是,这里的所有数据和费率都是以区块为单位的,即这里可以理解为区块单位的借款/存款利率,因为以太坊一年的区块数量是基本固定的,可以推算出年借款利率等数据
function getBorrowRate(uint cash, uint borrows, uint reserves) override public view returns (uint) {
uint ur = utilizationRate(cash, borrows, reserves);
return (ur * multiplierPerBlock / BASE) + baseRatePerBlock;
}
存款利率
存款利率和资金利用率是成正比的,即资金利用率越高,说明资金池中被借出的资金占比越高,需要提升存款利率来鼓励用户存款
$$ supplyRate = utilizationRate * borrowRate * (1-reserveFactor) $$
function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) override public view returns (uint) {
// reserveFactorMantissa 储备金率
// 存款利率=资金利用率*借款利率*(1-储备金率)
uint oneMinusReserveFactor = BASE - reserveFactorMantissa;
uint borrowRate = getBorrowRate(cash, borrows, reserves);
uint rateToPool = borrowRate * oneMinusReserveFactor / BASE;
return utilizationRate(cash, borrows, reserves) * rateToPool / BASE;
}
看一下以太坊主网上部署的利率模型的实际例子: (这里数字都是*18次方的,便于统一计算)
WhitePaper baseRate=50000000000000000 multiplier=150000000000000000
处理一下:base=0.005 multiplier=0.015
JumpRateModel
拐点型利率模型的特点就是在不同阶段,直线的斜率会变化(这里是立刻提高,以抑制借款)
因此模型由两部分组成:
- y=k1x+b1 (x<x0)
- y=k2x+b2 (x>x0)
其中最核心的就是两部分斜率k1 k2,以及临界值x0
和基础的利率模型一样,x代表资金利用率,在JumpRateModel合约中各参数分别对应的变量名如下:
- k1: multiplierPerYear
- k2: jumpMultiplierPerYear
- x0: kink
- b: baseRatePerYear
两部分直线都过点(kink, multiplierPerYear*kink+baseRatePerYear),带入到y=k2x+b2中,
得到 b2=multiplierPerYear*kink+baseRatePerYear-jumpMultiplierPerYear*kink
理解了这几个对应的变量后,第二部分的曲线公式可以整合为:
$$ borrowRate = jumpMultiplierPerYear * (x-kink) + multiplierPerYear*kink+baseRatePerYear $$
具体的实现代码如下:
function getBorrowRate(uint cash, uint borrows, uint reserves) override public view returns (uint) {
uint util = utilizationRate(cash, borrows, reserves);
if (util <= kink) {
return (util * multiplierPerBlock / BASE) + baseRatePerBlock;
} else {
uint normalRate = (kink * multiplierPerBlock / BASE) + baseRatePerBlock;
uint excessUtil = util - kink;
return (excessUtil * jumpMultiplierPerBlock/ BASE) + normalRate;
}
}
存款利率的计算方式则和基础的保持一致