# Accounting breaks if end market appears multiple times in swap path

In GMX Synthetics swap routing, if the destination market appears multiple times in the swap path, later markets' pool accounting is credited without receiving tokens, breaking collateral accounting.

- Payout: Contest reward
- Severity: high
- Program: Gmx
- Credited: IllIllI
- Disclosed: 2022-09-22
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-02-gmx-judging/issues/132
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AH-13
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** GMX Synthetics SwapUtils._swap / swap path routing
**Root cause:** _swap() skips the token transfer when receiver equals the market token, but still calls applyDeltaToPoolAmount(); the loop uses the receiver check instead of whether this is the last hop, so a repeated destination market in the path credits pool accounting without moving tokens.
**Steps:**
1. Craft an increase order whose swap path array contains the final destination market more than once.
2. During the loop, each market's _swap() runs; for the destination market, receiver == marketToken so transferOut is skipped (SwapUtils.sol L240-248).
3. applyDeltaToPoolAmount() still updates the pool's input/output token accounting for that market.
4. Markets appearing after the extra destination market in the array have their accounting updated for tokens they never received.
5. Repeat swaps back and forth through the same market (minimizing price impact fees) to drain a pool's collateral token balance to zero.
**How found:** Code reading of the swap loop: noticed _swap() decides whether to transfer based on receiver == marketToken rather than whether it is the final hop, and that applyDeltaToPoolAmount() runs regardless, implying a repeated destination market in the path breaks accounting.
**Exploitation:** Attacker submits swaps/increase orders with a swap path that revisits the destination market, paying only swap fees, to desynchronize pool accounting from actual token balances; repeated back-and-forth swaps drain collateral so LP withdrawals revert and positions cannot be exited.
**Escalation:** Repeated swaps through the same market minimize price-impact fees while compounding the accounting drift, eventually zeroing collateral and blocking all exits for affected markets.
**Insight:** When a routing loop uses a state check (receiver == destination) to decide whether to move funds, test paths that revisit the destination: the loop's 'last iteration' semantics differ from 'is destination', and accounting updates that run unconditionally will desync from actual balances.
