Create a decentralized exchange (DEX) for ERC-20 token 
Tags: web3, blockchain, ethereum
Published: 2022-03-09 00:06:18

This is the first part in a probably very long series of posts.
In this post, I'll be explaining how to create a 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.

```solidity
// 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`.

```solidity
//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

```solidity
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.

```solidity
  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.

```solidity
//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 {
        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 a 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](https://docs.uniswap.org/protocol/V2/reference/smart-contracts/router-02#addliquidity)