By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Study Guide – Automated Market Makers (Uniswap V2/V3, Constant Product Formula)
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.
x?*?y?=?k
x
y
k
tickLower
tickUpper
getAmountOut
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
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
feeGrowthGlobalX128
delegatecall
call
UniswapV2Pair.sol
UniswapV3Pool.sol
npx hardhat compile
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.
UniswapV2Factory
UniswapV3Factory
createPair(tokenA, tokenB)
createPool(tokenA, tokenB, fee)
addLiquidity
mint
UniswapV2Router02
swapExactTokensForTokens
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”.
token.approve(router.address, amount)
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.
tx.origin
msg.sender
onlyOwner
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.
block.timestamp
now + 300
x·y?=?k
uint128
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.
router.swapExactETHForTokens
amountOutMin = 0
amountOutMin
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.
tickLower = -887272
tickUpper = 887272
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.
require(reserve0 > 0 && reserve1 > 0)
k = reserve0 * reserve1
500
3000
10000
price * 2^96
FullMath.mulDiv
uint112
reserve0
reserve1
pragma solidity ^0.8.19;
balanceOf
amount0Out
amount1Out
uniswapV2Call
uniswapV3SwapCallback
maxSwap
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.