Liquidity Lu saysUniswap v2 trades against a constant-product invariant x·y=k: every swap moves along the curve while the product stays fixed, and a 0.3% fee skims to LPs.
Uniswap v2's constant product AMM holds two token reserves x and y satisfying x · y = k. To swap dx of token X for token Y, the curve solves (x + dx_after_fee)(y − dy) = k — so the more you swap, the worse your price, with the gap funding LPs. The 0.3% fee is taken off the input before computing dy.
Two consecutive swaps on the same pool show price impact compounding: each trade moves the pool farther from balance, so the second 100-unit swap pays more slippage than the first. The demo runs two swaps and prints k, the new reserves, and the price impact.
Power-ups you unlock
Invariant x · y = k holds across swaps
Larger swaps → worse price (curve gets steeper)
0.3% fee on the input goes to LPs
No price ranges — liquidity spread across all prices
Foundation of nearly every AMM that followed
The Sandwich Bot attacks — common mistakes
Forgetting the fee is applied to input, not output
Thinking price impact is linear (it is convex)
Ignoring slippage on the second swap (compounds)
Confusing the invariant k with the price
Boss battleRun two consecutive 100-unit swaps on a 1000/1000 pool and show k is preserved while price impact rises on the second.
Example code
<!doctype html><html><head><meta charset="utf-8"></head>
<body style="background:#06040d;color:#e6e0ff;font-family:monospace;padding:20px"><pre id="o"></pre>
<script>
function swap(x, y, dxIn){
const dxFee = dxIn * 0.997;
const k = x * y;
const newX = x + dxFee;
const newY = k / newX;
const dy = y - newY;
return { dxIn, dy, newX, newY, k, kNew: newX*newY, priceOut: dy/dxIn };
}
let pool = { x:1000, y:1000 };
const r1 = swap(pool.x, pool.y, 100);
pool = { x:r1.newX, y:r1.newY };
const r2 = swap(pool.x, pool.y, 100);
document.getElementById('o').textContent = [
'pool start: x=1000, y=1000, k=1,000,000',
'',
'swap #1: dx=100 → dy=' + r1.dy.toFixed(3) + ' (price: ' + r1.priceOut.toFixed(4) + ')',
' new pool: x=' + r1.newX.toFixed(2) + ', y=' + r1.newY.toFixed(2) + ' k=' + r1.kNew.toFixed(0),
'',
'swap #2: dx=100 → dy=' + r2.dy.toFixed(3) + ' (price: ' + r2.priceOut.toFixed(4) + ' ← WORSE)',
' new pool: x=' + r2.newX.toFixed(2) + ', y=' + r2.newY.toFixed(2),
'',
'invariant k preserved across both swaps; price impact compounds'
].join('\n');
</script></body></html>