文章详细介绍了Compound V3合约的行为,它类似于一种可调整供应量的ERC 20代币,即借贷平台的USDC余额的现值可以被转移。文章还讨论了Compound V3实现的ERC 20函数及其工作原理。
The Compound V3 合约表现得像一个重基 ERC 20 代币。重基代币是指具有算法调整供给而不是固定供给的代币。这儿的“代币”表示正的 USDC 余额的现值。也就是说,贷方可以将其本金的现值转移到其他地址,就如同它是一个 ERC 20 代币一样。由于本金的价值通常因利息累积而增加,这个 ERC 20 代币的价值随着时间的推移而向上重基。
Compound V3 不使用代币保管标准(例如 ERC-4626)来追踪借贷池的“份额”。
正如我们在讨论本金和现值时指出的,用户可能已经存入 100 USDC 但因利息累积而获得 110 USDC 的信用——这 110 代表现值。正是这个单位的账目由 Compound V3 的 ERC20 功能管理。
用户必须熟悉利息指数和 Compound V3 的 现值和本金价值的概念。由于 Comet 是我们在这里讨论的主要智能合约的名称,本文中将 Compound V3 和 Comet 交替使用。
每个标题将讨论 Compound V3 实现的一个 ERC 20 功能,以及它如何实现该功能。一些功能并不是 ERC 20 标准的一部分,但对本讨论是相关的。
totalBorrow
,顾名思义,是借入的 USDC 总额。也就是说,它是债务的现值。我们可以通过合约返回的结果和我们在 Compound 平台上看到的来证实这一点。这不仅仅是借款人从平台提取的 USDC 数量——它还包括借入的 USDC 上累积的利息。
下面我们展示一张 Compound V3 用户界面的截图,显示了这个值,以及 Etherscan 返回的 totalBorrow()
函数的结果。
类似地,totalSupply() 并不是贷方存入 Compound 的 USDC 数量——而是 现值 的总存款。
下面截图中的 totalSupply 和 totalBorrow 代码 应该能帮助你清晰理解现值之间的关系。
下面我们截图了两次对 totalSupply 的查询。请注意,右侧第二张截图中的 totalSupply
已经增加。
totalSupply() 函数的行为与 ERC 20 的 totalSupply() 相同。
借款人无法转移债务,因此 totalBorrow 不用于任何代币类接口。
balanceOf 在我们关于本金和现值的讨论中已经涵盖,因此在此不再赘述。
transfer 和 transferFrom 都会转移贷方的现值。金额参数以现值来测量。
这两个函数在内部都会调用 transferInternal
。在 Compound V3 中,转移整个余额的正确方法是转移 uint256 的最大值。指定整个余额可能有些棘手,因为它每秒钟都会增加。
请注意,借款人没有将抵押品转移到其他地址的机制,因为 transferCollateral
仅是内部的。此函数用于清算。
由于 24 kb 的部署限制,Comet 将其部分功能拆分到 CometExt.sol 中,使用了 fallback 扩展模式。CometExt 中的大多数功能与 ERC 20 功能相关。
cUSDCv3 的 approve() 功能是非标准的,因为它只接受 type(uint256).max 或零。由于账户余额因重基而不断变化,因此不可能为某个地址给予正好是整个余额的授权,因为随着利息的累积,余额会不断增加。
approve()
在内部调用 allowInternal,这一点值得单独考察。
allow() 函数不是 ERC20 的一部分,但它的行为与 approve() 类似,都是给一个地址最大授权。approve() 和 allow() 在内部都使用 allowInternal() 来实现对一个地址最大授权。
因为 approve 实际上是二元的,allow 的行为类似于 approve,只是它接受一个布尔参数以对全值进行批准,而不是 uint256。
“allowances” 存储变量保存在 CometStorage.sol 中,称为 isAllowed
。
在 Compound V3 中,授权是全有或全无的。这就是为什么 approve
只接受最大 uint256 值的原因。与传统的 ERC 20 代币不同,这里没有存储授权作为数字的存储变量。
授权是二元的,你只有对最大 uint256 值或零的批准。其他任何值都会导致 revert。
hasPermission
仅仅返回一个布尔值,表示一个地址是否拥有无限的审批或完全没有。
CometStorage 将 mapping(address => uint256)
公共 userNonce 作为公共变量暴露,而不是 EIP 2612 中指定的 nonces(address owner) external returns (uint)
。
name()
和 symbol()
函数是可选的 ERC 20 函数,返回字符串。
CometExt.sol 并不将这些值存储在字符串变量中,而是为节省 Gas 而将其存储在不可变的 bytes32
变量中。Solidity 不允许直接将 bytes32
转换为字符串,因此不可变变量在运行时通过下面的代码转换成字符串。
关于 Solidity 中的 bytes1
,bytes2
,...,和 bytes32
数据类型不为人知的细节是,它们可以像字节数组一样按字节级别进行索引。例如:
contract Example {
bytes32 immutable x = 0x3300000000000000000000000000000000000000000000000000000000000000;
function main() external pure returns (bytes1) {
return x[0]; // 返回 0x33
}
}
CometExt 在内存中初始化一个字节数组,并复制 name32
和 symbol32
不可变变量中存储的字符,然后将其转换为字符串。
Etherscan 知道的 ABI 不知道这些函数,因此它们不会出现在 Comet 函数列表中。然而,由于它们将调用 Comet 的回调,它们可以被调用并最终转到 CometExt 合同。
以下是使用 Foundry 的 cast 调用 name()
和 symbol()
的示例。
CometV3 的行为类似于一个重基 ERC 20 代币,表示贷方的正余额。这个正余额可以像普通的 ERC 20 代币一样转移到其他地址。approve()
函数是非标准的——它只能做无限的批准或根本不做。类似地,用于无Gas批准的 permit()
函数也是非标准的。
查看我们的区块链训练营以获取更多信息。
最初发布于 2024 年 1 月 7 日
- 原文链接: rareskills.io/post/cusdc...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!