精度损失与舍入漏洞
智能合约并不一定需要访问控制漏洞才会导致资金损失。
有时,漏洞就隐藏在一个简单的除法运算中。
金融智能合约使用整数算术。小数部分会被舍弃。这种舍入方向决定了价值流向谁。一个单位的误差可能会在数千次交易中不断累积。
在金融协议中,舍入本质上是一种价值转移策略。
每次除法运算都必须回答三个问题:
- 计算向哪个方向舍入?
- 哪个方从该方向中获益?
- 攻击者能否重复或放大这种优势?
常见的数学错误包括:
过早进行除法 如果在乘法之前进行除法,你会丢失精度。 示例:
(amount / 1e18) * rate。 中间步骤的除法会在乘法发生之前丢弃数据。 规则:务必先乘后除。中间溢出 即使最终结果可以放入
uint256,先进行乘法也可能导致溢出。 使用像 OpenZeppelin Math 这样的库,通过一步操作完成全精度乘法和除法。舍入方向错误 舍入不是一种建议,而是一条安全规则。 一个保守的协议应遵循以下原则:
- 债务向上舍入(进位)。
- 应付金额向上舍入。
- 抵押品价值向下舍入(舍去)。
- 向用户支付的资产向下舍入。
- 向用户收取的份额向上舍入。
当无法获得精确结果时,应向试图提取价值的一方进行不利舍入。
通胀攻击 在流动性较低的金库中,攻击者可以利用捐赠来操纵汇率。他们通过捐赠资产来增加资产总数,而不增加份额总数。这会导致新的存款在舍入后变为零份额。 缓解措施:使用虚拟资产或份额来建立稳定的初始汇率。
频率攻击 如果利息每区块累积一次且向下舍入,攻击者可能会不断触发累积操作,使利息保持为零。 缓解措施:使用高精度指数或将余数保留到下一期。
安全的金融工程需要:
- 明确的单位和小数位精度。
- 全精度乘法和除法。
- 针对特定操作的舍入规则。
- 余数追踪。
- 不变量测试和模糊测试。
不要只问计算结果是否足够接近。要问被舍弃的价值流向了哪里,以及由谁接收。
来源:https://dev.to/stablenaira/precision-loss-and-rounding-exploits-in-financial-smart-contracts-4c93