DeFiTuna借贷池被黑约57万美元:一个「空池子」如何骗过清算检查

取整归零的漏洞

2026-07-19 22:02

7月16日,Solana上的借贷协议DeFiTuna被 exploit,损失约56.96万枚USDC。安全公司CertiK把整条攻击链拆得很清楚:攻击者没有硬撬合约,而是造了一个几乎空的TUNA/USDC池子,把它变成借款流出后的「目的地」,再利用协议估值时的一个取整漏洞,让系统误以为这笔仓位「健康」,从而堂而皇之地把借出来的钱提走。

DeFiTuna事件概览
DeFiTuna事件概览

事情从一笔凌晨的交易开始。7月16日05:48左右,攻击者先建了一个几乎没有任何流动性的TUNA/USDC Fusion池,初始价格故意设得接近官方预言机价格,于是DeFiTuna上线前的「价格偏离检查」顺利过关。接着,他们在池子里挂了两个自己控制、价格刻在异常高位(tick 208,640)的限价单,合计只放了约0.001枚TUNA。

真正的杀招在估值函数里。 攻击者调用DeFiTuna的开放仓位指令,从借贷池借出约57万USDC,经由内嵌的Jupiter路由,把这笔钱 swap 进那个精心准备的薄池子,换回的TUNA少到可以忽略——精确算下来只有约0.000494枚。诡异的地方来了:DeFiTuna在 is_healthy() 里给仓位估值时,先按预言机价格算出约0.9077的数值,再用 to_num() 把正数定点值转成整数、直接丢弃小数部分,结果变成0。

攻击者构造的薄池与限价单
攻击者构造的薄池与限价单

因为「空仓位杠杆永远是1.0倍」这个隐含假设,总价值为0的仓位被系统判定为健康。 清算检查就这样被绕了过去。随后,那笔USDC在经济上已经属于两个恶意限价单,攻击者各自调用 DecreaseLimitOrder,分别提走约28.4万USDC。整个过程的脆弱点,就藏在 compute_total_and_debt() 第53行那个「向下取整」里。

资金很快被分散到多个跳转钱包,最后归集到两个主地址,分别持有约38.3万和18.4万美元,再经由Mayan跨链桥从Solana转到以太坊。在以太坊上,140枚ETH被存进隐私工具Railgun,另有约30万枚DAI留在钱包里。

USDC经Jupiter路由换入薄池的swap路径
USDC经Jupiter路由换入薄池的swap路径

这类漏洞的可怕之处在于,它不靠「偷私钥」,而是利用协议自己写的数学假设。当一处四舍五入能把资产总值归零,再聪明的预言机也救不了清算逻辑。 对做借贷、做机枪池的团队来说,任何「先乘后取整」「空仓默认健康」的写法,都该在审计时当作头等风险来拆——DeFiTuna这57万美元,买的就是一个教训。