# NORMIE: skim/transfer loop drains Sushi liquidity via flash loans

NORMIE token's fee-on-transfer/skim logic on Base was abused via flash loans and repeated skim/transfer loops to drain ~$490K of liquidity.

- Payout: Real-world hack
- Severity: high
- Program: NORMIE
- Analysis by: DeFiHackLabs
- Disclosed: 2024-05-26
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-05/NORMIE_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20240526-normie
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained vuln:accounting-error vuln:business-logic vuln:flash-loan

**Target:** ERC-20 token with fee-on-transfer logic and UniswapV2/V3 pools on Base
**Root cause:** The token's transfer/skim interaction with the UniswapV2 pair allowed an attacker to repeatedly skim and re-transfer tokens, manipulating the pair's reserves and price accounting.
**Steps:**
1. Fork Base at block 14952782.
2. Swap 2 ETH to NORMIE on SushiV2 router.
3. Flash loan 5e15 NORMIE from SushiV2 SLP pair via `swap(0, 5_000_000_000_000_000, this, hex"01")`.
4. In `uniswapV2Call`, transfer all NORMIE to the SLP pair.
5. Flash loan 11.33e15 WETH from UniswapV3 pool via `flash(this, 0, 11_333_141_501_283_594, "")`.
6. In `uniswapV3FlashCallback`, approve Sushi router and swap 9.06e15 NORMIE to WETH.
7. Transfer remaining NORMIE to SLP, then loop 50x: `SLP.skim(this)` followed by transferring NORMIE back to SLP.
8. Final `SLP.skim(this)` without re-transfer.
9. Swap 2 ETH to NORMIE again, repay UniswapV3 flash loan with 11.44e15 NORMIE.
10. Keep remaining ETH as profit.
**Exploitation:** Attacker flash-borrowed NORMIE from the SushiV2 pair and WETH from a UniswapV3 pool, then exploited the token's fee-on-transfer/skim behavior by repeatedly skimming the pair and re-transferring NORMIE, distorting reserves and extracting WETH profit before repaying the flash loans.
**Escalation:** Chained two flash loans (SushiV2 + UniswapV3) and a 50-iteration skim/transfer loop to amplify extraction.
**Insight:** When a token has fee-on-transfer or skim-sensitive logic, check whether repeated `skim()` + re-transfer cycles can shift pair reserves and let you arbitrage against a flash-loaned position; the loop count matters for maximizing extraction before repayment.
