25

SODA合约漏洞分析

 3 years ago
source link: https://learnblockchain.cn/article/1476
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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 锁在合约内,分别是:

480 weth
1100 weth
270 weth
1230 weth

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

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

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 锁在合约内,分别是:

480 weth
1100 weth
270 weth
1230 weth

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

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

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

  • 发表于 9小时前
  • 阅读 ( 17 )
  • 学分 ( 0 )
  • 分类:DApp

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK