# SMOOFSStaking: ERC721 reentrancy drains MOOVE rewards

SMOOFSStaking on Polygon reentered via ERC721 onERC721Received during Stake/Withdraw, letting attacker repeatedly withdraw the same NFT to drain MOOVE rewards.

- Payout: Real-world hack
- Severity: high
- Program: SMOOFSStaking
- Analysis by: DeFiHackLabs
- Disclosed: 2024-02-28
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-02/SMOOFSStaking_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20240228-smoofsstaking
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained vuln:reentrancy

**Target:** NFT staking contract on Polygon
**Root cause:** Stake() transfers the NFT via safeTransferFrom before finalizing state, invoking the attacker's onERC721Received callback; the callback re-enters Withdraw() repeatedly while stake accounting is inconsistent.
**Steps:**
1. Attacker holds Smoofs NFT tokenId 2062 and approves SMOOFSStaking.
2. Call `SMOOFSStaking.Stake(2062)` — NFT safeTransferFrom triggers attacker's `onERC721Received`.
3. Inside callback loop 9 times: `Smoofs.safeTransferFrom(this, SMOOFSStaking, 2062)` then `SMOOFSStaking.Withdraw(2062, true)`.
4. Each Withdraw pays out MOOVE rewards/tax refund while stake state is not yet settled.
5. After callback returns, outer Stake completes; attacker keeps accumulated MOOVE.
**Exploitation:** Attacker contract receives the NFT during Stake, re-enters Withdraw in a loop to repeatedly claim MOOVE payouts for the same token, then exits with inflated MOOVE balance.
**Insight:** When an NFT staking contract uses safeTransferFrom inside Stake, the receiver hook fires before stake bookkeeping finalizes — test re-entering Withdraw from onERC721Received to see if payouts are computed on stale state.
