# removedLiquidity can be underflowed to lock other user's deposits

Unchecked subtraction of removedLiquidity in SFPM burn underflows, letting an attacker craft a position whose premia math divides by zero and locks a front-run victim's deposit.

- Payout: Contest reward
- Severity: medium
- Program: Panoptic
- Credited: hash
- Disclosed: 2024-06-24
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-11-panoptic-findings/issues/516
- Library page: https://bugbountylibrary.com/r/c4%3A2023-11-panoptic%3AM-02
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic vuln:dos

**Target:** SemiFungiblePositionManager (Uniswap v3 LP tokenization, ERC1155 positions)
**Root cause:** In _createLegInAMM, `removedLiquidity -= chunkLiquidity` runs in an unchecked block, so burning a long leg after transferring the position with amount 0 underflows removedLiquidity to near 2**128.
**Steps:**
1. Mint a short token and a matching long token of same position size.
2. `safeTransferFrom(this, 0x1231, longTokenId, 0, "")` to zero out removedLiquidity/netLiquidity while keeping tokens.
3. Burn the long token: unchecked `removedLiquidity -= chunkLiquidity` underflows to ~2**128 - prevNetLiquidity.
4. Mint/burn short token to set netLiquidity to 0, leaving removedLiquidity = 2**128 - depositorLiquidity.
5. Front-run victim: `safeTransferFrom(this, Alice, shortTokenId, 0, "")` then Alice mints her deposit.
6. Alice's burn reverts: totalLiquidity == 2**128 so `totalLiquidity ** 2` wraps to 0 and Math.mulDiv divides by zero (or CastingError variant).
**How found:** Code reading of the unchecked block in _createLegInAMM combined with the observation that safeTransferFrom with amount 0 clears position accounting while retaining tokens, enabling a burn to underflow removedLiquidity; then traced how totalLiquidity feeds `totalLiquidity ** 2` in _getPremiaDeltas.
**Exploitation:** Attacker needs capital to mint short+long positions, transfers the poisoned tokenId to the victim before their deposit, causing the victim's subsequent burn/withdraw to revert permanently (funds locked) or corrupting premia values to extreme levels.
**Escalation:** Two variants: exact 2**128 totalLiquidity for division-by-zero DoS, or values slightly above 2**128 to distort premia gross/owed calculations.
**Insight:** In ERC1155/position managers, transferring with amount 0 can reset per-position accounting while leaving balances intact — look for unchecked arithmetic on those reset fields, and check downstream `x ** 2` in unchecked blocks for wraparound-to-zero division.
