MonoX Same-Token Swap
$31M drained from MonoX's single-token pools after the attacker swapped a token with itself, pumping MONO in the protocol's own oracle until pools emptied.
- Date
- Victim
- MonoX Finance
- Status
- Funds Stolen
On November 30, 2021, the single-pool AMM MonoX Finance lost approximately $31 million across its Ethereum and Polygon deployments. The bug was almost too simple to be real: the swap contract did not check whether the input token and the output token were the same.
What happened
MonoX used a novel "single-pool" AMM design where every token was paired against the protocol's MONO governance token internally, rather than against other tokens directly. A swap from token A to token B was implemented as A → MONO → B in two internal steps, each updating the relevant token prices.
The fatal omission: the swap function did not validate that tokenIn ≠ tokenOut. When a user swapped MONO for MONO, the price-update logic ran on both legs:
- The "sell" leg of the swap pushed MONO's price down (typical AMM behaviour).
- The "buy" leg pushed MONO's price up.
- Crucially, the price-update functions ran sequentially, and the
tokenOutprice update happened last — so the protocol ended the transaction with MONO's price massively inflated.
The attack loop:
- Swap MONO for MONO repeatedly, pumping MONO's recorded price.
- Swap the artificially expensive MONO for real assets — WETH, WMATIC, WBTC, USDC, USDT, LINK, GHST, DUCK, MIM, IMX.
- Repeat until each pool was drained.
Total losses on Polygon + Ethereum: ~2,100 WETH, 1.9M WMATIC, 36 WBTC, $8.2M USDC, $9.1M USDT and a long tail of other tokens, summing to ~$31M.
Aftermath
- MonoX paused both deployments and announced a recovery plan.
- The attacker laundered through Tornado Cash; no public recovery.
- MonoX never returned to its pre-incident standing.
Why it matters
MonoX is the textbook case for how a single missing equality check can be a fully-loaded exploit primitive. The bug — require(tokenIn != tokenOut) — is exactly one line of code. Its absence cost $31M.
The deeper lesson is the recurring one for novel AMM designs: every claimed invariant of the AMM must be tested across the full input space, including obviously-degenerate cases. The "swap a token for itself" case is degenerate from the user's perspective — no one would ever want to do it. From the protocol's perspective, it's a state-update path that produces unconstrained price drift. Modern AMM testing frameworks (Echidna, Foundry invariants) specifically generate degenerate inputs to surface exactly this class of bug.
Sources & on-chain evidence
- [01]slowmist.medium.comhttps://slowmist.medium.com/detailed-analysis-of-the-31-million-monox-protocol-hack-574d8c44a9c8
- [02]cryptobriefing.comhttps://cryptobriefing.com/monox-finance-drained-of-31m-in-latest-defi-hack/
- [03]immunebytes.comhttps://immunebytes.com/blog/monox-hack-incident-nov-30-2021-detailed-analysis/