DEV Community

Cover image for How to Create an ERC20 Token in Solidity
Abdul Maajid
Abdul Maajid

Posted on

How to Create an ERC20 Token in Solidity

Let’s start with the basics Understanding:

What is a Token?

Tokens can represent virtually anything in Ethereum:

  • reputation points in an online platform
  • skills of a character in a game
  • lottery tickets
  • financial assets like a share in a company
  • a fiat currency like USD
  • an ounce of gold
  • and many more...

What is an ERC-20 Token?

ERC stands for Ethereum Request for Comment, and 20 is the proposal identifier number. ERC-20 was designed to improve the ETH network.
An ERC20 token is a blockchain-based asset with similar functionality to bitcoin, ether, and bitcoin cash: it can hold value and be sent and received.
The ERC-20 introduces a standard for Fungible Tokens. In short they have a property that makes each Token be exactly the same type and value of another Token.

What makes ERC20 tokens so attractive and successful?
  1. ERC20 tokens are simple and easy to deploy, as you will see in this tutorial.
  2. It was the first popular specification to offer Ethereum token standardization. It was not by any means the first, but thanks to its popularity, it quickly became the industry standard.

Just like other Ethereum tokens, ERC20 tokens are implemented as smart contracts and executed on the Ethereum Virtual Machine (EVM) in a decentralized manner.

Creating your own ERC20 Token:

We will use Solidity to Create ERC-20 Token.
Solidity is an contract-oriented and statically-typed programming language that was designed to allow developers to create smart contracts.
ERC20 token need to implement the following methods and events:

Methods

ERC20 Methods

Events

ERC20 Events

In order to create an ERC20 token, you need the following:
  • The Token’s Name
  • The Token’s Symbol
  • The Token’s Decimal Places
  • The Number of Tokens in Circulation

Now Head over to the Ethereum Remix IDE and make a new Solidity file, for example - token.sol
Creating Contract File
Paste the following code into your new Solidity script:

pragma solidity ^0.8.0;

interface IERC20 {

    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);


    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}


contract SampleToken is IERC20 {
    using SafeMath for uint256;

    string public constant name = "SampleToken";
    string public constant symbol = "SMT";
    uint8 public constant decimals = 18;

    mapping(address => uint256) balances;
    mapping(address => mapping (address => uint256)) allowed;

    uint256 totalSupply_;

    constructor(uint256 total) public {
        totalSupply_ = total;
        balances[msg.sender] = totalSupply_;
    }

    function totalSupply() public override view returns (uint256) {
        return totalSupply_;
    }

    function balanceOf(address tokenOwner) public override view returns (uint256) {
        return balances[tokenOwner];
    }

    function transfer(address receiver, uint256 numTokens) public override returns (bool) {
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(msg.sender, receiver, numTokens);
        return true;
    }

    function approve(address delegate, uint256 numTokens) public override returns (bool) {
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;
    }

    function allowance(address owner, address delegate) public override view returns (uint) {
        return allowed[owner][delegate];
    }

    function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
        require(numTokens <= balances[owner]);
        require(numTokens <= allowed[owner][msg.sender]);

        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner, buyer, numTokens);
        return true;
    }
}

library SafeMath {
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
}

Enter fullscreen mode Exit fullscreen mode

We need to define two mapping objects. This is the Solidity notion for an associative or key/value array:

 mapping(address => uint256) balances;
 mapping(address => mapping (address => uint256)) allowed;
Enter fullscreen mode Exit fullscreen mode

The expression mapping(address => uint256) defines an associative array whose keys are of type address. a number used to denote account addresses, and whose values are of type uint256. Balances mapping, will hold the token balance of each owner account.

The second mapping object, allowed, will include all of the accounts approved to withdraw from a given account together with the withdrawal sum allowed for each.

After that we set the total amount of tokens at constructor (which is a special function automatically called by Ethereum right after the contract is deployed) and assign all of them to the “contract owner” i.e. the account that deployed the smart contract:

uint256 totalSupply_;
constructor(uint256 total) public {
  totalSupply_ = total;
  balances[msg.sender] = totalSupply_;
}
Enter fullscreen mode Exit fullscreen mode

Get Total Token Supply

This function will return the number of all tokens allocated by this contract regardless of owner.

function totalSupply() public view returns (uint256) {
  return totalSupply_;
}
Enter fullscreen mode Exit fullscreen mode

Get Token Balance of Owner

balanceOf will return the current token balance of an account, identified by its owner’s address.

function balanceOf(address tokenOwner) public view returns (uint256) {
   return balances[tokenOwner];
}
Enter fullscreen mode Exit fullscreen mode

Transfer Tokens to Another Account

The transfer function is used to move numTokens amount of tokens from the owner’s balance to that of another user, or receiver. The transferring owner is msg.sender i.e. the one executing the function.

function transfer(address receiver, uint256 numTokens) public returns (bool) {
    require(numTokens <= balances[msg.sender]);
    balances[msg.sender] = balances[msg.sender].sub(numTokens);
    balances[receiver] = balances[receiver].add(numTokens);
    emit Transfer(msg.sender, receiver, numTokens);
    return true;
}
Enter fullscreen mode Exit fullscreen mode

Approve user to Withdraw Tokens

This function is most often used in a token marketplace scenario. What approve does is to allow an owner i.e. msg.sender to approve a delegate account to withdraw tokens from his account and to transfer them to other accounts.

function approve(address delegate, uint256 numTokens) public returns (bool) {
   allowed[msg.sender][delegate] = numTokens;
   emit Approval(msg.sender, delegate, numTokens);
   return true;
}
Enter fullscreen mode Exit fullscreen mode

At the end of its execution, this function fires an Approval event.

Get Number of Tokens Approved for Withdrawal

This function returns the current approved number of tokens by an owner to a specific delegate, as set in the approve function.

function allowance(address owner, address delegate) public view returns (uint) {
   return allowed[owner][delegate];
}
Enter fullscreen mode Exit fullscreen mode

Transfer Tokens by Delegate

The transferFrom function is the peer of the approve function. It allows a delegate approved for withdrawal to transfer owner funds to a third-party account.

function transferFrom(address owner, address buyer,
                     uint numTokens) public returns (bool) {
  require(numTokens <= balances[owner]);
  require(numTokens <= allowed[owner][msg.sender]);

  balances[owner] = balances[owner] — numTokens;
  allowed[owner][msg.sender] =
        allowed[from][msg.sender] — numTokens;
  balances[buyer] = balances[buyer] + numTokens;
  Transfer(owner, buyer, numTokens);
  return true;
}
Enter fullscreen mode Exit fullscreen mode

SafeMath

We also used SafeMath Library for uint256 data type. SafeMath is a Solidity library aimed at dealing with one way hackers have been known to break contracts: integer overflow attack. In such an attack, the hacker forces the contract to use incorrect numeric values by passing parameters that will take the relevant integers past their maximal values.

Contract Deployment

Now Let's deploy our ERC20 Token to Ethereum Network. To Deploy Contract to Ethereum Network you will need to install the MetaMask plugin on your browser and a Ropsten (Ethereum test network) account with at least some Ropsten Ether in it.

Then, we will hop over to the second tab to the bottom called Compiler and click Compile.
Compile Contract
After compiled successfully Then, we will hop over to the third tab to the bottom called DEPLOY & RUN TRANSACTIONS. Then change the environment to Injected Web3. Make sure to select the appropriate contract from options.
Deploy Contract
And then enter total supply in highlighted box which you want for this token and click on deploy. A MetaMask popup will appear asking us to confirm the transaction. After approve your contract will be deployed which you can see in bottom section Deployed Contracts.
Deoployed

That’s it! your token contract is now deployed on Ethereum’s Ropsten testnet!

Congratulations on successfully creating your very own token/coin on the Ethereum network! Read more about the ERC-20 standard here.

Top comments (11)

Collapse
 
milo123459 profile image
Milo

Can you make a post about making a token on the Vite network? Better yet: With solidity++ (github.com/vitelabs/soliditypp)

Collapse
 
abdulmaajid profile image
Abdul Maajid

I will check this out..

Collapse
 
milo123459 profile image
Milo

Thank you!

Collapse
 
barnazaka profile image
my name

Hello Sir, Im having some errors, below is the screenshot.
Image description

Collapse
 
abdulmaajid profile image
Abdul Maajid

Hello!
May be you changed something in code because there is no error in code.
Update your code in remix and try to compile again.

Collapse
 
suhakim profile image
sadiul hakim

Can you create post about how to create a ERC721 token?

Collapse
 
abdulmaajid profile image
Abdul Maajid

Already created Check it out.
dev.to/abdulmaajid/how-to-create-a...

Collapse
 
roni_sommerfeld profile image
RoNi Sommerfeld

Hello, is it possible to use an ERC20 token inside a function of an ERC721 token?
To better explain what I want to do is as follows.
Before minting an ERC721 token (Item of my game) I want to check if the player has my token (ERC20) in his wallet, if he has he could mint it...
Is it possible to do that? Thanks.

Collapse
 
abdulmaajid profile image
Abdul Maajid

Hey

If you want to access/use ERC20 Token in any contract Just create an interface of ERC20 Token. And pass your erc20 contract address in this interface then you can access.
e.g. IERC20 token = IERC20(address)

Collapse
 
alx90s profile image
Alexander Härdrich • Edited

Hey man, when I created a new ERC20 token with a total token supply of 1000. Then I add 1000 more tokens via the _mint function to any address. Now I reach the limit of 1000 coins and we have a new amount of 2000. Is that possible ? Or is the _totalSuply just the initial amount and not the maximum ?

Collapse
 
abdulmaajid profile image
Abdul Maajid

Yes but you have to add function mint. which will mint new tokens for specific users.