# TermMaxMarket.provideLiquidity is vulnerable to donation attacks

First LP of TermMaxMarket donates FT/XT to inflate reserves so a victim's provideLiquidity mints zero LP tokens, letting attacker steal the deposit.

- Payout: Contest reward
- Severity: high
- Program: TermMax
- Credited: Drastic Watermelon
- Disclosed: 2025-03-25
- Write-up quality: 8/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_term_max_december2024.pdf#3.1.2
- Library page: https://bugbountylibrary.com/r/cantina%3Aterm_max_december2024%3A3.1.2
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:high tech:evm tech:solidity technique:race-window technique:source-review vuln:business-logic vuln:oracle-manipulation vuln:share-inflation

**Target:** TermMaxMarket AMM liquidity contract (provideLiquidity/withdrawLiquidity)
**Root cause:** LP minting in TermMaxCurve.calculateLpOut derives reserves from balanceOf and totalSupply of FT/XT and LP tokens; direct token transfers inflate balanceOf, so the minted-LP formula rounds down to 0 for the victim.
**Steps:**
1. Attacker is first depositor: `provideLiquidity(X)` mints X XT and X*ltv FT plus X LPXT and X*ltv LPFT.
2. Attacker withdraws all but 1: `withdrawLiquidity(lpFt-1, lpXt-1)`, leaving totalSupply of LPFT/LPXT = 1 and reserves = 1 FT / 1 XT.
3. Attacker frontruns victim's deposit by transferring all held FT and XT directly to the market via `ft.transfer(market, ...)` and `xt.transfer(market, ...)`.
4. Victim calls `provideLiquidity(Y)`; since Y * LP.totalSupply < token.balanceOf(market) for both pairs, calculateLpOut rounds to 0 and victim receives no LP tokens.
5. Attacker (sole LP holder) later withdraws 1 LPFT/1 LPXT and redeems FT/XT for underlying, capturing victim's deposit; a third-party deposit Z > reserves enables earlier exit.
**How found:** Reviewer read provideLiquidity and noticed LP share computation relies on balanceOf/totalSupply rather than internal accounting, recognizing the classic first-depositor donation/rounding pattern and constructing a frontrun PoC.
**Exploitation:** Attacker needs to be first LP (or hold near-total LP supply), frontruns victim's provideLiquidity in mempool with a direct token donation to the market, causing victim's LP mint to round to zero; attacker then withdraws the single LP share and redeems FT/XT to underlying for profit slightly above victim's deposit.
**Insight:** When an AMM mints shares from balanceOf-derived reserves, check whether a first depositor can shrink totalSupply to 1 and donate tokens to force the next depositor's share to round to zero; also check whether withdrawal-to-zero is blocked, which only delays attacker exit rather than preventing theft.
