> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tenderly.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Расследование взлома (Cover Protocol)

> Проанализируйте эксплойт Cover Protocol в Tenderly — импортируйте контракт, симулируйте deposit и найдите баг с кешем в Debugger.

Этот пример вкратце показывает, как Tenderly можно использовать для анализа и даже предотвращения взломов, подобных случившемуся с [Cover Protocol](https://twitter.com/CoverProtocol).

Cover Protocol был взломан из-за неспособности кода обновлять кеш в storage. Этого потенциально можно было бы избежать, [**настроив алерты на важные функции**](/monitoring/alerts/introduction), такие как deposit/withdrawal и определённые изменения состояния, чтобы предотвратить атаку.

Чтобы вручную проанализировать взлом, нам нужно [**импортировать смарт-контракт**](/developer-explorer/contracts) `Blacksmith`, в котором была обнаружена уязвимость. Если вы знаете точное имя затронутого протокола или уязвимого контракта, можно также искать его напрямую.

![](https://lh3.googleusercontent.com/BVJobjB-JHrSGyTHuC7v3cPLBbaUnNJH3pda8uJrHU2qCSV6ms-84BC614vdozpemjg5FO8J4cu-B9RjTTLfYWRQyBneYVBbLy5fv5_OQA1N-svrza9ZF6Q6xsUA5o37YyYPnaP4)

<Warning>
  Обратите внимание: искать можно только контракты, публично верифицированные в Tenderly или Etherscan. [**Подробнее о том, как верифицировать контракт в Tenderly, читайте здесь.**](/contract-verification/overview)
</Warning>

Если контракт публично не верифицирован, вы можете сделать это самостоятельно, чтобы иметь возможность использовать его с Tenderly. Если проект — open-source (как Cover), можно перейти в [GitHub-репозиторий проекта](https://github.com/CoverProtocol/cover-token-mining), найти нужный контракт (и его исходный код) и верифицировать его самостоятельно.

![](https://lh4.googleusercontent.com/vWVW6dAj1J6d83juyoXZ3cR9DTMmVgXu9PYHUUL4_Mv5LRAJ8wnXSckv72tEv-C96zOeutweZaLAx4OEaVBon1PkZOGMBmPwKLlTBJuPEAaPkZSDjwwtip3Kzx1d8B-UzYA7wRkE)

![](https://lh4.googleusercontent.com/C6BHcXHp8NHQmkb7kJP2vwNDi86mVgb-GyHb5Fp9OtddF3anpTTCdkERiNXAGYXnuhippPJKPuxf6a9RW1GIu91nECQWoV033C7gg1GHnz5tsoEP3BkkcMMiAHDCUspbmMz-BVUf)

Теперь, когда у нас есть контракт, который нужно импортировать в Tenderly, перейдите в свой Dashboard и кликните вкладку **Contracts** слева, а затем кнопку **Add Contract** в правом верхнем углу:

<img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/Screenshot%202021-12-01%20at%2010.28.37.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=51b1b58ec98df00a2b0526ec24d6a581" alt="" width="2521" height="787" data-path="images/Screenshot 2021-12-01 at 10.28.37.webp" />

Вы можете загрузить и верифицировать код контракта либо через Dashboard, либо через CLI [\[подробнее здесь\]](/contract-verification/overview):

<img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/Screenshot%202021-12-01%20at%2010.30.25.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=24ce923a3732175540cccc93975e4001" alt="" width="2521" height="787" data-path="images/Screenshot 2021-12-01 at 10.30.25.webp" />

<img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/Screenshot%202021-12-01%20at%2010.30.30.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=07faeb1cb135bdf6fca956ac178441cf" alt="" width="2521" height="927" data-path="images/Screenshot 2021-12-01 at 10.30.30.webp" />

Теперь, после импорта и верификации контракта, давайте проанализируем сам взлом. Мы знаем, что баг был в кеше функции deposit, поэтому симулируем эту функцию. Как видно на скриншоте ниже, после выполнения она завершилась с ошибкой `Blacksmith: pool does not exist`.

![](https://lh5.googleusercontent.com/JlFsuawkRAxjCnd7sHefFA9n-WpUOPMWIlnXb_IBOrdvQI8OFvRvTsWPH02p9qy1tmqDf8HnwVgJM2hK3x2iAmvWXNLj-qNLqDzyUmBBG4nbRAmkjfkpRGkh8748cFr052jEoaBL)

Теперь откроем эту ошибку в Tenderly Debugger. На строке 118 мы видим `Pool memory pool = pools[_lpToken];` в функции deposit, где данные кешируются, а позже, на строке 125, обновляются — там мы видим `_claimCoverRewards(pool, miner);`

Контракт использовал закешированные данные, потому что сами данные оставались в памяти; поэтому контракт позже рассчитывал функцию, используя эти данные. Кеш не обновлялся, что и привело к этому взлому:

```solidity title="example.sol" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
miner.rewardWriteoff = miner.amount.mul(pool.accRewardsPerToken).div(CAL_MULTIPLIER);
```

```solidity title="example.sol" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
miner.bonusWriteoff = miner.amount.mul(bonusToken.accBonusPerToken).div(CAL_MULTIPLIER);
```

![](https://lh3.googleusercontent.com/6jPAgWs9ZLNkM7PzW_g-0kR0Wy5kYMtk80huWk_KzsfpF7WBTrhE3VIWvPTI0bwVQmR25TLsARV-Ea3f2mK_kwcYESQEjxKebHv19YbNEuG-Jr0MJQ4t_LsxV-Q83rB_SC1NGV1v)

```solidity title="example.sol" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
function deposit(address _lpToken, uint256 _amount) external override {
    require(block.timestamp >= START_TIME, "Blacksmith: not started");
    require(_amount > 0, "Blacksmith: amount is 0");

    Pool memory pool = pools[_lpToken];

    require(pool.lastUpdatedAt > 0, "Blacksmith: pool does not exists");
    require(IERC20(_lpToken).balanceOf(msg.sender) >= _amount, "Blacksmith: insufficient balance");

    updatePool(_lpToken);

    Miner storage miner = miners[_lpToken][msg.sender];
    BonusToken memory bonusToken = bonusTokens[_lpToken];

    _claimCoverRewards(pool, miner);
    _claimBonus(bonusToken, miner);

    miner.amount = miner.amount.add(_amount);

    // update writeoff to match current acc rewards/bonus per token
    miner.rewardWriteoff = miner.amount.mul(pool.accRewardsPerToken).div(CAL_MULTIPLIER);
    miner.bonusWriteoff = miner.amount.mul(bonusToken.accBonusPerToken).div(CAL_MULTIPLIER);

    IERC20(_lpToken).safeTransferFrom(msg.sender, address(this), _amount);
    emit Deposit(msg.sender, _lpToken, _amount);
}

```

* Новый пул был одобрен для liquidity mining буквально за несколько часов до взлома. Этот пул был абсолютно нормальным, но, поскольку он был новым, в контракте blacksmith не было LP-токенов этого пула.
* Атакующий внёс некоторое количество токенов этого пула в контракт Blacksmith.
* Контракт Blacksmith ведёт учёт наград на попер-токен-основе. Если заблокировано много токенов, награда на токен будет мала. Если заблокировано мало токенов, награда на токен будет велика. Соответствующая переменная называется `accRewardsPerToken` и вычисляется как `totalPoolRewards / totalTokenBalance`.
* Затем атакующий вывел почти все LP-токены из контракта Blacksmith, уменьшив значение `totalTokenBalance` практически до нуля.
* Затем атакующий снова внёс некоторое количество токенов этого пула в контракт Blacksmith. Именно здесь баг проявил себя во всей красе. Поскольку `totalTokenBalance` в предыдущей транзакции сильно уменьшился, вновь рассчитанный `accRewardsPerToken` подскочил вверх. Контракт использует `rewardWriteoff`, чтобы держать под контролем эффект `accRewardsPerToken`. Однако из-за бага при расчёте значения `rewardWriteoff` использовалось старое (маленькое) значение `accRewardsPerToken`. Из-за этого большое значение `accRewardsPerToken` осталось без контроля.
* Затем атакующий вывел свои награды. Поскольку в `accRewardsPerToken` было большое неконтролируемое значение, общая награда, выплаченная системой, оказалась завышенной, и **в итоге контракт заминтил 40 796 131 214 802 500 000 токенов COVER**.

<Note>
  Спасибо Mudit Gupta за последнюю часть разбора этого взлома — [подробнее об этом в его блоге](https://mudit.blog/cover-protocol-hack-analysis-tokens-minted-exploit/) :)
</Note>
