正如我们在之前的文章中所承诺的那样,我们希望与社区分享一个错误。
Dracula协议仍然缺乏对其代码的官方审计。
然而,今天的帖子不是关于我们的,而是关于审计及其在整个DeFi社区中的作用。 在开发过程中,我们的团队已经注意到$SUSHI中的Sushiswap治理问题与John Seok同时被审计人员忽略;可以检查一下,$DRC已经修复了这个问题。 截至那一刻,Sushiswap没有实施治理;这并不重要。 当我们开始开发我们的协议并将Sushiswap MasterChef智能合约作为我们MasterVampire合约的潜在骨架进行调查时,我们注意到另一个错误,这次会产生更严重的后果。
我们想描述错误留下的漏洞和潜在的后门,并在不同的项目中分叉多次。 错误本身可能会导致用户的奖励部分丢失或不合理地倍增。 基于此的潜在攻击很难实施,并且需要特别的准备,以及在发射的初始阶段的所有者权利。 但它能够为任何具有管理员权限的人提供已经流通的代币供应量的显着份额。 即使在multisig和governance下,在普通事务中也很难注意到任何恶意的东西。
据我们所知,这个问题是在每个Sushiswap克隆中实现的。 我们将在Sushiswap MasterChef合同的例子中说明这个问题,因为它被审计了好几次,并得到了最多的关注。
MasterChef合同具有massUpdatePools函数,迭代所有池并调用updatePool函数。 此函数会更新给定的池,并为之前未收到的所有块提供奖励。 massUpdatePools仅在add和set函数中引用和调用。 在两者中,调用massUpdatePools位于可选标志下。 updatePool要求deposit和withdraw。
仅当设置_withUpdate标志时才调用massUpdatePools
让我们理解为什么_withUpdate是一个可选标志是不负责任的,可能是恶意的。
失去的奖励
想象一下,在Sushiswap方面有个非常小的池,而不是很多利益相关者。 随着罕见的存款和取款,因此,updatePool也被调用很少。 然后由于某种原因,奖励被重新设计,并且这个池在没有_withUpdate标志和对updatePool的调用的情况下减少了它的份额。 当set被调用时,奖励可能会减少,而当新池添加新分配点时,奖励可能会减少。
不需要手动减少我们想象中的小池的分配点,而是添加具有更多分配点的新池,有效地稀释我们的池份额。 如果没有预先调用updatePool,我们的虚拟池的用户将体验到,他们对lastRewardBlock和添加新池之间的所有块的奖励将按照旧奖励计划计算,而不是按照新奖励计划计算,并且使用新分配点,他们将获得更少的奖励。 这相当于追溯燃烧一些用户奖励。
这里有些交易,调用add和set,即没有_with Update标志的Sushi swap调用。 用户丢失和不公平获得Sushi的数量是未定义的。
毫无根据的造币
然而,这也可能以不同的方式工作:有些人可能会收到比他们应得的更多。
考虑在生产的初始阶段合同的恶意所有者,默默地增加了一些零分配点的池,并在那里存款一些代币。 这看起来一点都不可疑,因为分配点似乎设置为零,没有人激励这些池。
但是,让我们想象一下,如果在10天后,从一开始一堆新的交易将会出现一些新的池和他们的奖励更新,会发生什么。 几乎没有人会注意到,一些之前零分配点的池开始甚至有10%的分配,因为人们倾向于认为没有人能够每块铸币超过100/1000Sushi。
因此,在没有_withUpdate标志的情况下执行的更新交易将导致这些池(开发资金来自block one)接收总铸币量的10%*10天=目前总循环供应量的~10%。 大约64万Sushi在一个街区铸造。
审计
与这问题的合同进行了多次审查。
由Peckshield团队审计过Sushiswap。 由Quantstump审计过Sushiswap。 由Slowmist团队审计过Moonswap。 由Tomochain and Arcadia Group审计过Luaswap.
我们认为,这一发现的严重性至少是在一个较高的水平。 审计人员忽视了这一事实,这引起了一些关于审计在DeFi的作用的问题。
解决这个问题的方法非常简单,它是在Dracula协议中实现的。 人们只需要在没有任何"flags"的情况下对set函数中的updatePool进行硬编码调用。
尽管如此,我们仍然缺乏对我们项目的官方审计,并邀请任何人检查我们的代码。