SODA合约漏洞分析

soda是一个DEFI借贷的合约,其中的逻辑是这样的:用户超额抵押WETH然后贷出SOETH,抵押的WETH可以挖矿,SOETH则可以通过uniswap交易或者参与别的活动。

当用户抵押`WETH...

soda是一个DEFI借贷的合约,其中的逻辑是这样的:用户超额抵押 WETH然后贷出 SOETH,抵押的 WETH可以挖矿,SOETH则可以通过uniswap交易或者参与别的活动。

当用户抵押 WETH后每日会产生一定的贷款利息,当贷出的 SOETH与总利息超过一个阈值时,别人就可以进行清算。清算就是别人把贷和利息还上,然后获得抵押人的抵押物,即 WETH

比如,小明抵押了 100 WETH,贷出 70 SOETH,每日利息是0.05%,则每日需要付 70 * 0.05% = 0.035 SOETH. 假设平仓位是抵押额的0.9,则平仓位为 100 * 0.9 = 90 SOETH。 那么当n天后,70 + n * 0.035 >= 90时(计算可得 n >= 572),别人就可以清算,支付 90 SOETH以及5%抵押量的手续费,就可以拿走 100 WETH。最终需要支付 95 SOETH,获得 100 WETH

我们整理一下思路: 对于借贷:

  1. 用户抵押 WETH后,可以贷出70%的 SOETH
  2. 用户的日息为贷出额度的0.05%
  3. 用户的平仓位为90%的抵押量
  4. 当贷出额度+总利息超过平仓位时,不再产生利息,并且可以被别人清算。

对于清算:

  1. 需要还被清算者的贷款额度,即70%的 SOETH
  2. 需要还清被清算者的利息
  3. 需要出抵押值5%的手续费
  4. 因此清算发起人,需要支付95%抵押量的 SOETH,并获取100%的抵押物 WETH,利润率为5%

而soda的问题就在于,清算时,平仓仓位由抵押量的90%,变成了贷出量的90%。也就是说贷出即爆仓。

还是以小明为例: 小明抵押了 100 WETH,贷出 70 SOETH,理论上小明的平仓位为 100 * 0.9 = 90 SOETH,但是由于合约的BUG,清算时,平仓价位变成了 70 * 0.9 = 63 SOETH。也就是说,下单后,别人就可以对他的贷进行平仓清算。而清算发起者需要支出的费用由三部分组成:70%的贷、利息、5%的手续费。而在短时间内,利息几乎为0,那么清算者一共只需要出 75 SOETH,而获取小明的 100 WETH。利润率为25%。

问题代码:


function collectDebt(uint256 _loanId) external override {
    ...
    // should be 'loanInfo[_loanId].lockedAmount'
    uint256 maximumLoan = loanInfo[_loanId].amount.mul(loanInfo[_loanId].maximumLTV).div(LTV_BASE);

    // You can collect only if the user defaults.
    require(loanTotal >= maximumLoan, "collectDebt: >=");
    ...
}

截止目前为止,依然有4310枚 WETH锁在合约内,分别是:

  • LoanId 16: 480 weth
  • LoanId 92: 1100 weth
  • LoanId 93: 270 weth
  • LoanId 119: 1230 weth

这些仓位暂时是安全的,因为 SOETH的挖出的总量才2156(被销毁了一部分?),流通在uniswap市场上的 SOETH只有500多枚。假如要清算 270 WETH,则至少要购入 202 SOETH,按照uniswap的计价规则,这样会导致 SOETH的价格剧烈攀升,而利用bug清算的利润率才25%左右。

目前soda已经更新了合约,但是合约生效需要48小时,所以还是存在一定的风险。

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 2020-09-22 00:11
  • 阅读 ( 296 )
  • 学分 ( 16 )
  • 分类:DApp

0 条评论

请先 登录 后评论
不啻
不啻

1 篇文章, 26 学分