# RuggedArt: reentrancy in claimReward/stake drains pool

Reentrancy in RuggedArt staking/reward proxy let attacker flash-loan, claim rewards, buy NFTs, unstake and drain ~5 ETH.

- Payout: Real-world hack
- Severity: high
- Program: RuggedArt
- Analysis by: DeFiHackLabs
- Disclosed: 2024-02-19
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-02/RuggedArt_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20240219-ruggedart
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained vuln:flash-loan vuln:reentrancy vuln:reward-distribution

**Target:** RuggedArt staking/reward proxy and Uniswap V3 RUGGED/WETH pool
**Root cause:** The proxy's stake/claimReward flow is reentrant via the attacker fallback, allowing repeated reward claims and unstaking within one flash-loan transaction.
**Steps:**
1. Flash-borrow 22 WETH from Uniswap V3 pool via `pool.flash(this, 22e18, 0, ...)`.
2. In `uniswapV3FlashCallback`, call `proxy.claimReward()`.
3. Build 20 tokenIds and a UniversalRouter execute (command `0x04`) and call `proxy.targetedPurchase{value:1 wei}(tokenId, swapParam)`.
4. Call `proxy.unstake(RUGGED.balanceOf(this))`.
5. Repay pool with `RUGGED.transfer(pool, flashnumber+fee0)`.
6. Fallback reenters `proxy.stake(flashnumber)` after approving proxy max, amplifying reward accrual.
7. Swap remaining RUGGED back to WETH via `pool.swap` to realize profit.
**Exploitation:** Attacker flash-loans WETH, reenters the proxy's stake via fallback during claimReward/unstake to inflate rewards, purchases NFTs cheaply through UniversalRouter, unstakes, repays flash loan, and swaps RUGGED for WETH, netting ~5 ETH.
**Insight:** When a staking/reward proxy calls out to user contracts (ERC721 receiver, fallback) mid-accounting, check whether stake/claimReward/unstake can be reentered to double-count rewards before balances update.
