# SNOOD: allowance miscalculation drains UniswapV2 pair

SNOOD ERC-777 token's _spendAllowance miscalculation let attacker drain the SNOOD/WETH UniswapV2 pair via transferFrom and sync, netting ~104 ETH.

- Payout: Real-world hack
- Severity: high
- Program: SNOOD
- Analysis by: DeFiHackLabs
- Disclosed: 2022-06-18
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2022-06/Snood_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20220618-snood
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** ERC-777 token contract and UniswapV2 SNOOD/WETH pair
**Root cause:** SNOOD's _spendAllowance miscalculates allowance, so transferFrom from the pair succeeds without a real approval, letting the attacker move the pair's entire SNOOD balance.
**Steps:**
1. Fork mainnet at block 14983660.
2. Read `balance = SNOOD.balanceOf(uniLP)` (pair's SNOOD balance).
3. Call `SNOOD.transferFrom(address(uniLP), address(this), balance - 1)` — succeeds due to allowance miscalculation.
4. Call `uniLP.sync()` to update reserves to the drained state.
5. Transfer `balance - 1` SNOOD back to the pair.
6. Compute `amount0Out = ((balance-1)*9970*a)/(b*10000+(balance-1)*9970)` from reserves.
7. Call `uniLP.swap(amount0Out, 0, attacker, "")` to extract WETH.
**How found:** Reference notes an attack on an ERC-777 contract and UniswapV2 pair; the flaw is a miscalculation in _spendAllowance enabling unapproved transferFrom of pair-held tokens.
**Exploitation:** Attacker pulled nearly all SNOOD out of the pair via the flawed transferFrom, synced reserves so the pair believed it held ~1 wei SNOOD, then re-deposited the SNOOD and swapped to extract WETH (~104 ETH per reference).
**Insight:** For tokens with custom _spendAllowance/_transfer hooks (ERC-777), test whether transferFrom from a UniswapV2 pair can move the pair's own balance without approval; combined with sync() this lets you reset reserves and swap out the other asset.

