Fatskills
Practice. Master. Repeat.
Study Guide: Blockchain and Web3 Development: DeFi and Tokenomics - Automated Market Makers, Uniswap V2/V3, Constant Product Formula
Source: https://www.fatskills.com/cryptocurrency-bitcoin-blockchain-and-more/chapter/blockchain-and-web3-development-blockchain-and-web3-development-defi-and-tokenomics-automated-market-makers-uniswap-v2v3-constant-product-formula

Blockchain and Web3 Development: DeFi and Tokenomics - Automated Market Makers, Uniswap V2/V3, Constant Product Formula

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~5 min read

Study Guide – Automated Market Makers (Uniswap V2/V3, Constant Product Formula)


What This Is

An Automated Market Maker (AMM) is a smart?contract?based liquidity pool that replaces order?books with a simple math rule—most famously the constant?product formula?x?*?y?=?k. Anyone can deposit two tokens, and traders can swap against the pool instantly, without needing a counter?party. The first real?world proof?of?concept is Uniswap, where a user swaps 1?ETH for ~2,500?USDC in a single transaction, and the price automatically adjusts according to the pool’s balances.


Key Terms & Code Snippets

  • AMM (x·y?=?k) – The core invariant: the product of the two token reserves (x and y) stays constant (k). When you add one token, the other must be removed to keep k unchanged.
  • Liquidity Provider (LP) – An address that deposits equal?value amounts of two ERC?20 tokens into a pool and receives LP tokens representing its share.
  • LP Token (ERC?20) – A receipt minted by the pool contract; holders can later redeem it for the underlying assets plus accrued fees.
  • Swap Fee (e.g., 0.30?%) – A small percentage taken from each trade and credited to LPs; in Uniswap?V3 the fee tier is selectable per pool.
  • Tick & Price Range (V3) – V3 lets LPs concentrate liquidity in a custom price interval (tickLower?/?tickUpper), dramatically improving capital efficiency.
  • getAmountOut (Solidity) – Helper that applies the constant?product formula and fee to compute how many output tokens a swap will return.

solidity function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint) { uint amountInWithFee = amountIn * 997; // 0.30% fee-1000?3 uint numerator = amountInWithFee * reserveOut; uint denominator = reserveIn * 1000 + amountInWithFee; return numerator / denominator; }

  • swap (V2 Router) – The external function a dApp calls to trade tokens; it pulls the input token, runs the invariant check, and sends the output token.

js const tx = await router.swapExactTokensForTokens( ethers.utils.parseUnits('1.0', 18), // amountIn 0, // amountOutMin (slippage) [tokenA.address, tokenB.address], // path wallet.address, // to Math.floor(Date.now() / 1000) + 60 // deadline );

  • sqrtPriceX96 (V3) – Fixed?point Q64.96 representation of the current price; used for precise math without floating?point errors.
  • feeGrowthGlobalX128 – Tracks cumulative fees per unit of liquidity; LPs claim fees by comparing the current value with the snapshot taken when they minted LP tokens.
  • delegatecall vs call – V3 pools use delegatecall to execute user?provided hooks (e.g., flash swaps) while preserving the pool’s storage context.

Step?by?Step / Process Flow

  1. Write the Pool Contract – Clone the Uniswap V2 core repo or use the V3 periphery library. In Remix, add UniswapV2Pair.sol (or UniswapV3Pool.sol) and import OpenZeppelin’s ERC?20.
  2. Compile with Hardhat – Run npx hardhat compile using Solidity?0.8.19 (the version Uniswap V3 ships with).
  3. Deploy to a Testnet

bash npx hardhat run scripts/deploy.js --network goerli

The script should:
- Deploy the factory (UniswapV2Factory or UniswapV3Factory).
- Call createPair(tokenA, tokenB) (V2) or createPool(tokenA, tokenB, fee) (V3).

4. Add Liquidity – Using Ethers.js, approve both tokens, then call addLiquidity (V2) or mint (V3) with the desired price range.

5. Swap via Router – In your front?end, instantiate UniswapV2Router02 (or V3 router) and invoke swapExactTokensForTokens. Verify the output amount matches the getAmountOut calculation.


Common Mistakes

  • Mistake: Supplying unequal token values when creating a V2 pair.
    Correction: Always deposit tokens with the same USD value; otherwise the pool starts with a skewed price and LPs lose capital.

  • Mistake: Forgetting to approve the router contract before calling swap.
    Correction: Call token.approve(router.address, amount) first; otherwise the transaction reverts with “ERC20: transfer amount exceeds allowance”.

  • Mistake: Using tx.origin for access control in a flash?swap callback.
    Correction: Use msg.sender (or a role?based onlyOwner) because tx.origin can be spoofed through a malicious contract, opening a re?entrancy vector.

  • Mistake: Ignoring the price?range parameter in V3 and depositing liquidity across the entire curve.
    Correction: Choose a tight tick range around the current price to earn higher fees per capital; otherwise you earn the same as V2 but pay higher gas.

  • Mistake: Relying on block.timestamp for deadline checks in the router.
    Correction: Use a reasonable buffer (e.g., now + 300) and enforce a maximum slippage; miners can manipulate timestamps by up to ~15?seconds.


Blockchain Developer Interview / Practical Insights

  1. “Explain why an AMM can’t guarantee a specific price.” – Interviewers expect you to mention the invariant (x·y?=?k) and that price is derived from pool balances, which shift with each trade.
  2. “Differentiate Uniswap V2’s constant?product from V3’s concentrated liquidity.” – Highlight that V2 uses a single global k, while V3 splits liquidity into ticks allowing LPs to allocate capital where they expect most trades.
  3. “What are the gas?implications of using delegatecall in a V3 pool?” – Show you know that delegatecall preserves storage but adds ~10?k gas overhead; it’s acceptable for flash?swap hooks but should be minimized.
  4. “How would you audit the fee?distribution logic?” – Mention checking feeGrowthGlobalX128 updates, ensuring LPs can’t claim more than their share, and verifying that rounding errors are handled with uint128 arithmetic.

Quick Check Questions

  1. Scenario: A contract calls router.swapExactETHForTokens but sets amountOutMin = 0.
    Answer: This opens a front?running risk; the attacker can push the price just before the swap, causing the user to receive far fewer tokens. Always set a realistic amountOutMin based on slippage tolerance.

  2. Scenario: An LP adds liquidity to a V3 pool with tickLower = -887272 and tickUpper = 887272.
    Answer: That’s the full?range (same as V2) and defeats V3’s capital efficiency; the LP will earn lower fees per capital compared to a concentrated range.

  3. Scenario: A developer uses require(reserve0 > 0 && reserve1 > 0) inside the swap function.
    Answer: The check is unnecessary because the invariant already prevents division?by?zero; it adds extra gas and can block legitimate first?swap initialization.


Last?Minute Cram Sheet (10 one?liners)

  1. Never trust tx.origin for auth – it can be hijacked via a malicious contract.
  2. k = reserve0 * reserve1 – the constant?product invariant; any deviation reverts the swap.
  3. V2 fee = 0.30?%-multiplier 997/1000 – used in getAmountOut.
  4. V3 fee tiers: 0.05?%, 0.30?%, 1?% (encoded as 500, 3000, 10000).
  5. sqrtPriceX96 = price * 2^96; use FullMath.mulDiv for precise arithmetic.
  6. Gas tip: Store reserves in a single uint112 slot (reserve0, reserve1) to stay under the 32?byte slot limit.
  7. Compiler version: Uniswap V3 contracts compile cleanly with pragma solidity ^0.8.19;.
  8. LP token decimals = 18 – matches ERC?20 standard; use balanceOf to compute share.
  9. Flash swap: Call swap with amount0Out or amount1Out >?0 and implement uniswapV2Call (V2) or uniswapV3SwapCallback (V3).
  10. Common attack vector: price manipulation via large single swaps; mitigate with maxSwap limits or time?weighted average price (TWAP) oracles.