<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>ACai</title>
        <link>https://paragraph.com/@acai</link>
        <description>undefined</description>
        <lastBuildDate>Sat, 08 Aug 2026 07:30:48 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>ACai</title>
            <url>https://storage.googleapis.com/papyrus_images/455cfa4b3c9dc8cd3ec6cc16605f904252936f1179d09e7758d0fb9563ec0c29.png</url>
            <link>https://paragraph.com/@acai</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[HPAY 攻击事件分析 ]]></title>
            <link>https://paragraph.com/@acai/hpay</link>
            <guid>oHAGOxTvSt1Mx7b7aRcb</guid>
            <pubDate>Wed, 09 Nov 2022 03:17:04 GMT</pubDate>
            <description><![CDATA[背景分析文档目录：contract ├─autocompound │ AutocompundStaking.sol │ ├─base │ BaseStaking.sol │ MintableSupplyStaking.sol │ TaxedStaking.sol │ ├─lib │ StakingUtils.sol │ ├─presets │ MintableAutoCompundRelockBonus.sol │ └─timelock FixedTimeLockStaking.sol RelockBonusStaking.sol StaticFixedTimeLockStaking.sol 更多信息： https://wooded-meter-1d8.notion.site/0e85e02c5ed34df3855ea9f3ca40f53b?v=22e5e2c506ef4caeb40b4f78e23517ee&p=d4489312830a40819dbfc3ec1fb4246c&pm=s漏洞分析setTokenMintableAutoCompundRelockBonus.setT...]]></description>
            <content:encoded><![CDATA[<h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">背景分析</h1><p>文档目录：</p><pre data-type="codeBlock" text="contract
├─autocompound
│      AutocompundStaking.sol
│
├─base
│      BaseStaking.sol
│      MintableSupplyStaking.sol
│      TaxedStaking.sol
│
├─lib
│      StakingUtils.sol
│
├─presets
│      MintableAutoCompundRelockBonus.sol
│
└─timelock
        FixedTimeLockStaking.sol
        RelockBonusStaking.sol
        StaticFixedTimeLockStaking.sol
"><code>contract
├─autocompound
│      AutocompundStaking.sol
│
├─<span class="hljs-keyword">base</span>
│      BaseStaking.sol
│      MintableSupplyStaking.sol
│      TaxedStaking.sol
│
├─lib
│      StakingUtils.sol
│
├─presets
│      MintableAutoCompundRelockBonus.sol
│
└─timelock
        FixedTimeLockStaking.sol
        RelockBonusStaking.sol
        StaticFixedTimeLockStaking.sol
</code></pre><p>更多信息：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://wooded-meter-1d8.notion.site/0e85e02c5ed34df3855ea9f3ca40f53b?v=22e5e2c506ef4caeb40b4f78e23517ee&amp;p=d4489312830a40819dbfc3ec1fb4246c&amp;pm=s">https://wooded-meter-1d8.notion.site/0e85e02c5ed34df3855ea9f3ca40f53b?v=22e5e2c506ef4caeb40b4f78e23517ee&amp;p=d4489312830a40819dbfc3ec1fb4246c&amp;pm=s</a></p><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">漏洞分析</h2><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e80f30f32ace342f4ed15ea288142bf18d706d6ecb408692b495d67b8e641a7f.png" alt="setToken" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">setToken</figcaption></figure><p><code>MintableAutoCompundRelockBonus.setToken</code> 函数功能权限设置不当，任意用户可以修改结构体 <code>configuration</code> 中的 <code>stakingToken</code> 与 <code>rewardsToken</code> 参数。</p><pre data-type="codeBlock" text="struct StakingConfiguration {
    uint256 rewardRate;
    uint256 startTime;
    uint256 minStake;
    uint256 maxStake;
    ERC20 stakingToken;
    ERC20 rewardsToken;
}
"><code>struct StakingConfiguration {
    uint256 rewardRate<span class="hljs-comment">;</span>
    uint256 startTime<span class="hljs-comment">;</span>
    uint256 minStake<span class="hljs-comment">;</span>
    uint256 maxStake<span class="hljs-comment">;</span>
    ERC20 stakingToken<span class="hljs-comment">;</span>
    ERC20 rewardsToken<span class="hljs-comment">;</span>
}
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">攻击过程</h2><ul><li><p>创建一个 <code>fakeToken</code>；</p></li><li><p>调用 <code>setToken</code> 函数将 <code>stakingToken</code> 与 <code>rewardsToken</code> 设为攻击者创建的 <code>fakeToken</code>；</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e80f30f32ace342f4ed15ea288142bf18d706d6ecb408692b495d67b8e641a7f.png" alt="setToken " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">setToken</figcaption></figure><ul><li><p>调用 <code>stake</code> 函数，向 <code>MintableAutoCompundRelockBonus</code> 合约转入 <code>fakeToken</code>。此时 <code>_balances[msg.sender]</code> 将会记录攻击者存入的 <code>fakeToken</code> 数量；</p></li></ul><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b4c8d4cc0a469c4918e46832d5a565ad52faa10c2ba9f0fa7cb938520b6324c3.png" alt="stake " blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">stake</figcaption></figure><ul><li><p>调用 <code>setToken</code> 函数将 <code>stakingToken</code> 与 <code>rewardsToken</code> 设为 <code>HPAY</code>；</p></li><li><p>调用 <code>withdraw</code> 函数，从 <code>MintableAutoCompundRelockBonus</code> 合约转出 <code>HPAY</code> 。此时合约根据先前步骤 <code>3</code> 中存入 <code>fakeToken</code> 所记录的 <code>_balances[msg.sender]</code> 进行提款操作，实际提出的是 <code>HPAY</code>。</p></li></ul>]]></content:encoded>
            <author>acai@newsletter.paragraph.com (ACai)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9805065d183b235cea40a0cc352f4c16f9a85899e5d8580f428f5c2e29cf9fe6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[KaoyaSwap 攻击事件分析]]></title>
            <link>https://paragraph.com/@acai/kaoyaswap</link>
            <guid>0VhjZKRJb7IviytEpRnt</guid>
            <pubDate>Sun, 28 Aug 2022 12:22:24 GMT</pubDate>
            <description><![CDATA[相关信息KaoyaSwap 是 BSC 链上的一个自动做市商 AMM。然后，现在他们的官网 https://www.kaoyaswap.com/ 已经打不开了（如果我打开方式没错的话）。所以就直接进行攻击事件的分析吧。 攻击交易：https://bscscan.com/tx/0xc8db3b620656408a5004844703aa92d895eb3527da057153f0b09f0b58208d74 攻击者在进行攻击之前，自己构建了两个代币协助完成攻击，下面将他们分别称为 TA 和 TB 。 TA address：0x74eF69Defe8bae1Fe660fB93265FC1bc79c9bDa8 TB address：0xD84379C4eeA25d05574f9F0B99E3Bf73500Ca4B4交易流程因为攻击是发生在 AMM 上的，所以我们可以根据代币的流向先大概分析一下攻击者在这笔交易中都做了些什么，看看能不能看出有什么奇怪的地方。下面绿色框图是 Tokens Transferred 的内容，红色框图的是 Internal Txns 的内容。(1) 首先闪电贷 ...]]></description>
            <content:encoded><![CDATA[<h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">相关信息</h1><p>KaoyaSwap 是 BSC 链上的一个自动做市商 AMM。然后，现在他们的官网 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.kaoyaswap.com/">https://www.kaoyaswap.com/</a> 已经打不开了（如果我打开方式没错的话）。所以就直接进行攻击事件的分析吧。</p><p>攻击交易：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bscscan.com/tx/0xc8db3b620656408a5004844703aa92d895eb3527da057153f0b09f0b58208d74">https://bscscan.com/tx/0xc8db3b620656408a5004844703aa92d895eb3527da057153f0b09f0b58208d74</a></p><p>攻击者在进行攻击之前，自己构建了两个代币协助完成攻击，下面将他们分别称为 TA 和 TB 。 TA address：0x74eF69Defe8bae1Fe660fB93265FC1bc79c9bDa8 TB address：0xD84379C4eeA25d05574f9F0B99E3Bf73500Ca4B4</p><h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">交易流程</h1><p>因为攻击是发生在 AMM 上的，所以我们可以根据代币的流向先大概分析一下攻击者在这笔交易中都做了些什么，看看能不能看出有什么奇怪的地方。下面绿色框图是 Tokens Transferred 的内容，红色框图的是 Internal Txns 的内容。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fef8c1f37e16dc1e6b05e2da4ef1e0f8b213ea7b0856e3225a11ef45979afa94.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>(1) 首先闪电贷 1800 BNB</p><p>(2) 调用 swapExactTokensForTokens 函数，用 672 BNB 换出 125023 KY</p><p>(3) 调用 swapExactTokensForTokens 函数，用 100 BNB 换出 6666 BUSD</p><p>(4) 调用 addLiquidity 函数，添加 1026 BNB 和 50 TA，获得 226 KALP 流动性代币</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/242b014057ce5f071089c2c17aa3297a93f350ad0ec8db04995c198a9f166feb.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>(5) 调用 addLiquidity 函数，添加 1 BNB 和 1 TB，获得 0.9 KALP 流动性代币</p><p>(6) 调用 addLiquidity 函数，添加 1 TA 和 1 TB，获得 0.9 KALP 流动性代币</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/395560e161d76d4cdf5d8748e20d8acec5811e79c6f688c965ce481e5eb898fc.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4aac254e417fcf55f68488e8e1e83514ce39bf66a8462b02efb2ffad052bf9db.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>(7) 调用 swapExactTokensForETHSupportingFeeOnTransferTokens 函数，其中 path 参数为 <code>[TA, WBNB, TB, TA, WBNB]</code> 的地址。这个函数还涉及到 BNB 的转账，但是函数 Output 中没有体现。（剧透一下，转出了 1019 BNB 给攻击地址。具体情况后面的代码分析会解释）。</p><pre data-type="codeBlock" text="Input：
 &quot;amountIn&quot;: &quot;8000000000000000000000&quot;,
 &quot;amountOutMin&quot;: &quot;1&quot;,
 &quot;path&quot;: [
    &quot;0x74ef69defe8bae1fe660fb93265fc1bc79c9bda8&quot;,
    &quot;0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c&quot;,
    &quot;0xd84379c4eea25d05574f9f0b99e3bf73500ca4b4&quot;,
    &quot;0x74ef69defe8bae1fe660fb93265fc1bc79c9bda8&quot;,
    &quot;0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c&quot;
 ],
 &quot;to&quot;: &quot;0xa722ca7bf032de8f7a675da75dfec661bc89ace9&quot;,
 &quot;deadline&quot;: &quot;1661293930“

Output：
 0x
"><code><span class="hljs-keyword">Input</span>：
 <span class="hljs-string">"amountIn"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"8000000000000000000000"</span>,
 <span class="hljs-string">"amountOutMin"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"1"</span>,
 <span class="hljs-string">"path"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
    <span class="hljs-string">"0x74ef69defe8bae1fe660fb93265fc1bc79c9bda8"</span>,
    <span class="hljs-string">"0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"</span>,
    <span class="hljs-string">"0xd84379c4eea25d05574f9f0b99e3bf73500ca4b4"</span>,
    <span class="hljs-string">"0x74ef69defe8bae1fe660fb93265fc1bc79c9bda8"</span>,
    <span class="hljs-string">"0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"</span>
 <span class="hljs-punctuation">]</span>,
 <span class="hljs-string">"to"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"0xa722ca7bf032de8f7a675da75dfec661bc89ace9"</span>,
 <span class="hljs-string">"deadline"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"1661293930“

Output：
 0x
</span></code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/47486673379382d40de3d144c82f1d4abb7b98f26f0d0ee7fa8ad74be362bb83.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f79819fd5962de4b273f630dce9d23cbe3599cb51fa5222f1b78f741d5211ad6.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>(8) 调用 removeLiquidityETHSupportingFeeOnTransferTokens 函数，销毁 226 KALP，获得 8050 TA，Output &quot;amountETH&quot;: &quot;6392515470500594443&quot;</p><p>(9) 调用 removeLiquidityETHSupportingFeeOnTransferTokens 函数，销毁 0.9 KALP，获得 0.0009 TB，Output &quot;amountETH&quot;: &quot;1020797089459256392608&quot;</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b7a5fbc5d43b47e9f5959f45da0349b0a96e6a4c227bffd7eb0eb30d2b529b81.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>(10) 调用 removeLiquidity 函数，传入 0.9 KALP，获取 0.5 TA 和 1.9 TB</p><p>(11) 调用 swapExactTokensForTokens 函数，传入 83918 KY，获得 25170 BUSD</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/00822e3b6a3a0e0e09f76da3749e261073607441e50f955b6b2205761bf93fc0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>(12) 在 pancakeswap 中把 17740 KY 换成 5457 BUSD，把 23364 KY 换成 24 WBNB。</p><p>(13) 归还 1800 WBNB 闪电贷。</p><p>(14) 然后把 37294 BUSD 和 271 WBNB 转移到 0xd87f 地址中</p><p>总的来看，攻击者主要投入了 1026 BNB 到 WBNB 和 TA 的池子中，然后通过 swapExactTokensForETHSupportingFeeOnTransferTokens 函数以 8000 TA 获得 1019 BNB，并且通过 removeLiquidityETHSupportingFeeOnTransferTokens 函数移除 WBNB 和 TB 池子的流动性获得 1020 BNB。 投入 1026 BNB，获得 （1019 + 1020） BNB，其中必有蹊跷。</p><h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">代码分析</h1><p>首先来分析一下 <code>swapExactTokensForETHSupportingFeeOnTransferTokens</code> 函数，先调用 <code>_transferIn</code> 转入 TA，然后调用 <code>_swapSupportingFeeOnTransferTokens</code> 函数按照 <code>path</code> 进行一系列 swap 操作，计算 <code>_pools[TA，WBNB][WBNB]</code> 的变化，根据差值给 <code>to</code> 地址发送相等数量的 BNB。 需要关注的函数：<code>_transferIn</code> 和 <code>_swapSupportingFeeOnTransferTokens</code>。这些函都涉及到了一个关键的变量 <code>_pools</code> ，它是这次攻击的关键点。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/79ae86c97de70711acf8c05e35acfe188ca052bf36448fb19c46919bed19c1c3.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>先来看 <code>_transferIn</code> 函数，它的作用是把 <code>path</code> 中的第一个代币转入合约中，并修改对应的 <code>_pools</code> 值。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c5287b6a7929692332c72996a09013eb363bd2458c425e2adea151657f1bf704.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><code>_swapSupportingFeeOnTransferTokens</code> 函数根据 <code>path</code> 所提供的代币地址进行 swap，并将对应的 <code>_pools</code> 变量进行修改。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/73adea3b768419dd2b0380b43bb9bcc9affb100d484528d3c2c23f1e3dc52885.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>其中 <code>_transferOut</code> 函数的作用就是向 <code>to</code> 地址发送 <code>amount</code> 数量的 token。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7a0a2a26bb98e3647e2f9f0c1a61e53218d9cb2e72a8d72eb0d5fff2a412d66a.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>当 <code>swapExactTokensForETHSupportingFeeOnTransferTokens</code> 函数中 <code>path = [TA, WBNB, TB, TA, WBNB]</code> 时所发生的情况是（下面简称 <code>[A, W, B, A, W]</code>）：</p><p>首先在 <code>_transferrIn</code> 函数中：</p><pre data-type="codeBlock" text="_pool[AW][A] + amountIn
"><code>_pool<span class="hljs-selector-attr">[AW]</span><span class="hljs-selector-attr">[A]</span> + amountIn
</code></pre><p>然后在 <code>_swapSupportingFeeOnTransferTokens</code> 函数中（注意 <code>_pool[AW][W]</code> 做了两次减法操作）：</p><pre data-type="codeBlock" text="i = 0 , _pool[AW][W] – amountOutput1, _pool[WB][W] + amountOutput1
i = 1 , _pool[WB][B] – amountOutput2, _pool[BA][B] + amountOutput2
i = 2 , _pool[BA][A] – amountOutput3, _pool[AW][A] + amountOutput3
i = 3 , _pool[AW][W] – amountOutput4
"><code><span class="hljs-selector-tag">i</span> = <span class="hljs-number">0</span> , _pool<span class="hljs-selector-attr">[AW]</span><span class="hljs-selector-attr">[W]</span> – amountOutput1, _pool<span class="hljs-selector-attr">[WB]</span><span class="hljs-selector-attr">[W]</span> + amountOutput1
<span class="hljs-selector-tag">i</span> = <span class="hljs-number">1</span> , _pool<span class="hljs-selector-attr">[WB]</span><span class="hljs-selector-attr">[B]</span> – amountOutput2, _pool<span class="hljs-selector-attr">[BA]</span><span class="hljs-selector-attr">[B]</span> + amountOutput2
<span class="hljs-selector-tag">i</span> = <span class="hljs-number">2</span> , _pool<span class="hljs-selector-attr">[BA]</span><span class="hljs-selector-attr">[A]</span> – amountOutput3, _pool<span class="hljs-selector-attr">[AW]</span><span class="hljs-selector-attr">[A]</span> + amountOutput3
<span class="hljs-selector-tag">i</span> = <span class="hljs-number">3</span> , _pool<span class="hljs-selector-attr">[AW]</span><span class="hljs-selector-attr">[W]</span> – amountOutput4
</code></pre><p>转账的金额只通过最后一对 <code>pair</code> 的 <code>_pool</code> 数值 <code>_pool[AW][W]</code> 的减少量（从 AW 这个池子里换出了多少 W）来确定。正确的方法应该是只关注最后一步中 <code>_pool[AW][W]</code> 的减少量，而不是整个 swap 过程中 <code>_pool[AW][W]</code> 的总（累计）减少量。如果采用总（累计）减少量计算，则当 path 中有重复的 pair （<code>[A, W]</code>）不连续出现时，会多次计算 <code>_pool[AW][W]</code> 的减少量，最终导致 <code>balanceBefore.sub(balanceAfter)</code> 的值大于实际值。</p><p>我们看到第 1 次 TA 换 WBNB 的时候，换出来 1019.797089459257413406 WBNB，第 2 次 TA 换 WBNB 的时候，换出来 0.000395070241992122 WBNB，累加得到 1019.797484529499405528 WBNB，吻合之前提到的值。而正常情况下应该转出的 WBNB 因该为 0.000395070241992122 WBNB，同时将 [WBNB, TB] 池子中 TB 的币价大幅提高（转入了大量 WBNB）。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3d81a3c27168771e7c17289cddccfc4d4ae7b3386d0d7391ce852e90ffc3dcfb.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cefd9e93c6396d053813e79db6cb7483f5dd84186de83ad104b7705b6abaf9b2.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>综上所属，利用了 <code>_pools</code> 变量在整个 swap 过程中累计减少量的漏洞，攻击者用一笔钱，在提高了 [WBNB, TB] 池子中 TB 的币价的同时， swap 出了超量的 WBNB。然后再移除 [WBNB, TB] 池子的流动性， 获取大量的 BNB。</p>]]></content:encoded>
            <author>acai@newsletter.paragraph.com (ACai)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/9805065d183b235cea40a0cc352f4c16f9a85899e5d8580f428f5c2e29cf9fe6.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>