# Large amounts of points can be minted virtually without any cost

Flatmoney's final-withdrawal fee exemption lets a sole LP loop deposit/withdraw to mint unlimited FMP points at only gas cost.

- Payout: Contest reward
- Severity: medium
- Program: Flatmoney
- Credited: Bauer
- Disclosed: 2023-12-11
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-12-flatmoney-judging/issues/187
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-12-flatmoney%3AM-4
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity vuln:business-logic vuln:fee-bypass vuln:reward-distribution

**Target:** StableModule.sol executeDeposit/executeWithdraw
**Root cause:** executeWithdraw skips the withdraw fee when totalSupply()==0 (final withdrawal), and executeDeposit mints FMP points proportional to deposit amount without any cost beyond a refundable keeper fee.
**Steps:**
1. Announce deposit of 100e18 rETH as LP, pay keeper fee
2. Wait minExecutabilityAge (10s), execute deposit as keeper: mints 100e18 UNIT + 100e18 FMP points, keeper fee refunded
3. Immediately announce withdraw of all 100e18 UNIT, pay keeper fee
4. Wait 10s, execute withdraw as keeper: totalSupply()==0 so no withdraw fee, rETH returned, keeper fee refunded
5. Repeat every ~20s while sole LP to accumulate points at only gas cost
**How found:** Code reading of executeWithdraw's totalSupply()==0 branch noting the withdraw fee is skipped for the final withdrawal, combined with executeDeposit minting points per deposit, revealing a costless loop.
**Exploitation:** Attacker acts as both LP and keeper, looping deposit/withdraw cycles while being the only LP so each withdrawal hits the totalSupply()==0 branch and avoids the withdraw fee; keeper fees are self-refunded, leaving only cheap L2 gas as cost.
**Escalation:** Rinse-and-repeat for the duration of sole-LP status (e.g. ~9000e18 points in 30 minutes) to accumulate excessive FMP redeemable for value.
**Insight:** When a fee is waived on the 'last withdrawal' (totalSupply==0) branch, check whether deposit-side rewards (points, incentives) can be farmed by a sole LP looping deposit/withdraw to repeatedly trigger that zero-fee branch.
