{"content":{"title":"收益聚合器的常见陷阱：Beefy 案例研究","body":"作者：Daniil Ogurtsov - MixBytes的安全研究员\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/29.jpg)\r\n\r\n在本文中，我们将概述在收益聚合器中遇到的安全问题，这是DeFi中非常常见的一类项目。自行业诞生以来，它们已经走过了一段漫长的道路，并积累了丰富的安全技术和最佳实践经验。\r\n\r\n本文旨在描述特定于收益聚合器的bug。由于它们具有独特的背景，因此安全审计可更详细和深入地考虑这些特点。额外的分析框架可以帮助发现更复杂的bug。\r\n\r\n## 收益聚合器如何工作\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/RdmRsnt.png)\r\n\r\n来源：[https://arxiv.org/pdf/2210.04194.pdf](https://arxiv.org/pdf/2210.04194.pdf)\r\n\r\nDeFi项目通常需要大量的流动性来运作。流动性在行业中是有限的，项目竞争吸引流动性。因此，DeFi项目设计用以激励流动性提供者——以费用或代币铸造的形式。这些奖励取决于用户在这些DeFi项目中的活动，因此流动提供者的回报是波动的。\r\n\r\n收益聚合器项目“聚合”了一些流动性提供者的选项，并提供一些额外的特性和工具：\r\n\r\n1. 他们构建“策略”——专门的智能合约，负责：\r\n\r\n- 确定收益将如何生成（在哪里、如何以及以哪种代币）\r\n- 将流动性交付到最终生成回报的智能合约\r\n- 提取并传递流动性回流动性提供者\r\n- 修改风险/回报特征（例如，通过折叠利用杠杆获取更多风险/回报）\r\n- 通过特殊的交易流最大化回报（以收取更多奖励的额外代币）\r\n- 优化回报交付（例如逐步出售奖励代币）\r\n- 考虑特殊情况（清算风险、紧急提款）。\r\n\r\n2. 他们以增长为导向运作。收益聚合器通常选择不承担不可永久性损失风险，并避免出现负回报的情况。因此，投资通常以LP代币的形式接受。在某些情况下，收益聚合器可能会提供单边存款的额外选项——有时可用于大流动性稳定币池（例如Curve上的稳定交换池）。\r\n\r\n3. 他们进行复利——奖励被每小时/每日再投资以提升进一步回报。这是大多数用户使用收益聚合器的主要原因。对所有流动性提供者同时在一次交易中再投资更为有效——在大多数项目中，这被称为“收割”。然而，这不仅仅是再投资，也是某些代理在积极回报时收取费用的时刻（策略构建者、收益聚合器本身、收割功能调用者）。\r\n\r\n上述特征是任何收益聚合器的基础，但推广的产品可能有所不同。其中一些以收益聚合作为核心工具（如Yearn Finance、Beefy Finance），其他可能将其他产品推向用户，而将收益生成本身视为次要（如OUSD提供稳定币或Idle以分期的形式提供固定或杠杆利率）。这些特殊产品的转变将从我们的分析中排除。\r\n\r\n## 主要安全分析原则\r\n\r\n我们看到收益聚合器的两个基本组成部分使得安全分析变得特殊。\r\n\r\n1) 通常它们有许多金库/策略——它们的设计和风险可能显著不同。\r\n\r\n收益聚合器更愿意为其金库/策略的安全负责。因此，收益聚合器设计了内部审计、测试、监控的流程，以便在上线前对策略进行充分分析。此外，他们邀请外部策略构建者并激励他们扩展金库/策略的市场。\r\n\r\n这与大多数DEX的情况不同，DEX中的对之间共享同一个智能合约，但可以有不可预知的代币被交易。DEX团队仅构建智能合约标准，但通常不对交易对中的代币负责。\r\n\r\n相比之下，收益聚合器的金库/策略很少标准化——它们有不同的交易流、连接的DeFi项目和转移的代币。因此，更广泛的坏场景可能会出现。让外部审计人员分析一些金库（尤其是核心的）是一种正常的做法。\r\n\r\n2) 独特的信任假设集。\r\n\r\n金库有策略构建者和管理者。他们具有某些特权功能旨在有利于流动性提供者。但这些所有者可能是潜在的恶意行为者。因此，审计人员必须明确将所有者视为等待机会利用其特权的攻击者。\r\n\r\n## 常见安全陷阱总结\r\n\r\n操作会被操控的股份与基础代币之间的转换率\r\n\r\n股份与接受的代币之间的转换是许多DeFi项目的痛点。错误的计算很容易被利用。\r\n\r\n收益聚合器在这里并没有太大区别——它们通常铸造代币，Beefy Finance对此的描述非常准确“具有利息的代币化存款证明”。用户的余额并不会随着赚取的更多奖励而上升，但一个股份应该随着计入的奖励而代表越来越多的基础代币。这个转换率是动态的，可以被利用。\r\n\r\n费率计算往往使用预言机或DEX。过度使用DEX是脆弱性的核心所在。这正是攻击者在黑客攻击最大的收益聚合器时所利用的地方。攻击者的目标是降低股份的转换率并提高后者的转换率。\r\n\r\n对于分析的一般建议与许多使用DEX进行记账的项目相同——假设DEX可以在同一交易中设置为任何价格。如果能够在同一交易中使用不同的转换率进行存款和取款，则表明存在红旗。\r\n\r\n依赖DEX可能有不同的形式。考虑PancakeBunny黑客（[漏洞分析链接](https://learnblockchain.cn/article/12428)），该黑客向存款人收取每1 BNB收取3个BUNNY代币作为费用。然而，回报是以LP代币计算并需要转换为以BNB计价，而PancakeBunny在这一转换中犯了错误，这导致攻击者进行递归操控BUNNY铸造。\r\n\r\n未能防护三明治攻击的交换\r\n\r\n策略广泛使用交换。它们通常不只是想赚取协定费用；它们尝试最大化以额外代币获取的额外激励，如PancakeSwap为相关池的流动性提供额外CAKE交换。这些额外奖励从来不会长时间累积——策略在每次收割时会立即在DEX上进行交换。\r\n\r\n攻击者可以利用这些以可预测的方式卖出代币的交易。他们进行三明治攻击，以增加金库的滑点并获得无风险的代币回报。\r\n\r\n同样的问题出现在接受不同代币投资的金库中。金库在一开始会交换这些代币以获得用于生成收益的LP。\r\n\r\n这里的建议很直接——控制交换中的风险容忍度，包括交换后最低接收代币的不变条件。\r\n\r\n来自所有者的攻击\r\n\r\n如前所述，最佳实践是将金库所有者/管理者视为恶意行为者。他们通常与收益聚合器团队没有关系。\r\n\r\n这里有一些所有者/管理者通常可用的攻击向量：\r\n\r\n- 当前的金库/策略函数允许任意调用；\r\n- 当一个金库允许更改策略时。当之前的策略变得无效且需要更新时。有许多收益聚合器具有这一功能。这对所有方都非常方便，否则更新将需要从每一个流动性提供者那里提款。结果是，新版本可能会为所有者引入额外的隐藏权利；\r\n- 通过技巧人为提升管理人员的奖励/费用。\r\n\r\n代币特定风险\r\n\r\n对于许多收益聚合器，覆盖的活跃策略数量可以达到十个或数十个——受影响的项目集和传输的代币集独特。\r\n\r\n偏离可预测ERC-20标准的多样化代币可能引入额外的漏洞向量。这在许多DeFi项目中都是这样的，但在这里，情况控制得更少，因为收益聚合器自身的性质暗示着场景的多样性，这使得出现不寻常的代币被认为是可能的。\r\n\r\n所有类型的不寻常代币对于策略都是风险——通货膨胀/通货紧缩、重置、带息、可钩、具有奇怪的小数位、在函数调用时不返回任何值。这就是为啥在分析策略时特别关注代币。\r\n\r\n这也是审计人员建议在所有关键功能上添加nonReentrant修饰符的原因——以消除意外钩子的风险。这是非常简单但极其有效的。\r\n\r\n不良的余额管理\r\n\r\n有时奖励的计算是错误的。有些奖励代币可能会被忽视，或者被阻塞在某些智能合约中。奖励值得进行强有力的测试，因为有许多容易出错的地方。\r\n\r\n糟糕的金库生命周期设计\r\n\r\n糟糕的金库设计可能低估金库出现的坏场景。有些只意味着存款和取款展示完整的生命周期。这显然不是真的。金库必须与更广泛的风险特征一起运作，必须设计风险缓解程序。产生收益的池可以被黑客攻击，借贷协议上的头寸可以被清算等。\r\n\r\n团队必须检查是否嵌入特殊功能供所有者/管理者处理此类情况（暂停、紧急提款、管理流动性头寸和杠杆/折叠）。\r\n\r\n值得注意的是，这是最难分析的主题之一，因为这不仅需要理解代码，还需要了解什么时候出错可能发生的各种场景。\r\n\r\n* * *\r\n\r\n在接下来的案例研究中，我们将以一个简单的金库为例，尝试从这些攻击向量的角度进行分析。\r\n\r\n## 案例研究：评估Beefy Finance\r\n\r\n在这里，我们将描述Beefy Finance金库以及它们如何处理攻击向量。\r\n\r\n我们的例子是CAKE-BNB LP金库。\r\n\r\n[https://app.beefy.finance/vault/cakev2-cake-bnb](https://app.beefy.finance/vault/cakev2-cake-bnb)\r\n\r\n下面是该金库的智能合约系统示意图，包括资金流动。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n这个Beefy金库关系到五个合约，其中三个是Beefy编写的：Vault、Strategy、BoostStaker。每个合约都有各自的角色。\r\n\r\nVault - 负责与用户的交互（接收LP和发送增长的LP）。每次存款都会铸造股份，每次提款都会销毁股份。这个合约是ERC20的，因此股份像普通代币一样可转让。金库是股份与LP之间转换逻辑的关键点。\r\n\r\n[https://bscscan.com/address/0xb26642B6690E4c4c9A6dAd6115ac149c700C7dfE](https://bscscan.com/address/0xb26642B6690E4c4c9A6dAd6115ac149c700C7dfE)\r\n\r\nStrategy - 管理代币转移的整体逻辑。收割在这里进行——它应该1) 再投资增长的LP和2) 将以其他代币形式获得的奖励进行销售，在DEX上出售以获得token0和token1，将它们存入DEX交易对以将其转换为更多的LP。\r\n\r\n[https://bscscan.com/address/0xDE238C509bcCBCd91B90dE40dF3e25B43A131311](https://bscscan.com/address/0xDE238C509bcCBCd91B90dE40dF3e25B43A131311)\r\n\r\nBoostStaker - 是一个中间合约，旨在通过将其一部分发送到veContract（如果该代币存在并且包括在策略中）来提升获得的代币奖励。这个Beefy策略使用了BoostStaker但没有将代币发送到veContract - 因此附加奖励实际上并没有进行耕作。\r\n\r\n[https://bscscan.com/address/0xd7c0c12c91750a6ef37580d44b0fd6af1068e615#code](https://bscscan.com/address/0xd7c0c12c91750a6ef37580d44b0fd6af1068e615#code)\r\n\r\nMasterChef - 一个来自PancakeSwap的合约，接收LP，LP必须来自白名单，通常来自于一侧为CAKE代币的对。MasterChef持有约100万美元的CAKE余额并将其分配给LP的存款者。这是项目激励流动性提供的知名工具。这是策略中CAKE的来源。\r\n\r\n[https://bscscan.com/address/0xa5f8c5dbd5f286960b9d90548680ae5ebff07652#code](https://bscscan.com/address/0xa5f8c5dbd5f286960b9d90548680ae5ebff07652#code)\r\n\r\nDEX - 策略并不评估CAKE代币的回报。为了不与其打交道，现金流中每个CAKE都会在DEX出售以获得更多的LP。\r\n\r\n[https://bscscan.com/address/0x10ed43c718714eb63d5aa57b78b54704e256024e](https://bscscan.com/address/0x10ed43c718714eb63d5aa57b78b54704e256024e)\r\n\r\n有时赚取的铸造代币（如我们例子中的CAKE）可以通过添加时间锁抵押到veContract以获得额外的铸造分发（BoostStaker模块）。但对于这个CAKE-BNB LP金库来说并不适用。\r\n\r\n让我们逐个检查一些常见的攻击向量，并寻找一些论据来证明该金库在攻击中是安全的。\r\n\r\n向量一：被操控的股份与基础之间的转换率\r\n\r\n我们将展示一个简单的框架来分析转换率。我们将检查攻击者是否无法提取超过存入的金额。\r\n\r\n步骤如下：\r\n\r\n1. 找出转换发生的函数；\r\n2. 将转换分解为可理解的公式；\r\n3. 分析每个元素在公式中的表现，检查攻击者是否有选项去操控这些元素。操控任何元素意味着操控整个公式的返回值，从而操控转换率。\r\n\r\n处理这个问题的主要合约是Vault。\r\n\r\n这是存入/提取函数的代码。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n让我们将其分解为更简单的公式。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n这些公式来自代码，旨在单独说明所有组件。某些行涉及到通货紧缩代币的风险（代币在传输过程中可能会丢失）。我们在公式中保留这一部分。\r\n\r\n此外，你可能从代码中注意到，函数withdraw()还额外检查了Vault合约上的b - LP余额。目前我们将其忽略，但稍后在分析其他向量时将重新提及。我们找到了有趣的数学错误。\r\n\r\n我们将集中在每个公式元素上，估计攻击者操控某个元素数字的可能性。同时，我们假设攻击者拥有无限资金并可以随时闪贷。攻击者的目标是提升\\[shares per LP\\]（每个LP的股份）在存入时增加，并降低\\[share per LP\\]（每个LP的股份）在提款时减少——这有可能让他们提取超过存入的资金（但不一定）。\r\n\r\n现在让我们分析所有的元素：\r\n\r\n1. 已铸造股份总额\r\n\r\n该参数在任何代币移动之前计算，攻击者无法通过其他函数铸造/销毁股份。此外，该参数作为合约变量存储，无需调用即可计算。\r\n\r\n因此，这个元素是被保护的。\r\n2. Vault的LP余额 + Strategy的LP余额 + MasterChef上累积的LP\r\n\r\n这些参数容易被提升——攻击者可以向这些合约发送代币，但这并不意味着会有什么危险。首先，攻击者无法撤回这些发送的代币。其次，在我们的情况中，攻击者提升了\\[shares per LP\\]，但这些操控的收益少于平衡提升的成本。想象一下，提供100个股份，余额中有200个LP代币，转换率为0.5。首先，攻击者以当前费率存入100个LP代币。现在我们有150个股份和300个LP代币。然后，攻击者直接向余额发送150个代币。转换率变成150 /450 = 0.25。是的，攻击者成功地降低了\\[shares per LP\\]，但这样的攻击不会带来利润。攻击者提取50个股份，但获得了450 \\*50 /150 = 150个LP代币，尽管花费是100个LP代币（存款）和150个代币（直接提升余额）。\r\n\r\n因此，这个元素没有保护，但也不脆弱。\r\n3. 传输过程中丢失的LP百分比\r\n\r\n在这里，金库试图处理通货紧缩代币。\r\n\r\n这个元素是被保护的，攻击者通常无法在一笔交易中影响此参数，但对于重置代币某些操控是可能的。攻击者可以进行余额更新交易的抢跑交易，进而使同一序列的交易具有不同的转换率。然而，必须指出的是，收益聚合器优先不与重置代币打交道（像许多DeFi项目一样）。\r\n\r\n因此，公式是防止攻击的。我们可以从中得出什么教训？\r\n\r\n1. 大多数数字在任何代币移动之前都被获得。\r\n2. 它很简单。\r\n3. 没有获取价格数据并且较少读取外部合约。\r\n4. 存款和提款的公式是相同的。\r\n\r\n最后的话，在这里，你可能注意到这些公式并不完全相同。问题就在于传输过程中丢失的LP百分比。在存款中是乘法，而在提款中是除法。但在通货紧缩代币的背景下这没有问题。用户的损失是永远存在的：在存款时收到更少的股份，在提款时需要更多的股份。因此，这里的公式偏差是必要的。\r\n\r\n向量二：未防止三明治攻击的交换\r\n\r\n对于收益聚合器，有两个常见的地方存在不受保护的交换：\r\n\r\n1. 金库外部：存款和提款的代币转换。\r\n2. 金库内部：收割或其他操作的代币转换。\r\n\r\n让我们来观察我们选择的CAKE-BNB金库的这两个区域。\r\n\r\n存款和提款时的代币转换\r\n\r\n从界面页面可以看到，这个金库允许存入和提取多个代币。\r\n\r\n[https://app.beefy.finance/vault/cakev2-cake-bnb](https://app.beefy.finance/vault/cakev2-cake-bnb)\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n但是，金库合约仅接受一种代币类型——LP。\r\n\r\n因此，转换在某些外部合约中发生。\r\n\r\n这是Beefy描述的交易流。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n这是这样的交易的示例。\r\n\r\n[https://dashboard.tenderly.co/tx/bsc/0x68d7210daadbf31c06a84fb9fe5d1b5ad15c8d9a00cc8b9de52119510119d5c0/debugger](https://dashboard.tenderly.co/tx/bsc/0x68d7210daadbf31c06a84fb9fe5d1b5ad15c8d9a00cc8b9de52119510119d5c0/debugger)\r\n\r\n从交易中，我们导出了处理交换的合约。\r\n\r\n[https://bscscan.com/address/0x10ab57c5889a00c497ce6be7ce142bb9a613e362#code](https://bscscan.com/address/0x10ab57c5889a00c497ce6be7ce142bb9a613e362#code)\r\n\r\n此处的交换通过DEX路由器经过每个地方实现AmountOutMin——该参数在交易初始化时以数据输入，因此是离线计算的。交易示例如证实该金额不是默认设置为零。这足以减轻三明治攻击的风险。\r\n\r\n收割或其他操作时的代币转换\r\n\r\n策略合约是处理这些交换的合约。在我们的策略中，交换用于转换从MasterChef获得的CAKE代币作为奖励。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n如你所见，此处AmountOutMin被设置为零。因此，在发生重大滑点交换的情况下，它在前置运行中是脆弱的。但上下文是，在这里发生重大滑点交易的可能性不大——池的规模远大于平均CAKE收割的数量。此外，收割可以频繁发生，因为金库在Binance智能链上运行——这降低了在一笔交易中发生大量CAKE收割的可能性。\r\n\r\n向量三：来自所有者的攻击\r\n\r\n我们的CAKE-BNB金库使用Beefy标准来设置角色特权——所有金库是相同且相当安全的。\r\n\r\n向量四：代币特定风险\r\n\r\n在我们的金库中，代币相当常见且没有额外的风险。\r\n\r\n向量五：不良的余额管理\r\n\r\n金库处理简单代币，但保留了某些代码来减轻通货紧缩代币传输可能出现的意外情况。在我们的金库中并不存在这样的情况，但作为标准，它的代码会从策略迁移。代码应用余额检查，因此只有实际收到的代币才被计算。\r\n\r\n我们发现了一个微小的错误，这可能导致对股东的错误提款计算。此情况看起来不严重，但有趣的是这是如何通过设计而可能的。\r\n\r\n问题出现在这个金库函数中，以及它的用法。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n此函数计算总的金库代币，并用来计算\\[share per LP\\]。它总结了Vault、Strategy上的LP余额和MasterChef上的累积LP代币。\r\n\r\n必须满足两个条件：\r\n\r\n1. 金库和策略合约上有大量代币。\r\n2. LP是个通货紧缩代币（代码试图处理这些情况）。\r\n\r\n在这种情况下，股东的提款将不正常。\r\n\r\n回想一下这个函数。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n让我们设想一个简单的场景。\r\n\r\n我们有铸造的100个股份，两位股东各50。\r\n\r\n我们从balance()函数返回200个LP代币，合约之间的分配为：\r\n\r\n1. Vault中50\r\n2. Strategy中50\r\n3. MasterChef中100\r\n\r\n让我们应用传输时1%的燃烧率以处理通货紧缩代币。\r\n\r\n想象一下第一个股东提取50个股份。\r\n\r\n根据withdraw()函数，该股东将提取98.5个代币。\r\n\r\n当第二个股东提取50个股份时，他们将获得96.05个代币。\r\n\r\n结果是，他们持有相同数量的股份，但提取的LP代币不同。\r\n\r\n这是如何发生的？\r\n\r\n每个合约都从链中的下一个合约提款。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n如果Vault合约拥有一些LP代币的余额，则它不会从Strategy中提款。Strategy也是如此——它试图优先以自身的资金支付，然后再撤回BoostStaker。依此类推。\r\n\r\n“更深”合约余额中的LP代币在通货紧缩代币的情况中变得更昂贵。\r\n\r\n应用1%的烧毁率以传输，MasterChef上的100个LP代币将在到用户钱包时需要进行4次传输，最终仅剩下96.05。\r\n\r\n因此，第一位股东提取了“更便宜”的代币，这种转移的最小成本。\r\n\r\n而第二位股东留下了“更贵”的代币，将在提取时经历4次传输。\r\n\r\n![](https://img.learnblockchain.cn/2025/03/09/picture.png)\r\n\r\n在withdraw()函数中，关键参数r依赖于balance()函数。该函数累计三个余额组件，每个组件有效值不同。\r\n\r\n对于通货紧缩代币，将不同合约上的代币余额相加是不正确的，因为它们需要不同数量的转移。\r\n\r\n向量六：不良的金库生命周期设计\r\n\r\n这个向量更适用于更复杂的策略。在我们的CAKE-BNB金库中，一切都是直接的。尽管如此，金库遵循内部标准并具有紧急功能。\r\n\r\n## 控制风险的内部流程\r\n\r\n一些收益聚合器采用内部程序来评估金库和策略。\r\n\r\nYearn通过许多步骤和高风险评分引入策略：\r\n\r\n[https://docs.yearn.finance/resources/risks/risk-score#strategy-risk-score](https://docs.yearn.finance/resources/risks/risk-score#strategy-risk-score)\r\n\r\n同样，Beefy Finance也适用：\r\n\r\n[https://docs.beefy.finance/safu-protocol/beefy-safety-score](https://docs.beefy.finance/safu-protocol/beefy-safety-score)\r\n\r\n## 总结\r\n\r\n收益聚合器处理DeFi中可能发生的整个情况集。因此，审计人员必须特别关注金库的安全分析及其特殊向量。\r\n\r\n我们只描述了最著名的安全问题，这些都是由收益聚合器特有的。显然，这里的所有智能合约漏洞都可能存在，并且具有破坏性。\r\n\r\n- 谁是MixBytes？ \r\n\r\n[MixBytes](https://mixbytes.io/) 是一支由专家区块链审计员和安全研究员组成的团队，专注于为兼容EVM和基于子战略的项目提供全面的智能合约审计和技术咨询服务。请在[X](https://twitter.com/MixBytes)上关注我们，以保持对最新行业趋势和见解的关注。\r\n\r\n>- 原文链接： [mixbytes.io/blog/yield-a...](https://mixbytes.io/blog/yield-aggregators-common-pitfalls)\r\n>- 登链社区 AI 助手，为大家转译优秀英文文章，如有翻译不通的地方，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/24680","address":null},"history":null,"timestamp":1741495804,"version":1}