Codementor Events

Create a decentralized exchange (DEX) for ERC-20 token

Published Mar 09, 2022
Create a decentralized exchange (DEX) for ERC-20 token

This is the first part in a probably very long series of posts.
In this post, I'll be explaining how to create a basic decentralized exchange for an ERC-20 token.

Expectations

This post assumes basic knowledge of solidity, the ERC standard, and creating a basic ERC20 token

Creating the ERC20 token

We'll create a basic ERC20 token by importing the ERC20.sol from Openzeppelin. Our token will be named TSTtoken and it's gonna have a total supply of 1 million.

// TSTtoken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";

contract TSTtoken is ERC20 {

uint256 initialSupply = 1000000e18;
    constructor() ERC20("Test", "TST") {
        _mint(msg.sender, initialSupply);
    }
}

Next we will create the smart contract for our DEX in DEX.sol.

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; 

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
import './TSTtoken.sol'; 

contract DEX { 
    IERC20 public token; 
    event Bought(uint256 amount); 
    event Sold(uint256 amount); 
    
    constructor(){ 
        token = new TSTtoken(); 
    } 
    
    function buy() payable public { 
         // TODO
    } 
 
    function sell(uint256 amount) public { 
        // TODO
    } 
}

Our DEX contract has two functions

buy: The user can send ether and receive TSTtoken in exchange

sell: The user can send TSTtoken and get back ether

The Buy Function

To code the buy function, we'll have to check the amount ether being sent to the contract in the message (i.e msg.value) and verify that the contract owns enough TSTtoken. If the contract has enough TSTtoken, it sends it to the user and emits the Bought event.

Note:

For simplicity, we'll exchange 1 TSTtoken for 1 Wei

    function buy() payable public {
        uint256 amountTobuy = msg.value; 
        uint256 dexBalance = token.balanceOf(address(this)); 
        require(amountTobuy > 0, "You need to send some ether"); 
        require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
        token.transfer(msg.sender, amountTobuy); emit Bought(amountTobuy);
    }

I guess the buy function is pretty easy

The Sell Function

This function will require the user to have approved the sell amount by calling the ERC-20 approve function.

When the sell function is called, we'll call the ERC-20 transferFrom function to transfer the tokens from the caller address to the contract address. If the transfer is successful, we'll send the equivalent amount of Eth back to the caller address.

    function sell(uint256 amount) public { 
        require(amount > 0, "You need to sell at least some tokens"); 
        uint256 allowance = token.allowance(msg.sender, address(this));
        require(allowance >= amount, "Check the token allowance");
        token.transferFrom(msg.sender, address(this), amount);
        payable(msg.sender).transfer(amount); emit Sold(amount); 
    } 

Cool, we've just written a smart contract for a very basic DEX. Now anyone can buy and sell our token with Eth. Here is the complete code for the DEX.sol file.

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; 
import "https://github.com/OpenZeppelin/openzeppelincontracts/blob/master/contracts/token/ERC20/IERC20.sol";
import './TSTtoken.sol'; 

contract DEX { 

    IERC20 public token; 
    event Bought(uint256 amount); 
    event Sold(uint256 amount); 
    constructor() { 
        token = new TSTtoken(); 
    } 
    
    function buy() payable public {
        uint256 amountTobuy = msg.value; 
        uint256 dexBalance = token.balanceOf(address(this)); 
        require(amountTobuy > 0, "You need to send some ether"); 
        require(amountTobuy <= dexBalance, "Not enough tokens in the reserve");
        token.transfer(msg.sender, amountTobuy); emit Bought(amountTobuy);
    } 
    
    function sell(uint256 amount) public { 
        require(amount > 0, "You need to sell at least some tokens"); 
        uint256 allowance = token.allowance(msg.sender, address(this));
        require(allowance >= amount, "Check the token allowance");
        token.transferFrom(msg.sender, address(this), amount);
        payable(msg.sender).transfer(amount); emit Sold(amount); 
    } 
    
}

Ways to improve the DEX

  • Implement an exchange of TSTtoken to another ERC20 token e.g DAI, UNI etc

  • Add our fee on Buy and Sell of the token

  • Add the liquidity for TSTtoken with transaction fees generated to uniswap by implementing the addLiquidity/addLiquidityETH function

Discover and read more posts from Majid Kareem
get started