By the end of this lesson you can

  • →Derive an AMM's price from its reserves and compute the effect of a trade of any size
  • →Calculate the capital required to move a pool price by a given factor
  • →Explain why an AMM price is a reserve ratio rather than a valuation
  • →Identify systems that treat a pool price as an oracle, and why that is exploitable

Junior · enrolled learners

This lesson opens with bZx, February 2020.

What happened
bZx took its prices from Kyber, and Kyber routed to on-chain pools. On 15 February (UTC) an attacker took a flash loan of 10,000 ETH from dYdX and put 1,300 ETH of it into a five times leveraged short of ETH against wBTC at bZx. bZx converted 5,637 ETH into 51 wBTC through a Kyber order that was routed to Uniswap, at around three times the market price, and a logic error in bZx's contract skipped the collateral check that should have reverted the position. The attacker then sold wBTC into the skewed pool, profiting by about $370,000 while bZx lost about $620,000 of equity. On 18 February a second attacker flash-borrowed 7,500 ETH from bZx and spent 900 ETH buying sUSD through Kyber, pushing its price to about two and a half times the market rate, then posted the sUSD as collateral, valued at the price Kyber now reported, to borrow 6,796 ETH from bZx, an equity loss of around $600,000. Combined losses were more than $1M on that accounting.
The decision point
The two attacks failed differently, and the difference is the lesson. The first needed a bug: a safety check that did not fire. The second needed none. No key was stolen and no check was bypassed; bZx asked Kyber for the price of sUSD, Kyber reported what the pools it read now said, and bZx lent against that number exactly as written. A constant product pool reports a price that is a function of its two reserve balances and nothing else, so anybody willing to move the balances can set the reported price, and a flash loan supplies the capital to do it inside a single transaction. The failure in the second attack was that a system treated a reserve ratio as if it were a valuation.
Recorded loss
$1,000,000

What you will be able to answer

  • →What determines the price in a constant product pool?
  • →What does the invariant say?
  • →How much capital moves a pool price by a factor f?
  • →Why is a pool price not a valuation?

Orientation and Year One are open: anyone can read them without an account. From Year Two onward the lessons are for enrolled learners, because progress through the later years only means anything if it is tracked against a record.

It is free. We do not sell the list and there is nothing to buy at the end of it.

Sources and review

Confidence high·Volatility low·Reviewed 2026-08-06·Owner unassigned

Contested

This course has two halves since the 2026-09-09 merge. Lessons 1 to 5 cover the mechanics of a single swap and do not compare venues. Lessons 6 to 12, formerly the separate course J309, own venue selection: the four architectures, AMM generations, on-chain order books, aggregators, intents, perp DEXs and launch venues. The split between the halves is kept; material should not move across it without moving in both directions.

Reported bZx losses vary with what is counted. The per-attack figures used here (10,000 ETH flash loan, 1,300 ETH at five times, 5,637 ETH converted to 51 wBTC, $370,000 profit and $620,000 of equity loss; 7,500 ETH flash borrow, 900 ETH, 6,796 ETH borrowed and around $600,000 of equity loss) are from palkeo's transaction-level analysis, which puts the total at more than a million dollars. CoinDesk put the attackers' takes at about $350,000 and $633,000, and the Quadriga Initiative case study gives $918,000.

The two attacks did not share a mechanism. palkeo, PeckShield (quoted by CoinDesk) and the bZx team (quoted in the Quadriga Initiative case study) all attribute the first to a logic error that stopped a collateral check from firing, so the first was a contract bug amplified by slippage, and palkeo states that bZx's price reads in that transaction were correct. The second was an oracle manipulation with no code defect. This lesson's argument about reserve ratios rests on the second attack only.