# Launchpad slippage is not enforced properly during token graduation

Launchpad buy() checks slippage only against bonding-curve cost, so graduation swaps bypass maxAmountInQuote and users overpay for partial fills.

- Payout: Contest reward
- Severity: medium
- Program: GTE
- Credited: chaos304
- Disclosed: 2026-02-05
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2025-08-gte-perps-and-launchpad#m-24
- Library page: https://bugbountylibrary.com/r/c4%3A2025-08-gte-perps-and-launchpad%3AM-24
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Launchpad.sol buy() bonding curve / AMM graduation
**Root cause:** Slippage is validated only against amountInQuote from curve.buy() before _graduate() performs the remaining AMM swap, so the total quote spent across curve+AMM is never compared to maxAmountInQuote.
**Steps:**
1. Call `buy(buyData)` with amountOutBase large enough to exhaust the bonding curve supply and trigger graduation.
2. Observe `amountInQuote = data.curve.buy(...)` is checked against `buyData.maxAmountInQuote` and passes.
3. `_graduate()` then swaps remaining base tokens on the UniswapV2 pair, spending additional quote not covered by the slippage check.
4. Transaction succeeds even though total quote paid far exceeds maxAmountInQuote and user receives a fraction of desired tokens at exorbitant effective price.
**How found:** Noticed the slippage check sits before the `if (!data.active)` graduation branch, so the AMM leg of the purchase is excluded from the maxAmountInQuote comparison.
**Insight:** When a function has a post-processing branch (graduation, fallback swap, second leg), verify slippage/limit checks cover the aggregate spend across all legs, not just the first internal call.
