原文发布在 https://github.com/33357/smartcontract-apps这是一个面向中文社区,分析市面上智能合约应用的架构与实现的仓库。欢迎关注开源知识项目!
Compound RateModel合约解析RateModel合约是用来计算 Compound 上特定代币借贷利率的合约,分析它可以知道借贷利率的计算方法。
演示代码仓库:https://github.com/33357/compound-protocol
WhitePaperInterestRateModel.sol直线型利率模型
合约初始化- 公共函数(合约内外部都可以调用)
- constructor
- 代码速览
constructor(uint baseRatePerYear, uint multiplierPerYear) public { baseRatePerBlock = baseRatePerYear.div(blocksPerYear); multiplierPerBlock = multiplierPerYear.div(blocksPerYear); emit NewInterestParams(baseRatePerBlock, multiplierPerBlock); }
- 参数分析 函数
constructor
的入参有 2 个,出参有 0 个,对应的解释如下:constructor( uint baseRatePerYear, // 年基准利率 uint multiplierPerYear // 年利率乘数 ) public { ... }
- 实现分析
... { // 块基准利率 = 年基准利率 / 年块数 baseRatePerBlock = baseRatePerYear.div(blocksPerYear); // 块利率乘数 = 年利率乘数 / 年块数 multiplierPerBlock = multiplierPerYear.div(blocksPerYear); // 触发事件 NewInterestParams emit NewInterestParams(baseRatePerBlock, multiplierPerBlock); }
- 总结 合约需要按
block
作为时间单位来计算利率,因此需要将baseRatePerYear
和multiplierPerYear
转换为baseRatePerBlock
和multiplierPerBlock
。这里的blocksPerYear
为2102400
,是按照平均15秒
一个block
计算的。
- 代码速览
- constructor
- 公共函数(合约内外部都可以调用)
- utilizationRate
- 代码速览
function utilizationRate(uint cash, uint borrows, uint reserves) public pure returns (uint) { if (borrows == 0) { return 0; } return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); }
- 参数分析 函数
utilizationRate
的入参有 3 个,出参有 1 个,对应的解释如下:constructor( uint cash, // 代币余额 uint borrows, // 用户借出代币总数 uint reserves // 储备代币总数 ) public view returns ( uint // 资金借出率 ){ ... }
- 实现分析
... { // 如果借出代币总数为 0,资金借出率也为 0 if (borrows == 0) { return 0; } // borrows * 1e18 / (cash + borrows - reserves) return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); }
- 总结
utilizationRate
用于计算代币的资金借出率
,资金借出率
的计算公式为资金借出率 = 借出代币总数 / (代币余额 + 借出代币总数 - 储备代币总数)
。由于使用无符号整数计算资金借出率
会精度不够,所以需要乘以1e18
,扩大精度范围。
- 代码速览
- utilizationRate
- 公共函数(合约内外部都可以调用)
- getBorrowRate
- 代码速览
function getBorrowRate(uint cash, uint borrows, uint reserves) public view returns (uint) { uint ur = utilizationRate(cash, borrows, reserves); return ur.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock); }
- 参数分析 函数
getBorrowRate
的入参有 3 个,出参有 1 个,对应的解释如下:function getBorrowRate( uint cash, // 代币余额 uint borrows, // 用户借出代币总数 uint reserves // 储备代币总数 ) public view returns ( uint // 块借出利率 ) { ... }
- 实现分析
... { // 计算资金借出率 uint ur = utilizationRate(cash, borrows, reserves); // ur * multiplierPerBlock / 1e18 + baseRatePerBlock return ur.mul(multiplierPerBlock).div(1e18).add(baseRatePerBlock); }
- 总结
getBorrowRate
用于计算代币的块借出利率
,块借出利率
的计算公式为块借出利率 = 资金借出率 * 块利率乘数 + 块基准利率
。由于资金借出率
扩大了精度范围,需要除以1e18
得到实际值。
- 代码速览
- getSupplyRate
- 代码速览
function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) public view returns (uint) { uint oneMinusReserveFactor = uint(1e18).sub(reserveFactorMantissa); uint borrowRate = getBorrowRate(cash, borrows, reserves); uint rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18); return utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18); }
- 参数分析 函数
getSupplyRate
的入参有 4 个,出参有 1 个,对应的解释如下:getSupplyRate( uint cash, // 代币余额 uint borrows, // 用户借出代币总数 uint reserves, // 储备代币总数 uint reserveFactorMantissa // 储备金率 ) public view returns ( uint // 块质押利率 ) { ... }
- 实现分析
... { // 1 - reserveFactorMantissa uint oneMinusReserveFactor = uint(1e18).sub(reserveFactorMantissa); // 获取借款利率 borrowRate uint borrowRate = getBorrowRate(cash, borrows, reserves); // borrowRate * (1 - reserveFactorMantissa) uint rateToPool = borrowRate.mul(oneMinusReserveFactor).div(1e18); // utilizationRate * borrowRate * (1 - reserveFactorMantissa) return utilizationRate(cash, borrows, reserves).mul(rateToPool).div(1e18); }
- 总结
getSupplyRate
用于计算代币的块质押利率
,块质押利率
的计算公式为块质押利率 = 资金借出率 * 借款利率 * (1 - 储备金率) = 借款利率 * 资金借出率 * (1 - 储备金率)
。由于资金借出率
扩大了精度范围,需要除以1e18
得到实际值。
- 代码速览
- getBorrowRate
拐点型利率模型
合约初始化- 内部函数(仅合约内可以调用)
- constructor
- 代码速览
constructor(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_, address owner_) internal { owner = owner_; updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_); }
- 参数分析 函数
constructor
的入参有 5 个,出参有 0 个,对应的解释如下:constructor( uint baseRatePerYear, // 年基准利率 uint multiplierPerYear // 年利率乘数 uint jumpMultiplierPerYear, // 拐点年利率乘数 uint kink_, // 拐点资金借出率 address owner_ // 所有者 ) internal { ... }
- 实现分析
... { // 记录所有者 owner = owner_; // 更新拐点利率模型参数 updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_); }
- 总结
拐点型利率模型
比直线型利率模型
多了拐点年利率乘数
和拐点资金借出率
这两个参数。
- 代码速览
- updateJumpRateModelInternal
- 代码速览
function updateJumpRateModelInternal(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) internal { baseRatePerBlock = baseRatePerYear.div(blocksPerYear); multiplierPerBlock = (multiplierPerYear.mul(1e18)).div(blocksPerYear.mul(kink_)); jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear); kink = kink_; emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink); }
- 参数分析 函数
updateJumpRateModelInternal
的入参有 4 个,出参有 0 个,对应的解释如下:function updateJumpRateModelInternal( uint baseRatePerYear, // 年基准利率 uint multiplierPerYear // 年利率乘数 uint jumpMultiplierPerYear, // 拐点年利率乘数 uint kink_, // 拐点资金借出率 ) internal { ... }
- 实现分析
... { // 块基准利率 = 年基准利率 / 年块数 baseRatePerBlock = baseRatePerYear.div(blocksPerYear); // 块利率乘数 = 年基准利率 / (年块数 * 拐点资金借出率) multiplierPerBlock = (multiplierPerYear.mul(1e18)).div(blocksPerYear.mul(kink_)); // 拐点块利率乘数 = 拐点年利率乘数 / 年块数 jumpMultiplierPerBlock = jumpMultiplierPerYear.div(blocksPerYear); // 记录拐点资金借出率 kink = kink_; // 触发事件 NewInterestParams emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink); }
- 总结
拐点型利率模型
中计算块利率乘数
时,方法和直线型利率模型
不一样:拐点资金借出率
越高,块利率乘数
越低,其目的我不是很清楚。(可能是拐点资金借出率越高的代币市场深度越好,块利率乘数可以设置的更低,大家可以讨论一下)
- 代码速览
- constructor
- 公共函数(合约内外部都可以调用)
- utilizationRate
- 代码速览
function utilizationRate(uint cash, uint borrows, uint reserves) public pure returns (uint) { if (borrows == 0) { return 0; } return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); }
- 参数分析 函数
utilizationRate
的入参有 3 个,出参有 1 个,对应的解释如下:constructor( uint cash, // 代币余额 uint borrows, // 用户借出代币总数 uint reserves // 储备代币总数 ) public view returns ( uint // 资金借出率 ){ ... }
- 实现分析
... { // 如果借出代币总数为 0,资金借出率也为 0 if (borrows == 0) { return 0; } // 资金借出率 = borrows * 1e18 / (cash + borrows - reserves) return borrows.mul(1e18).div(cash.add(borrows).sub(reserves)); }
- 总结
拐点型利率模型
中计算资金借出率
和直线型利率模型
相同。
- 代码速览
- utilizationRate
- 内部函数(仅合约内部可以调用)
- getBorrowRate
- 代码速览
function getBorrowRateInternal(uint cash, uint borrows, uint reserves) internal view returns (uint) { uint util = utilizationRate(cash, borrows, reserves); if (util
关注打赏
- 代码速览
- getBorrowRate
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?