本文详细解释了Compound V3协议如何以秒为单位计算利息,并通过Solidity代码逐行分析利用率如何驱动利率的变化。
Compound V3 协议以秒为单位测量利率。Compound V3 前端将这些数字缩放到以年为单位,以便于人类理解。当我们在 Etherscan 上检查 Compound V3 的利率参数时,我们可以看到以下借款者参数。在接下来的部分,我们将确认这些参数与我们在 Compound USDC 以太坊前端上看到的内容一致。
本文是一个 Solidity 的逐行讲解,解释了如何使用率对利率造成影响。
我们假设你已经阅读了我们的文章 如何确定加密货币利率。
在 Compound V2(和 AAVE V3)中,供应利率是借款利率乘以利用率。在 Compound V3 中,供应利率直接是利用率的函数,不考虑借款利率。借款利率遵循其自身的利率曲线。
AAVE V3 称之为 “最佳利用率(optimal utilization)”,而 Compound V3 则称之为 “拐点(kink)”。
变量 borrowPerSecondInterestRateBase 是 “截距(intercept )”,当前值为 317097919。我们在这一部分的目标是展示这个截距等于 1% 的年利率。也就是说,当利用率为零时,借款者支付 1% 的利息(根据当前参数,可能会由治理进行更改)。
每年有 31,536,000 秒(SECONDS_PER_YEAR),不考虑闰年和其他公历的特殊情况。如果将 31536000(SECONDS_PER_YEAR)乘以 317097919(borrowInterestRatePerSecond),我们得到大约 0.01e18(1e16)。在 1 是 1e18 的尺度下,这相当于 1% 的借款利率。
实际上,我们可以通过查看 以太坊上的 USDC Compound 市场 来验证这一点。
如果你将鼠标悬停在各种利用率水平的 “利率模型” 上,你可以看到预期的供应和借款利息。前端不允许你将鼠标悬停在 0% 的利用率。然而,你可以看到每 1% 的利用率变化,利息变化约为 0.03%,因此在 0% 的利用率下,预期的利息将为 1%。请参见下面的动画。
https://img.learnblockchain.cn/2025/02/26/file.mp4
因此,我们可以看到 y 截距确实是每年 1%。
这在撰写时是正确的,其他底层资产在其他二层上可能会有所不同。
在上面的动画中,我们看到在 0% 的利用率下,预期的 “赚取 APR”(贷方的收益)为 0%。这与我们在 Etherscan 上看到的内容相匹配。供应利率的 y 截距参数称为 supplyPerSecondInterestRateBase。根据图表和 Etherscan,截距为零。
在上面的示例中,我们推断 0.01e18
转换为 1%的利息。我们将通过代码库展示这一推断是如何得出的。这将需要五个步骤。
在 CometCore.sol 第 57 行 中,我们看到 Compound 使用了一个 “FACTOR_SCALE” 值为 1e18(如下截图中的蓝框)。
我们也在上面的部分提到 SECONDS_PER_YEAR
常量(红框)。
让我们查看 Comet.sol 中的 getUtilization() 函数。
此时我们不知道 totalSupply_
和 totalBorrow_
(蓝框和绿框)使用了什么规模,但合理的假设是它们使用相同的规模(小数位数),并因此它们的规模会相互抵消(返回行 464)。由于分子乘以了 FACTOR_SCALE
(红框),因此利用率百分比将以 18 位小数为单位进行测量。
现在让我们比较当前的 getUtilization() 值在 Etherscan 上与 Compound 应用上显示的值。
当前利用率 904869679838357231
除以 FACTOR_SCALE
后转化为 90.49%(四舍五入到两位小数)。这确实是在使用 18 位小数。
presentValueSupply
和 presentValueBorrow
的函数,我们期望读者还不熟悉这些术语——但可以将其视为可借贷的总资本的美元价值和总借款美元的价值。
在我们关于 DeFi 中的利率 的文章中,我们提到流行的利率模型是分段函数,并具有 “最佳” 利用率的概念。Compound V3 将其称为 “拐点”——当利率开始更陡峭上升的时候。这两个不同的术语实际上指的是同样的概念。
在撰写时,USDC 在以太坊上的最优利用率为 93%,如下所示。
由于利用率以 18 位小数的 定点数字 形式进行测量,借款拐点和供应拐点同样以 18 位小数定点数字进行测量。利率函数直接比较这两个值,如我们将要在接下来部分看到的。
熟悉其他定点库中的 mulDivDown
的程序员将会轻松理解这个函数。
它接受两个定点数字并将它们相乘,以得到另一个定点数字。该函数如下所示。
由于我们是将两个 18 位小数的数字相乘,因此我们需要除以 FACTOR_SCALE
,以避免得到 36 位小数的输出。
只需将该函数看作是“它将两个 18 位小数的数字相乘,并返回一个表示其乘积的 18 位小数的数字”。
我们现在准备好查看 Compound V3 使用 1e18 规模来测量利率的方式。
Compound 使用了分段线性函数,如我们在关于利率的文章中讨论的。以下是 getSupplyRate()
函数,它根据当前的利用率返回贷方获得的当前利率。我们知道 mulFactor(...)
返回的是 FACTOR_SCALE
(18 位小数)数字。因此,我们知道 supplyPerSecondInterestRate
(黄色圆圈)也一定是 FACTOR_SCALE
数字,否则我们将添加小数不对齐的数字。因此,函数 getSupplyRate()
返回的是 FACTOR_SCALE
小数。
函数 getBorrowRate
的行为相同,因此我们将不在此处包括。
曲线的参数——截距、斜率和拐点——都可以由治理进行调整。
要计算利用率作为函数的利率,用户可以使用 getUtilization()
获取当前利用率,并将其插入到 getSupplyRate()
和 getBorrowRate()
中。
contract GetCurrentRatesComet {
function getRates(IComet comet)
external
returns (uint64, uint64) {
uint64 private constant SECONDS_PER_YEAR = 365 * 24 * 60 * 60;
uint256 utilization = comet.getUtilization();
// 这些是 18 位小数定点数字
// 测量每秒的利息
uint64 supplyRate = comet.getSupplyRate();
uint64 borrowRate = comet.getBorrowRate();
// 将它们以 APR 形式返回
return (supplyRate * SECONDS_PER_YEAR,
borrowRate * SECONDS_PER_YEAR);
}
}
我们仅展示了 Compound 如何在特定时刻计算利率。在稍后的文章中,我们将展示如何将利务进行复利和累积利息。
利率的时间单位为秒。测量精确到 18 位小数。利用率也是以 18 位小数进行测量。
请查看我们的 区块链训练营 以了解更多信息。
最初发布于 2024 年 1 月 4 日
- 原文链接: rareskills.io/post/compo...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!