📦 Interactive Contract Explorer

Click on any contract to expand and see its key functions. Uniswap V2 has just 3 core contracts — elegant simplicity.

🏭
UniswapV2Factory
0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f

Registry of all pairs. Creates new pair contracts using CREATE2 for deterministic addresses.

createPair(tokenA, tokenB)
returns address pair
Deploys a new Pair contract for two tokens. Uses CREATE2 so the address is deterministic.
getPair(tokenA, tokenB)
returns address pair
Returns the pair address for two tokens (or address(0) if it doesn't exist).
allPairs(uint index)
returns address pair
Returns the pair at the given index. Use allPairsLength() to iterate.
feeTo()
→ address
Protocol fee recipient. If set, 1/6th of LP fees go here (governance controlled).
💱
UniswapV2Pair
Deterministic per token pair (CREATE2)

The core contract. Holds reserves, executes swaps, mints/burns LP tokens. One per trading pair.

swap(amount0Out, amount1Out, to, data)
Core swap. Sends tokens optimistically, then verifies k invariant. If data is non-empty, it's a flash swap.
mint(to)
→ uint liquidity
Mints LP tokens proportional to deposited reserves.
burn(to)
→ (uint amount0, uint amount1)
Burns LP tokens, returns proportional share of both reserves.
getReserves()
→ (uint112, uint112, uint32)
Returns cached reserves and last block timestamp. Used for price calculations and TWAP.
price0CumulativeLast()
→ uint
TWAP oracle accumulator. Updated every block with price×time.
📡
UniswapV2Router02
0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D

User-facing contract. Handles token approvals, multi-hop paths, deadline checks, and ETH wrapping.

swapExactTokensForTokens(amountIn, amountOutMin, path, to, deadline)
Swap exact input for minimum output. Path is an array of token addresses defining the route.
swapTokensForExactTokens(amountOut, amountInMax, path, to, deadline)
Swap up-to-max input for exact output amount.
addLiquidity(tokenA, tokenB, amountADesired, ...)
Add liquidity to a pair. Calculates optimal amounts and mints LP tokens.
removeLiquidity(tokenA, tokenB, liquidity, ...)
Remove liquidity by burning LP tokens and receiving both underlying tokens.

🔄 Animated Transaction Flow

Follow a swap transaction as it travels from your wallet through the Router, Factory, and Pair contracts.

🔮 CREATE2 Address Derivation

Uniswap uses CREATE2 to compute pair addresses deterministically — no need to query the Factory. Enter two token addresses to see how it works.

// CREATE2 address derivation:
// pair = keccak256(0xff, factory, keccak256(tokenA, tokenB), initCodeHash)
//
// 1. Sort tokens: token0 < token1 (lexicographic)
// 2. salt = keccak256(abi.encodePacked(token0, token1))
// 3. address = keccak256(0xff ++ factory ++ salt ++ init_code_hash)[12:]
//
// This means anyone can compute the pair address offline!
// No need to call the Factory contract.

Factory:  0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
Token A:  0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 (WETH)
Token B:  0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (USDC)

→ Pair:   0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc (ETH/USDC)
Why CREATE2? Deterministic addresses mean any contract or off-chain code can compute the pair address without an on-chain call. This saves gas and enables efficient routing.

⚡ Flash Swap Walkthrough

Flash swaps let you receive tokens before paying for them — as long as you pay back (with fee) in the same transaction. Powerful for arbitrage, liquidations, and collateral swaps.

1
Request Tokens
Call swap() with data ≠ empty bytes
2
Receive Tokens
Pair sends you tokens FIRST (optimistic transfer)
3
Callback
Pair calls uniswapV2Call() on your contract
4
Do Anything
Arb, liquidate, swap on another DEX...
5
Repay
Return tokens + 0.3% fee. If you can't → revert!
// Example: Flash swap arbitrage
contract FlashArb {
    function execute(address pair, uint amount) external {
        // Step 1: Request tokens (triggers flash swap)
        IUniswapV2Pair(pair).swap(amount, 0, address(this), bytes("flash"));
    }

    function uniswapV2Call(address sender, uint amount0, uint amount1, bytes data) external {
        // Step 4: We have the tokens! Do something profitable...
        uint profit = doArbitrage(amount0);

        // Step 5: Repay with fee
        uint fee = amount0 * 3 / 997 + 1;
        IERC20(token).transfer(msg.sender, amount0 + fee);
    }
}
Atomic guarantee: If you can't repay, the entire transaction reverts — including the initial token transfer. You never risk the pool's funds. This is the same principle as flash loans.