LV Finance Rug Pull

Reported loss $334K
Ethereum
Rugpull

What happened

LV Finance was a September 2020 Ethereum yield farm: stakers deposited USDC, USDT, SUSHI, UNI, LINK and other tokens into twelve pool contracts to earn the LV token at 0xa77f34bd…5aab22. The pools' addReward function, callable only by the rewardDistribution address the owner sets, hid a backdoor: any reward value of 3 or less skips the reward logic and runs _migrate, which either flips a flag that blocks every withdraw or sends the pool's entire balance to the caller through a helper named upgrade that is really an ERC-20 transfer. On 19 September 2020 0xb19dE844…6DF6e6 called addReward(2) on the USDC pool and received 201,585.64 USDC in that single transaction.

The existing record says the same call was made on each pool, taking in total 201.5K USDC, 79.6K USDT, 8.1 LEND, 2.7K SUSHI, 816 UNI, 1K LINK, 1.3 SNX, 261 YFV, 0.02 YFI, 82.1 PYLON and 0.76 YFII, which were exchanged for ETH.

How it happened

  1. Each pool holds one deposit token in _token (the USDTPool copy hard-codes USDT). stake pulls tokens in, and withdraw pays them back only while require(_upgrade < 1,"contract migrated") holds.
  2. The pool owner sets rewardDistribution with setRewardDistribution, and addReward carries the onlyRewardDistribution modifier, so only that address can call it.
  3. addReward(uint256 reward) treats a value above MIN_REWARD = 3 as a normal reward top-up. Any value of 3 or less falls to else{super._migrate(reward);}.
  4. _migrate(1) toggles _upgrade, which makes every staker's withdraw revert with "contract migrated". Any other value runs _token.upgrade(msg.sender, _token.balanceOf(address(this))), and the SafeERC20.upgrade helper encodes token.transfer.selector, so the pool's whole balance goes to the caller.
  5. What happened: in transaction 0xa5b92bb9…f03325 (19 September 2020, 14:53:08 UTC), 0xb19dE844…6DF6e6 called addReward(2) on the USDC pool 0x9e1d0964…75deb7 and received 201,585.6402 USDC.
  6. The existing record lists the twelve pools as 0x80c09d3c…59a494, 0x9e1d0964…75deb7, 0x7b63771f…c39f80, 0xa2a430ce…d6f27d, 0xb7b3ab63…dd2f3e, 0x828995b4…5f7a27, 0x5a529c3a…72bc6c, 0xd76e4470…02f7f1, 0xbca5fc48…89ca06, 0xc3dc2d24…7b903f, 0xe52dfd3d…2a3e14 and 0x478e26cb…d28c02, all drained the same way.

Protocol details

Classification Yield Aggregator
Protocol Type Exit Scam/Rugpull
Affected asset / contract LV

Build your security review skills

Work through hands-on labs covering real exploit mechanics, review techniques, and defensive patterns.