# Cover Protocol Blacksmith: stale cache mints infinite COVER

Blacksmith cached pool data in memory, updated storage but not the cache, so accRewardsPerToken stayed inflated and attackers minted ~40.8 quintillion COVER tokens.

- Payout: Real-world hack
- Severity: critical
- Program: Cover Protocol
- Analysis by: DeFiHackLabs
- Disclosed: 2020-12-29
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2020-12/Cover_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20201229-cover
- Tags: area:web3 domain:web3 impact:funds-loss impact:integrity kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:reward-distribution

**Target:** Blacksmith liquidity mining contract (Solidity)
**Root cause:** claimRewards/deposit path caches pool data in memory, writes updated pool data to storage but never refreshes the cached copy; the stale accRewardsPerToken is later used in rewardWriteoff calculations.
**Steps:**
1. Wait for a newly approved pool with zero LP tokens in Blacksmith.
2. `bs.deposit(bpt, amount)` to seed the pool.
3. Withdraw almost all LP tokens so totalTokenBalance approaches zero, inflating accRewardsPerToken = totalPoolRewards / totalTokenBalance.
4. Deposit again: rewardWriteoff is computed from the stale (small) cached accRewardsPerToken, leaving the large value unchecked.
5. `bs.claimRewards(bpt)` to withdraw inflated rewards, minting 40,796,131,214,802,500,000 COVER.
**How found:** Analysis points to line 118 of Blacksmith.sol: reading the code shows pool data cached in memory, storage updated, cache not refreshed — a classic cache-invalidation flaw exploited via a freshly approved pool with no existing LP tokens.
**Exploitation:** Attacker cycled deposit/withdraw on a fresh pool to drive totalTokenBalance near zero, then re-deposited so the stale cached accRewardsPerToken bypassed rewardWriteoff, and claimed rewards to mint ~40.8e18 COVER; largest hacker returned 4350 ETH after burning, others cashed out ~$4.4M (1400 ETH, 1M DAI, 3k LINK, 90 WBTC).
**Escalation:** Repeated across multiple hackers and pools; team revoked Blacksmith minting access to stop it.
**Insight:** In reward-farming contracts, look for memory-cached structs that are written back to storage but not re-read; a freshly whitelisted pool with zero LP balance lets you manipulate per-token reward ratios and bypass writeoff checks.

## Proof of concept (copied exactly from the original report)

**Foundry PoC deposit and claimRewards exploit**

```
cheat.prank(0x00007569643bc1709561ec2E86F385Df3759e5DD);
        bs.deposit(address(bpt), 15_255_552_810_089_260_015_361);
        emit log_named_uint("Deposit BPT", 15_255_552_810_089_260_015_361);
        cheat.prank(0x00007569643bc1709561ec2E86F385Df3759e5DD);
        //bs.withdraw(address(bpt),12345678);
        bs.claimRewards(address(bpt));
        emit log_named_uint(
            "After claimRewards, Cover Balance", Cover.balanceOf(0x00007569643bc1709561ec2E86F385Df3759e5DD)
        );
```

