Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Real protocols are too big to hold in your head on the first attempt. The toy is the version where you cut every feature that isn't load-bearing, then implement the rest in <500 lines of code, then attack it. You don't ship the toy; you read what the toy taught you. The mistake is skipping the toy because the real version 'isn't that much bigger' — production code hides the mechanism behind two layers of abstractions and you stop being able to reason about it.
A toy AMM is x * y = k with one pair, no fees, no LP tokens, no router. ~80 lines of Solidity. A toy Optimistic Rollup is a sequencer that posts hashes to L1 and a single non-bisecting fraud-proof checker. Both miss every production feature — and both are sufficient to show whether the core mechanism works.
k = 10000 and verify against the contract's return value.swap() function. Note how much of it is feature scaffolding (callback for flash swaps, K invariant check with fees) vs. the actual x*y=k reasoning. The toy isolates the latter.// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ToyAMM {
address public tokenA;
address public tokenB;
uint256 public reserveA;
uint256 public reserveB;
constructor(address _a, address _b) { tokenA = _a; tokenB = _b; }
function addLiquidity(uint256 a, uint256 b) external {
// No LP tokens, no rebalancing, no fees. The toy is just the invariant.
IERC20(tokenA).transferFrom(msg.sender, address(this), a);
IERC20(tokenB).transferFrom(msg.sender, address(this), b);
reserveA += a; reserveB += b;
}
// x*y=k: the only rule. amountOut = reserveB - (reserveA*reserveB) / (reserveA+amountIn)
function swapAforB(uint256 amountIn) external returns (uint256 out) {
uint256 k = reserveA * reserveB;
IERC20(tokenA).transferFrom(msg.sender, address(this), amountIn);
reserveA += amountIn;
uint256 newReserveB = k / reserveA;
out = reserveB - newReserveB;
reserveB = newReserveB;
IERC20(tokenB).transfer(msg.sender, out);
}
}
interface IERC20 { function transferFrom(address,address,uint256) external returns (bool); function transfer(address,uint256) external returns (bool); }