# Malicious users can steal swap fees from liquidity providers

TermMax LP reward formula ignores holding duration, so a flash-loan-funded deposit+withdraw in one block siphons accrued swap fees from long-term LPs.

- Payout: Contest reward
- Severity: high
- Program: TermMax
- Credited: 0x37
- Disclosed: 2025-03-25
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_term_max_december2024.pdf#3.1.1
- Library page: https://bugbountylibrary.com/r/cantina%3Aterm_max_december2024%3A3.1.1
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:high tech:evm tech:solidity technique:source-review vuln:business-logic vuln:flash-loan vuln:reward-distribution

**Target:** TermMax market/router LP reward accounting (calculateLpReward)
**Root cause:** calculateLpReward weights reward by (currentTime - openMarketTime) for the LP's amount but never tracks when the LP actually deposited, so liquidity added moments before withdrawal earns the full time-weighted share of accrued fees.
**Steps:**
1. Generate swap fees: `market.buyFt(1000e8,0)`, `market.buyXt(1000e8,0)`, then `sellFt`/`sellXt` full balances.
2. `vm.warp(block.timestamp + 57 days)` toward maturity so rewards accrue.
3. As attacker: `market.provideLiquidity(100000e8)`, approve lpFt/lpXt to router, immediately `router.withdrawLiquidityToFtXt(alice, market, lpFt.balanceOf(alice), lpXt.balanceOf(alice), 0, 0)`.
4. Repeat deposit/withdraw loop to compound skimmed fees.
5. Honest LP withdraws; compare received ft/xt vs baseline (880738388498/1000821070844 → 880036223746/999548671891).
**How found:** Code review of the reward formula: noticed reward depends on currentTime-openMarketTime rather than the LP's actual deposit timestamp, hypothesizing same-block deposit/withdraw would still earn rewards; confirmed with a Foundry PoC comparing honest LP output with and without attacker interference.
**Exploitation:** Attacker flash-loans underlying, deposits large liquidity right before an honest LP's withdrawal, and withdraws in the same transaction, capturing a time-weighted share of accrued swap fees proportional to lpAmt; honest LPs receive less.
**Escalation:** Looping deposit/withdraw across blocks or scaling capital via flash loans increases skimmed fees; no special preconditions beyond accrued rewards.
**Insight:** When a reward formula uses global elapsed time (currentTime - openMarketTime) multiplied by user amount, check whether per-user accrual start is tracked; if not, same-block deposit/withdraw or flash-loan capital captures time-weighted rewards.
