原文标题:《DeFi Lending Concepts Part 1: Lending and Borrowing》
原文作者:Tal
原文编译:Kxp,BlockBeats
这篇文章是三篇系列文章的第一篇,讨论 DeFi 借贷协议的工作原理——它们的关键组成部分、公式和用例。在这一过程中,我们将强调,尽管协议使用不同和创意的命名方式,但它们倾向于重复、迭代和分享核心概念。其中一篇本博客文章中详细介绍如何使用 ERC20 Token来代表用户在借贷池中的份额。我们将从分析这些协议的独特元素开始,并提供技术概念来区分它们的工作方式。
在传统金融(或 TradFi)中,借贷由第三方金融机构进行调整。这些金融机构被委托执行两项关键任务:强制借方向贷方支付利息,并评估并防止被认为是不可信的当事方参与这些活动。
相比之下,在去中心化金融(或 DeFi)中,第三方借款人和贷款人是不值得信任的。这种信任的缺失激发了一个创新的设计,用于在链上促进借贷过程。
借贷池是一个智能合约。DeFi 协议用户可以存入资产(通常是 ERC20 Token),目的是使用该合约来借出他们存入的资产。其他用户可以与借贷池进行交互,享受即时贷款,即抵押在池中的资产进行借款。
与传统金融方法相比,借贷池在借贷方面具有一些重大的优点,例如:
· 在 DeFi 中,贷款不受贷款资金与借款金额 1:1 可用性的限制。相反,来自协议所有用户的资金都被存入池中,从而创建了足够大的Token库存,以立即满足贷款需求。
· DeFi 不需要还款计划。贷款是根据以前存入的抵押品执行的,用户可以随时选择还款。
此时,你可能会想,「如果我不得不提供同等价值(甚至高估)的资产作为抵押品,为什么要在借贷协议上借入资产?难道我不应该出售抵押品并购买所借资产吗?」
实际上,这种 DeFi 借贷协议似乎只允许完全抵押(或超额抵押)的贷款,为一个有趣的「交易」方法打开了大门:杠杆。
假设你对 WBTC 非常看好,非常确定它的价值会飙升!你可以在你最喜欢的借贷协议上存入一些 WBTC(价值 1000 美元),然后使用它来借入一些稳定币(例如 USDC),然后用这些稳定币在某个交易所上购买更多的 WBTC(对于我们的场景,假设你的初始存款的一半,即 500 美元)。在这种情况下,你暴露于 WBTC 的价值为 1500 美元,而你的初始存款只有 1000 美元。
但是,如果你把你的 500 美元的 WBTC 抵押品存入协议来借入更多的 USDC 呢?这个过程被称为超额杠杆,你可以一直这样做,直到你超出了你的借款能力,而协议的政策会阻止你这样做。
在类似的情况下,假设你对 WBTC 持悲观态度(毕竟现在是 Crypto 冬天)。你可以采取我们之前场景的相反操作,将 USDC 作为抵押品存入协议来借入 WBTC,然后立即以更多的稳定币换掉它。如果你的预测成为现实,WBTC 的价格下降了,你可以在交易所上以更便宜的价格购买相同数量的 WBTC,偿还贷款并获得多余的 USDC,从而打开(并关闭)WBTC 的空头头寸。
与传统金融一样,将资产存入借贷池的用户会受到长期保留资金的激励,并获得存款利息。利息随时间累计,按用户在协议中的存款的百分比计算,并由其相应的存款用户声明。用户在借贷池中保留资产的时间越长,他们获得的利息就越多。
协议如何记录每个用户在池中的份额?当一个用户向池中存入资产时,他们的「份额」会稀释所有用户的份额,协议会相应地反映这一点。然而,协议不会直接跟踪和更新每个用户的池份额,而是仅处理存款人份额的变化,而无需每次提取或存入时主动更新其他用户的份额。
你可能会认为这个协议让你既能拥有蛋糕,又能吃掉蛋糕。但实际上不是这样的:
协议通过铸造和销毁 ERC20 Token来处理利息发放,我们称之为「份额Token」,它代表了贷款池中一个贷方的份额(或存款资产的比例)。这种「份额Token」设计自动调整其他「股东」的股份稀释,以反映「份额」的铸造和销毁,与他们的基础资产的存款或提取成比例。
下面,我们将提供不同协议如何使用「份额Token」的实际示例,并讨论它们的相似之处。
aToken 是 AAVE 的收益生成Token,由贷款池在存入和提取资产时铸造和销毁。
aToken 是集成到 AAVE 协议中的类似于 ERC20 的Token,因此用户可以进入的每个不同市场(存入抵押品)都有一个对应的 aToken。
如果我们查看 AAVE 借贷池合约,我们可以看到当用户向池中存入资产时发生的基本操作:
我们可以看到与用户存入的市场相对应的 aToken 将被称为「铸造」函数。
我们可以看到,实际要铸造的数量是:
如上图所示,在这个例子中,用户加入了一个已经在之前的存款中赚取了一些利息的市场。上面的方程式帮助我们理解这一点,因为它显示了如何使用全局指数来考虑所有用户的利息累计,这个指数会在各种操作(存款、提款等)时更新。
当用户提取他们的基础资产时,liquidityIndex 将用作乘数来计算交易中所欠的Token数量。
以下是来自借贷池合约的相关代码片段:
在这里,aToken 合约的 balanceOf 函数有点奇怪。毕竟,我们刚刚确定铸造的 aToken 数量与存入的基础资产数量不同。调用 IAToken(aToken).balanceOf(address(user)) 如何产生用户即将提取的基础资产数量(如在函数底部所示)?原因如下:
· 当用户提取他们的资产时,他们的 aToken 将被销毁。这些已销毁的 aToken 保持其他用户所拥有的 aToken 的总量与他们的份额成比例,这些份额是在用户资产提取之后的。
· 用户提取资金的市场利率会随着每次提取而更新。
正如我们先前所述,aToken 是类似于 ERC20 的Token。我们强调它们是「类似」ERC20 Token,因为它们的 balanceOf 函数具有独特的属性。在常规的 ERC20 Token中,balanceOf 函数返回一个地址拥有的Token数量。
由于 aToken 代表池的份额,而不是直接的价值,因此 aToken 的 balanceOf 函数返回协议欠用户的基础Token的数量,以对其存款进行补偿。
在此,该 balanceOf 函数覆盖了继承的 aToken 合约中的 balanceOf 函数。结果,该示例逻辑中的 balanceOf 逻辑被执行,而不是用户Token数量的常规(继承)映射查找。
上述提到的Token数量然后乘以 getReserveNormalizedIncome 的结果,该函数执行以下逻辑:
我们可以识别此处的分支:
· 如果在该块中已经更新了保留数据:返回该市场的 liquidityIndex 值,因为它已经更新。
· 否则:我们需要看看 calculateLinearInterest 中发生了什么才能找出下一个流程。
当前市场的 ReserveData 对象中的 currentLiquidityRate 和 lastUpdateTimestamp 被传递到此函数中,函数的结果为:
让我们分解此方程式的组件,以更好地理解 linearInterest 值的要点:
· currentLiquidityRate:可以将其视为我们所在市场的年利率(APY)
· block_{timestamp} - lastUpdatedTimestamp:自上次更新以来经过的时间
注意:由于我们在 getNormalizedIncome 中选择了第二个分支,因此在此时保证该值为正值。
因此,我们可以将此利息应计机制视为一个简单的利息复合机制,它在每个区块中进行复合。现在,我们已经确定了要为用户累计的利息金额,我们只需要将该值乘以流动性指数,然后在 balanceOf 函数中进行用户的规范化收入乘法:
现在我们了解了 aToken 背后的逻辑,但我们仍然需要解决 liquidityIndex 的工作原理之谜。
在下面的示例中,liquidityIndex 可以定义为一定时间内储备积累的利息:
回顾之前提到的 liquidityRate 变量 - 现在我们将讨论它在计算 liquidityIndex 中的使用。只有当 liquidityRate 大于 0 时,才会积累利息 - 换句话说,只有该市场中有任何 APY 时才会积累利息。这是有意义的。
让我们快速回顾一下 calculateLinearInterest 的实际操作:
上述逻辑可以转化为以下方程式:
正如我们可以在 DefaultReserveInterestRateStrategy.sol 合约中看到的那样,liquidityRate 是通过以下方式定义的:
因此,可以写为:
整体借款利率(overallBorrowRate)在此定义为:
我们可以将其写成:
利用率(utilizationRate)可以定义为:
在定义利用率时,我们更容易考虑储备中流动性(当前借出的流动性)与市场中总流动性之间的比率,这可以简化为:
现在我们可以使用这两个定义来编写流动性指数的方程式:
由于 totalBorrows 在分子和分母中都存在,因此我们可以写成:
关于流动性指数的方程式,现在已经说得够多了,我们以后会再来讨论这个定义。
让我们继续我们下一个借贷协议示例,Compound。
Compound 使用称为 cToken 的「份额Token」来处理借款和放贷。这个Token为 Compound 协议中所有可用于用户借贷的资产进行记账。
与我们在 AAVE V2 中讨论的类似,Compound 的「份额Token」被铸造并用于赎回基础资产。
Compound 使用的汇率类似于 AAVE V2 的流动性指数,以确定应铸造多少 cToken。这个汇率是一个这样的函数:
让我来解释这里的关键术语:
·totalCash:cToken 账户拥有的 ERC20 基础Token的数量。
· totalBorrows:借款者借出市场上的 ERC20 基础Token的数量。
· totalReserves:保留的一定数量的 ERC20 基础Token,可通过治理方式进行提取或转移。
· totalSupply:返回 cToken 的总供应量的 ERC20 函数。
有了这个背景,我们可以写出 Compound 的汇率方程式:
当用户存入 ERC20 Token时,汇率决定了将铸造多少 cToken 作为回报:
要铸造的 cToken 数量由以下方程式定义:
为了进一步巩固这些协议之间的相似性,让我们再分析另一个借贷协议 Euler,看看它如何处理借贷。
在下面的示例中,deposit 函数允许用户存入 ERC20 Token以换取 eToken。
正如我们所见,internalAmount 是为此转移铸造的 eToken 数量。
与 Compound 的名字和函数 exchangeRate 又一次直接重叠。
让我来解释一下用于计算汇率的关键参数:
· poolSize:使用基础资产的 ERC20 合约中,以池合约地址调用 balanceOf(address)函数的结果。
· totalBorrows:借出的 ERC20 基础Token的总量,目前不在池中。
· totalBalances:所有 eToken 持有者的总余额。
因此,方程式将是:
我们已经涵盖了 3 个借贷协议:
· AAVE V2
· Compound
· Euler
我们已经检查了「份额Token」的铸造方式,以及它们如何通过借贷池交换存款资产。
我们提出的三个方程式可以归纳为一个简单的方程式:
请记住,汇率可以按照协议定义的任何方式进行定义。这些任意的汇率可以增加铸造的Token数量(如果小于 1),如果大于 1 则会减少数量。
在 AAVE V2 和 Compound 中,我们已经看到了 someRate 变量的一些相似之处。在 Compound 中,someRate 是:
而对于 AAVE V2,someRate 的定义如下:
流动性指数的定义为:
虽然我们不能将每个协议的汇率归纳为一个式子,但对于 AAVE2 和 Compound,我们知道汇率是市场中总流动性的函数。回到我们的方程式,给定 totalLiquidity 是市场中 ERC20 基础Token的总量,那么在 exchangeRate 表达式的分子中和 liquidityRate 的分母中的分子是功能上相同的。
简而言之:这些协议在本质上是相似的。虽然它们有时可能使用不同的术语,但当将它们分解为方程式时,每个组件在实现中都具有类似的目的。我们邀请读者随机选择一个借贷协议,并检查我们在此处讨论的归纳是否也适用于该协议。如果适用的话,请随时告诉我们。
原文链接
欢迎加入律动 BlockBeats 官方社群:
Telegram 订阅群:https://t.me/theblockbeats
Telegram 交流群:https://t.me/BlockBeats_App
Twitter 官方账号:https://twitter.com/BlockBeatsAsia