精度损失与舍入漏洞

智能合约并不一定需要访问控制漏洞才会导致资金损失。

有时,漏洞就隐藏在一个简单的除法运算中。

金融智能合约使用整数算术。小数部分会被舍弃。这种舍入方向决定了价值流向谁。一个单位的误差可能会在数千次交易中不断累积。

在金融协议中,舍入本质上是一种价值转移策略。

每次除法运算都必须回答三个问题:

  • 计算向哪个方向舍入?
  • 哪个方从该方向中获益?
  • 攻击者能否重复或放大这种优势?

常见的数学错误包括:

  1. 过早进行除法 如果在乘法之前进行除法,你会丢失精度。 示例:(amount / 1e18) * rate。 中间步骤的除法会在乘法发生之前丢弃数据。 规则:务必先乘后除。

  2. 中间溢出 即使最终结果可以放入 uint256,先进行乘法也可能导致溢出。 使用像 OpenZeppelin Math 这样的库,通过一步操作完成全精度乘法和除法。

  3. 舍入方向错误 舍入不是一种建议,而是一条安全规则。 一个保守的协议应遵循以下原则:

  • 债务向上舍入(进位)。
  • 应付金额向上舍入。
  • 抵押品价值向下舍入(舍去)。
  • 向用户支付的资产向下舍入。
  • 向用户收取的份额向上舍入。

当无法获得精确结果时,应向试图提取价值的一方进行不利舍入。

  1. 通胀攻击 在流动性较低的金库中,攻击者可以利用捐赠来操纵汇率。他们通过捐赠资产来增加资产总数,而不增加份额总数。这会导致新的存款在舍入后变为零份额。 缓解措施:使用虚拟资产或份额来建立稳定的初始汇率。

  2. 频率攻击 如果利息每区块累积一次且向下舍入,攻击者可能会不断触发累积操作,使利息保持为零。 缓解措施:使用高精度指数或将余数保留到下一期。

安全的金融工程需要:

  • 明确的单位和小数位精度。
  • 全精度乘法和除法。
  • 针对特定操作的舍入规则。
  • 余数追踪。
  • 不变量测试和模糊测试。

不要只问计算结果是否足够接近。要问被舍弃的价值流向了哪里,以及由谁接收。

来源:https://dev.to/stablenaira/precision-loss-and-rounding-exploits-in-financial-smart-contracts-4c93