# AMM reserve skew via burn and sync

Token code that burns or moves tokens out of the pair's own balance, then calls sync()

_Area: DeFi oracles, liquidations and flash loans. Seen in 40 disclosed reports; latest 2026-10-17. Updated 2026-10-23._

## How it works
An AMM prices swaps from stored reserves and enforces x*y=k. Some token code removes tokens from the pair's own balance (a burn, raw transfer, or "recycle") and then calls pair.sync(), which rewrites the stored reserve to the new lower balance. No value flows in for that removal, so one reserve drops while the other stays flat; the next swap prices against the skewed reserve and the attacker extracts the difference. The broken assumption: reserves only change through swaps or balanced liquidity events. Two related shapes: ordering, where sync() runs before the incoming amount is credited and latches a low reserve [E2](https://bugbountylibrary.com/r/dhl%3A20260825-fhtoken.md); and reserve distortion without any burn, via direct transfers plus skim() or repeated LP mint/skim/swap cycles [E7](https://bugbountylibrary.com/r/dhl%3A20260618-jb.md).

## Where it shows up
- Token transfer hooks or sell branches that burn from the pair's balance, not the sender's [E2](https://bugbountylibrary.com/r/dhl%3A20260825-fhtoken.md)[E3](https://bugbountylibrary.com/r/dhl%3A20260716-crowdringcircle.md)[E6](https://bugbountylibrary.com/r/dhl%3A20260628-aidc.md)[E8](https://bugbountylibrary.com/r/dhl%3A20260428-judao.md)
- pair.sync() called inside a transfer, sell, or reward path [E1](https://bugbountylibrary.com/r/dhl%3A20260827-cashcowcoin.md)[E2](https://bugbountylibrary.com/r/dhl%3A20260825-fhtoken.md)[E3](https://bugbountylibrary.com/r/dhl%3A20260716-crowdringcircle.md)[E5](https://bugbountylibrary.com/r/dhl%3A20260728-lula.md)[E8](https://bugbountylibrary.com/r/dhl%3A20260428-judao.md)
- Public sell(), mine(), recycle(), or similar entry points reaching a privileged burn/mint [E1](https://bugbountylibrary.com/r/dhl%3A20260827-cashcowcoin.md)[E4](https://bugbountylibrary.com/r/dhl%3A20261017-tipmine.md)[E5](https://bugbountylibrary.com/r/dhl%3A20260728-lula.md)
- "Accumulated" fee amounts debited from the pair [E6](https://bugbountylibrary.com/r/dhl%3A20260628-aidc.md)
- sync() ordered before the incoming amount is credited [E2](https://bugbountylibrary.com/r/dhl%3A20260825-fhtoken.md)
- Unverified helper/gateway contracts with opaque selectors touching a live pair [E7](https://bugbountylibrary.com/r/dhl%3A20260618-jb.md)

## How to review
Grep every sync() call site and trace each path that changes a pair's token balance outside a swap. The core tell: sync() after a burn or removal from the pair's own balance, or before a credit. The invariant: after any user-triggerable call, reserve0/reserve1 must equal token.balanceOf(pair), and any decrease in one reserve must be matched by value paid in. Assert reserve==balanceOf after each path. sync() is safe only when paired with a credit in the same transaction. Check that burns debit the sender, never the pair; that sync() runs only after all credits for that transfer; and that privileged burn/mint helpers are unreachable from permissionless functions. Confirm gating (proxy-only, Rental-only, once-per-day) cannot be satisfied or bypassed by an ordinary user [E1](https://bugbountylibrary.com/r/dhl%3A20260827-cashcowcoin.md)[E4](https://bugbountylibrary.com/r/dhl%3A20261017-tipmine.md)[E5](https://bugbountylibrary.com/r/dhl%3A20260728-lula.md).

## Variants seen
- Permissionless entry to a privileged burn on the pair, then sync(): public sell() via proxy [E1](https://bugbountylibrary.com/r/dhl%3A20260827-cashcowcoin.md), ungated mine() [E4](https://bugbountylibrary.com/r/dhl%3A20261017-tipmine.md), recycle() callable only by Rental but reached through user reward claims [E5](https://bugbountylibrary.com/r/dhl%3A20260728-lula.md)
- Premature sync() before the seller is credited, latching a low reserve (ordering bug) [E2](https://bugbountylibrary.com/r/dhl%3A20260825-fhtoken.md)
- Sell-destroy burning pair reserve on any non-exempt transfer [E3](https://bugbountylibrary.com/r/dhl%3A20260716-crowdringcircle.md)
- Ordinary transfers burning accumulated amounts from the pair [E6](https://bugbountylibrary.com/r/dhl%3A20260628-aidc.md)
- Sell transfer hook that burns pair reserve and syncs on tokens sent to the pair [E8](https://bugbountylibrary.com/r/dhl%3A20260428-judao.md)
- Reserve distortion via direct transfers plus skim(), or repeated LP mint/skim/swap cycles, with no sync() [E7](https://bugbountylibrary.com/r/dhl%3A20260618-jb.md)

## Impact and severity
Direct loss of the paired asset: ~165 WBNB [E1](https://bugbountylibrary.com/r/dhl%3A20260827-cashcowcoin.md), ~220 WBNB [E6](https://bugbountylibrary.com/r/dhl%3A20260628-aidc.md), ~201K USDT [E3](https://bugbountylibrary.com/r/dhl%3A20260716-crowdringcircle.md), ~578K USDT [E5](https://bugbountylibrary.com/r/dhl%3A20260728-lula.md), ~667 SOL [E4](https://bugbountylibrary.com/r/dhl%3A20261017-tipmine.md), ~49,958 USDT [E7](https://bugbountylibrary.com/r/dhl%3A20260618-jb.md), excess USDT via flash-loaned collateral [E8](https://bugbountylibrary.com/r/dhl%3A20260428-judao.md). Critical where the trigger is permissionless and repeatable; worse when one call zeroes a reserve and a plain swap finishes the drain [E3](https://bugbountylibrary.com/r/dhl%3A20260716-crowdringcircle.md)[E4](https://bugbountylibrary.com/r/dhl%3A20261017-tipmine.md). E7 is lower confidence: unverified helper with opaque selectors.

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20260827-cashcowcoin.md
- E2: https://bugbountylibrary.com/r/dhl%3A20260825-fhtoken.md
- E3: https://bugbountylibrary.com/r/dhl%3A20260716-crowdringcircle.md
- E4: https://bugbountylibrary.com/r/dhl%3A20261017-tipmine.md
- E5: https://bugbountylibrary.com/r/dhl%3A20260728-lula.md
- E6: https://bugbountylibrary.com/r/dhl%3A20260628-aidc.md
- E7: https://bugbountylibrary.com/r/dhl%3A20260618-jb.md
- E8: https://bugbountylibrary.com/r/dhl%3A20260428-judao.md
