# First liquidity provider can DOS the pool of a stable pair

Stable-pair invariant k rounds to zero when x*y<1e18, letting first LP mint tiny liquidity, drain reserves via swaps, and inflate totalSupply to DOS the pool.

- Payout: Contest reward
- Severity: medium
- Program: Blackhole
- Credited: ZZhelev
- Disclosed: 2025-07-03
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-05-blackhole#m-06
- Library page: https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-06
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:dos

**Target:** Solidity Pair contract stable-pool invariant (_k) and mint/swap
**Root cause:** In _k for stable pools, _a=(_x*_y)/1e18 truncates to zero when x*y<1e18, so k=0 and swap invariant checks pass trivially; mint lacks a minimum-k guard for the first LP.
**Steps:**
1. Deploy stable pair via `factory.createPair(tokenA, tokenB, true)`.
2. Attacker transfers small amounts (e.g. `10000000` wei each) of tokenA/tokenB to pair and calls `pair.mint(attacker)`.
3. Because `_k` returns 0, transfer 1 token0 to pair and call `pair.swap(0, balance1-1, attacker, "0x")` to drain token1.
4. Transfer 1 token1 and call `pair.swap(balance0-1, 0, attacker, "0x")` to drain token0, leaving 1/2 wei.
5. Repeat mint+drain cycles; totalSupply grows geometrically until final `mint` reverts (overflow/ILM), DOSing the pool.
**How found:** Code review of `_k` stable branch spotted integer division `(_x*_y)/1e18` truncating to zero for small reserves; hypothesized invariant check bypass and validated with a Hardhat PoC looping mint/drain.
**Exploitation:** Attacker repeatedly seeds dust liquidity, mints LP, and uses zero-k swaps to extract nearly all reserves each cycle while inflating totalSupply; eventually mint reverts, bricking the pair for other LPs/traders.
**Escalation:** Iterating cycles compounds totalSupply growth until overflow, converting a per-cycle drain into a permanent pool DOS.
**Insight:** In stableswap-style invariants, audit every fixed-point division for truncation-to-zero at small reserves; a zero invariant silently disables swap safety checks, so first-LP paths need explicit minimum-k guards.
