时间:2021-12-24|浏览:309
代码的升级是一件痛苦且脆弱的事。尤其是在本就十分复杂的代码大厦上,任何微小的改动,都可能因为某些边界条件的疏忽而造成崩塌,Compound最近就遇到了这事
背景介绍
Compound是一个老牌的去中心化借贷平台
Q1: 为什么要有借贷这回事儿?
在区块链上,所有的资产都是代币化的。我们看好一个项目,但是却没有这个项目发行的代币。这时最简单的方法就是去交易所用手里有的币来换。但是,如果我们又不舍得自己手里的币,该怎么办呢。这时可以去借,抵押品便是我们拥有的币。如果这个项目涨了,获得收益的同时,还可以赎回曾经抵押的币。
交易会发生所有权的转移,而借贷不发生所有权的转移,只是被暂时锁在合约中
同时,由于借贷的引入,我们可以操控更大的资金敞口,实现杠杆交易...
Q2:Compound的运作流程?
和AMM类似,在区块链上实现自动化的借贷,首先要做的便是吸引资金(流动性),而用户所以能将钱存在一个平台,必然是受到利益的驱使。AMM通过交易费来激励用户添加流动性,而借贷平台的手段便是借款利息
由于存在借贷这一需求,总会有人愿意付出利息来借币。而有了利息的激励,也有人愿意将闲钱拿来提供流动性。此外,借贷平台通过利率模型参数的动态调整,可以维持整个系统的供给平衡与风险
Q3: 如何与Compound交互?
用户与Compound的交互接口主要是CToken/CEther合约(这些合约本身就是一种代币), CToken 相当于 Compound这一平台的"入场券"。通过向不同CToken合约质押其底层代币(underlying token)便可以获得相应的CToken
这一操作,表现在代码层面就是 ctoken.mint(amount),比方说:我手里有1000个ETH,便可以调用cEth.mint(1000) 来向cEth池中 "注入流动性"
要注意的是,cToken和底层代币并不是1:1的兑换关系,当蛋糕越做越大时,cToken所能换出的底层代币也就越多。这和LP token的类似,利息便是以这种形式来发放的
那有了cToken以后,我们可以做什么呢?
最简单的便是借钱,因为cToken代表用户质押在Compound的资产,因此可以通过"过抵押"的方式来借出Compound拥有的代币。Compound会先计算用户拥有所有cToken的价值(可能来自于不同的池),根据抵押率来计算用户的流动性(Liquidity)
表现在代码层面就是 ctoken.borrow(amount),比方说:我通过 ceth.mint(1000) 质押了 1000 个 ETH,如果我想借 Dai 的话,需要调用 cDai.borrow(x) 这里的 x 最多价值750 ETH (抵押率75%)
这些都是以美元计算的,再根据Oracle来换算成不同的Token数量
而Comptroller这一合约是一个中间层,它所做的事情,便是交互前的一些计算与验证工作,类似银行的审计员。比方说:张三借了多少钱,欠了多少钱,这小子又来借1000个ETH还能不能借给他
表现在代码层面就是:getHypotheticalAccountLiquidityInternal()、borrowAllowed()、mintAllowed() ...
Q4: COMP代币与Compound的关系?
COMP代币是Compound发行的平台代币,可以用于管理。因为Compound采用DAO的治理模式。对Compound所有的操作,都需要通过投票来决定,提案(proposals)通过后由一个特权合约来执行写在提案中的操作。通过COMP可以获得投票的权重
详情见:https://compound.finance/governance
当然只能用来投票显然还是缺少些吸引力的,COMP本质上就是Compound发行的股票,拥有更多的COMP,可以享受更优的利率,随着Compound的发展,COMP带来的价值也会越来越大,因此COMP值钱(目前 $300 左右)
同时,为了激励用户使用Compound,无论是向Compound提供流动性,还是从Compound借出资产,都会获得一定的COMP奖励,这些奖励以区块为单位计算(划重点:这里与本次事件相关)
修了东墙又补西墙
事故1:Bug的原理
事情的起因是这样的:
2021年9月31日,Compound DAO出现这样一条提案(Proposals 62: https://compound.finance/governance/proposals/62):
该提案提出更新 Comptroller 合约以修复一些 Bug
这里我们可以看出 Bug 和 CompSpeed 有关,CompSpeed 这个变量代表是每个区块可以挖出的 COMP 数量
这里以 mint 为例简单介绍Bug的原理:
ctoken 的 mint 函数的调用链为:mint → mintInternal → mintFresh
可以看到,在 mintFresh 中,会先调用 Comptroller 的 mintAllowed 函数,再更新用户 ctoken 的余额
而 mintAllowed 中,会先调用 updateCompSupplyIndex,再调用 distributeSupplierComp
前者会更新借贷池的奖励状态,主要是 compSupplyState
这一结构体中,block字段记录了更新时的区块号,index字段记录的是更新时的奖励指数
**什么是奖励指数(index)呢?**这是一个随时间不断累加的值,其公式为
表示的是一个借贷池,随着时间的推移,向每个cToken分发的COMP数量。因此,其差值可以简单理解为,这段时间内一个cToken可以获得的COMP数量
用戶喜愛的交易所
已有账号登陆后会弹出下载