autorenew
漏洞降临 #4:Solana AMM 交换中的香蕉与橙子混淆 —— u64 类型混淆的一课

漏洞降临 #4:Solana AMM 交换中的香蕉与橙子混淆 —— u64 类型混淆的一课

在区块链开发这个充满梗与百万美元交易的野蛮世界里,即便是最微小的代码失误也能把一次顺畅的交换变成滑坡。欢迎来到漏洞降临 #4——来自 Accretion 团队 的节日提醒:别把香蕉当成橙子,也别在你的 Solana 智能合约里把 base 货币当成 quote 资产。

如果你曾折腾过去中心化交易所(DEX),就知道 自动化做市商(AMM)是 Solana 上快速代币交换的引擎。但正如这条推文所指出的,交换逻辑里的一个狡猾 bug 可能让交易在未检查滑点的情况下通过,最终让交易者拿到比预期更少的代币。我们来用香蕉类比把它拆解一下。

漏洞:当 u64 掩盖了水果拼盘

相关代码处理了四种常见的 AMM 交换场景:

  • Buy ExactIn​:你指定精确的 quote 输入数量(比如 SOL),得到可变的 base 输出(你喜欢的 meme 币)。
  • Buy ExactOut​:你想要特定的输出数量,按需支付输入。
  • Sell ExactIn​:用 base 代币作为输入换取可变的 quote 输出。
  • Sell ExactOut​:固定的 quote 输出,base 输入可变。

乍一看,买入路径很稳当——计算清晰,对余额不足或数据无效有合适的错误处理。但把视角拉到 Sell ExactIn 路径,你会看到问题所在:滑点检查在比较 base 数量​quote 数量​​。

可以这么想:食谱要求 5 根香蕉,但你却在检查你是否有 5 个橙子。两者都是水果(或者在代码层面上,它们都是 u64 整数),所以比较不会报错。检查在不该通过的时候通过了,导致交换在远超预期的滑点下执行。糟糕——这会让交易者后悔。

下面是推文第一张图中有问题的代码片段一瞥:

Rust 代码片段,展示买卖交换逻辑中滑点检查的类型不匹配

第二张图更深入地展示了卖出端的后果:

详细的 Rust 代码,展示 sell exact in/out 路径,突出余额不足和滑点错误

没有编译期警告,也没有运行时崩溃——只有默默地失败。这个小妖精居然在 ​三次审计​ 中幸存下来。为什么?因为 Rust 的类型别名让 u64 在不同单位之间易容而不被察觉。

为什么这在 Meme 代币世界很重要

Meme 代币依赖 Solana 的速度和低手续费,驱动病毒式拉升和社区驱动的 DEX,比如 RaydiumOrca。但当像这样的交换 bug 潜伏时,会侵蚀信任。想象一个热门的新狗狗主题代币发布:交易者大额抛售、滑点未被检查,突然之间原本的噱头式暴涨变成了有点像 rug-pull 的感觉。对于正在构建下一个 PEPE 或 WIF 的区块链开发者来说,忽视单位安全不仅是马虎——它就是等待发生的资金流失。

解决方法:用 Newtypes 包裹起来

Accretion 的专业建议?别用普通的 u64 别名,改用 Rust 的 newtype structs​。它们是简单的包装器,能在编译时强制类型安全。像这样:

rust
#[derive(Debug, PartialEq)]
struct BaseAmount(u64);

#[derive(Debug, PartialEq)]
struct QuoteAmount(u64);

impl BaseAmount {
fn to_u64(&self) -> u64 { self.0 }
// Add ops like add, mul for safe arithmetic
}

现在,尝试把 BaseAmount(5)QuoteAmount(5) 比较?编译器会说不行——“mismatched types”。香蕉还是香蕉,橙子还是橙子。这是一个小改动,但在审计层面能带来巨大的回报。

这不仅是理论;这是 Solana 安全专家的实战建议。如果你在审计或发布 AMM,看看 Accretion 的服务——他们在招募顶级审计师并在 bug 咬人之前发现它们。

总结:给 Solana 开发者的果实教训

漏洞降临是个一年一度既节日又让人心惊的仪式,提醒我们连专业人士也会混淆单位。随着 meme 代币从玩笑演化为重磅项目,健壮的代码能让社区保持繁荣。有类似的血泪故事?在评论里分享吧——让我们一起为未来做审计。

保重,degens。记住:在智能合约里,精确不是可选项——它是利润与烂果肉之间的果皮。

你可能感兴趣