A13: DeFi Builder

Hard

Deploy Your Own DEX

Time Allocated: 75 minutes
Points: 60 (+10 bonus)
Group Size: 2-3 students
Materials Needed: Remix IDE (remix.ethereum.org), Price-tracking worksheet, L11 SimpleDEX contract code
Submission: Working DEX on Remix + completed worksheet + 3-minute group presentation

Overview

Decentralised exchanges (DEXes) are the backbone of DeFi, enabling permissionless token trading without intermediaries. In this hands-on assignment you will deploy your own mini DEX using the SimpleDEX contract from Lesson 11. You will create two ERC-20 tokens, provide liquidity, execute swaps, and observe how the constant-product formula x × y = k determines prices in real time.

Learning Objectives

  • Deploy and interact with multiple Solidity contracts on Remix IDE
  • Understand how an automated market maker (AMM) prices assets using x × y = k
  • Observe price impact and slippage through hands-on experimentation
  • Analyse how reserve ratios change after successive swaps
  • Present technical findings clearly to peers

Prerequisites

Activity Structure

1 Deploy Two ERC-20 Tokens (15 minutes)

Each group deploys two custom ERC-20 tokens. Use the MyToken contract from L10 or the simplified version below.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; contract MyToken { string public name; string public symbol; uint8 public decimals = 18; uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; constructor(string memory _name, string memory _symbol, uint256 _supply) { name = _name; symbol = _symbol; totalSupply = _supply; balanceOf[msg.sender] = _supply; } function transfer(address _to, uint256 _amount) public returns (bool) { require(balanceOf[msg.sender] >= _amount, "Insufficient balance"); balanceOf[msg.sender] -= _amount; balanceOf[_to] += _amount; return true; } function approve(address _spender, uint256 _amount) public returns (bool) { allowance[msg.sender][_spender] = _amount; return true; } function transferFrom(address _from, address _to, uint256 _amount) public returns (bool) { require(balanceOf[_from] >= _amount, "Insufficient balance"); require(allowance[_from][msg.sender] >= _amount, "Allowance exceeded"); balanceOf[_from] -= _amount; balanceOf[_to] += _amount; allowance[_from][msg.sender] -= _amount; return true; } }
  1. Create a new file MyToken.sol in Remix and paste the code above
  2. Compile with Solidity 0.8.20 or later
  3. Deploy Token A with constructor arguments: name = your group's chosen name (e.g. "AlphaToken"), symbol (e.g. "ALPHA"), supply = 1000000
  4. Deploy Token B with a different name/symbol and the same supply
  5. Copy both contract addresses -- you will need them for the DEX

2 Deploy the SimpleDEX (10 minutes)

Deploy the SimpleDEX contract from Lesson 11. The constructor takes the addresses of your two tokens.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface IERC20 { function transferFrom(address from, address to, uint256 amount) external returns (bool); function transfer(address to, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); } contract SimpleDEX { IERC20 public tokenA; IERC20 public tokenB; uint256 public reserveA; uint256 public reserveB; event LiquidityAdded(address indexed provider, uint256 amountA, uint256 amountB); event Swap(address indexed trader, address tokenIn, uint256 amountIn, uint256 amountOut); constructor(address _tokenA, address _tokenB) { tokenA = IERC20(_tokenA); tokenB = IERC20(_tokenB); } function addLiquidity(uint256 _amountA, uint256 _amountB) external { tokenA.transferFrom(msg.sender, address(this), _amountA); tokenB.transferFrom(msg.sender, address(this), _amountB); reserveA += _amountA; reserveB += _amountB; emit LiquidityAdded(msg.sender, _amountA, _amountB); } function swap(address _tokenIn, uint256 _amountIn) external { require( _tokenIn == address(tokenA) || _tokenIn == address(tokenB), "Invalid token" ); bool isTokenA = (_tokenIn == address(tokenA)); (IERC20 tokenIn, IERC20 tokenOut, uint256 reserveIn, uint256 reserveOut) = isTokenA ? (tokenA, tokenB, reserveA, reserveB) : (tokenB, tokenA, reserveB, reserveA); tokenIn.transferFrom(msg.sender, address(this), _amountIn); uint256 amountOut = (reserveOut * _amountIn) / (reserveIn + _amountIn); require(amountOut > 0, "Insufficient output"); tokenOut.transfer(msg.sender, amountOut); if (isTokenA) { reserveA += _amountIn; reserveB -= amountOut; } else { reserveB += _amountIn; reserveA -= amountOut; } emit Swap(msg.sender, _tokenIn, _amountIn, amountOut); } }
  1. Create a new file SimpleDEX.sol in Remix
  2. Compile and deploy with the two token addresses as constructor arguments
  3. Copy the DEX contract address

3 Add Liquidity and Perform Swaps (25 minutes)

This is the core of the assignment. You will provide liquidity, execute swaps, and track how reserves and prices change.

  1. Approve the DEX: On each token contract, call approve(DEX_address, 500000) so the DEX can transfer tokens on your behalf
  2. Add initial liquidity: Call addLiquidity(100000, 100000) on the DEX. Record the initial reserves on your worksheet
  3. Swap 1 -- Small swap: Approve the DEX for Token A again if needed, then call swap(tokenA_address, 1000). Record the output amount and new reserves
  4. Swap 2 -- Medium swap: Call swap(tokenA_address, 10000). Record results
  5. Swap 3 -- Large swap: Call swap(tokenA_address, 50000). Record results
  6. Reverse swap: Now swap Token B back into Token A. Call swap(tokenB_address, 10000). Record results
  7. For each swap, calculate the effective price (tokens out / tokens in) and the price impact compared to the initial 1:1 ratio
Important: Before each swap, make sure you have approved enough tokens for the DEX to spend. Call approve() on the input token with the DEX address and the amount you want to swap. If a transaction reverts with "Allowance exceeded", you need to approve again.

4 Complete the Worksheet (10 minutes)

Fill in the price-tracking worksheet with your recorded data:

5 Group Presentation (15 minutes total -- 3 min/group)

Present your findings to the class:

Bonus Challenge (+10 points): After completing the core assignment, attempt one of these extensions:
  • Slippage Protection (+5 pts): Modify the swap function to accept a _minOut parameter and add require(amountOut >= _minOut, "Slippage too high")
  • Simple Escrow (+5 pts): Deploy the Escrow contract from L11 alongside your DEX and demonstrate a token-based escrow trade between group members

Deliverables

Item Points Description
Working DEX on Remix 30 Two ERC-20 tokens deployed, SimpleDEX deployed, liquidity added, at least 3 swaps executed successfully
Completed Worksheet 15 All swap data recorded, prices calculated, x × y = k verified, analysis questions answered
Group Presentation 15 Clear explanation of findings, price impact demonstration, real-world connection
Total 60
Bonus (slippage protection and/or escrow) +10 Optional advanced challenges

Tips for Success

Real-World Context: Uniswap, the largest DEX, uses this same constant-product formula. As of 2024, Uniswap has facilitated over $2 trillion in cumulative trading volume. The SimpleDEX you are building today implements the core pricing mechanism that powers billions of dollars in daily trades. The key insight: no order book, no matching engine, no intermediary -- just a mathematical formula and smart contract code.

Submission Instructions

  1. Keep your Remix session open so the instructor can verify your deployed contracts
  2. Submit the completed price-tracking worksheet (one per group) with all member names
  3. Be prepared to share your screen during your 3-minute presentation
  4. If you attempted the bonus challenge, include a brief note on your worksheet describing what you added

Related Resources

Rubric Answer Key Instructor Guide Worksheet

© Joerg Osterrieder 2025-2026. All rights reserved.