Balancer漏洞分析
一、相关模块:
1)batchSwap
Balancer Vault中,batchSwap提供了类似Uniswap V4的任意组合交换——只在交易完毕时进行结算。
代币可在过程中被增发任意数量,而用户只需对最后的结算结果付款
2)Composable Pools(可组合池)
底层资产(如peg)相似的LST代币可在Composable Pool互换,交换比率取决于原线性池中「LST和底层资产数量的比值」。{底层资产/LST} 越大,该LST在组合池中的价值越高。
3)线性池
Balancer 的线性池在交易时会向上取整amount in,向下取整amount out。
当池的Virtual supply为零,池会进行初始化,此时LST代币与底层资产1:1兑换。
(Virtual supply=totalSupply-线性池balance
其中Virtual supply为LST代币实际发行量,totalSuppy为定值,线性池balance代表预增发量)
二、可用攻击向量
1)BatchSwap的“增发”机制:LST代币可在交易过程中被铸造出能填满Virtual supply的数量,为初始化线性池提供条件。
2)线性池的取整机制:使用LST兑换底层资产,向下取整的amount out可让线性池兑换比例失衡,且在线性池原有资产比例悬殊时失衡尤为显著。
失衡表现:{底层资产/LST}偏大
3)组合池的兑换比例机制:根据可组合池特点,抬高某一LST的价格可以以折扣价兑换到其他LST
三、主要流程:
1.第一笔swap(usdc线性池):以“增发”的USDC BPT(上文LST)兑换了线性池内的绝大部分usdc
2.第二笔swap(usdc线性池):构造一笔交易,其amount out被取为0。线性池{底层资产/LST}因取整机制变得极大
3.第三笔swap(组合池),组合池内的DAI/USDT BPT以低价被USDC BPT换出
4.第四笔swap(usdc线性池):向线性池注入USDC BPT,使VirturalSupply=0,初始化线性池
5.第五笔swap(usdc线性池):以1:1的比例使用USDC换出USDC BPT,偿还“增发”贷款
第五步是必须的:USDC的精度低于USDC BPT,舍入造成的线性池平衡倾斜是单向的,只有第五步才能提供足量的USDC BPT,同时保留DAI/USDT BPT
四、联想
在zkLend攻击中,攻击者事先让lending_accumulator的值变得极大,再利用舍入机制以较少数量的wstETH兑换较多的wstETH。
zkLend的舍入均向下取整(核心payload),Balancer Liner pool也存在相同的问题,但Balancer攻击者走的不是这条路径
具体实现为:
1.以 1 >的利率“借入”BPT(flashloan),并将其交易为 main 和 wrapped,以将代币余额减少到接近零。
2.制作一笔交易,利用 GivenOut swap的四舍五入误差,使总余额等于虚拟供应量,从而将汇率重置为 1(因为汇率 = 余额/供应量)。
3.以新的较低利率偿还swap借的 BPT 以获得利润
五、参考
https://slowmist.medium.com/review-and-recommendations-of-balancer-incident-d2b31b5bd863