ERC20 Implementation

What is Erc20

Firstly let's look at what ERC is and why ERC. ERC is known as Ethereum Request for Comment which refers to guidelines that developers must follow to implement some function-creating assets. ERC20 is regarded as a fungible token asset that is being used for transactions on the blockchain.

ERC20 is the standard fungible token being used on transactions on Ethereum. Developers must follow the Ethereum Request for Comment standard and guidelines when creating the ERC20 for such a token to interact with the Ethereum Ecosystem. Every blockchain has its fungible token which they have implemented. These tokens are being used for transaction fees which are known as gas fees, it also allows users to send each other tokens. This ensures interoperability between blockchain assets and blockchain DApps.

Use Cases:

  1. It can be used to create stablecoin which is mostly pegged to dollar rates,

  2. It can be used to tokenize real assets

  3. We can also use it to purchase goods and services

Examples of Dapps that are using Erc20:
Uniswap
is the first Ethereum-based DEX enabling the swapping of ERC-20 tokens via liquidity pools. Cowswap is a DEX facilitating trade of Ethereum-based tokens by matching supply with demand.

We will implement the ERC20 token standard with the Ethereum Request for Comment standard functionality.

We define the contract as not licensed (use with caution in production) , the pragma solidity is compiler version locked to 0.8.28 for security and reproducibility. Also declare our contract wrapper which will wrap our entire implementation.

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.28;

contract ERC20 {

}

Inside the ERc20 we will have our other implementations, We define our token name, symbol, token decimal which can 18 or 6, and declare our total supply.

contract ERC20 {
 string _name;       // Token name (e.g., "My Token")
    string _symbol;     // Token ticker (e.g., "MTK")
    uint8 _decimals;    // Token divisibility (typically 18)
    uint256 _totalSupply; // Total tokens in existence
}

we define the access control which define the address of the owner of the token which is defualted to address zero

   // Access Control
    address owner;      // Contract owner (uninitialized - default address(0))

Declare a storage to the balance of users who have the token and allowances of user we want to appvove to spend on our behave

 // Storage Mappings
    mapping(address => uint256) public balances;           // User balances
    mapping(address => mapping(address => uint256)) public allowances;

Declaration of custom errors to maximize the gas consumption of the smart contract, these errors handle different error instances

// Custom Errors
    error InvalidAddress();         // Invalid address used (e.g., address(0))
    error InsufficientFunds();      // Insufficient balance for operation
    error InsufficientAllowance();  // Approved amount too low
    error OnlyOwnerAllowed();       // Non-owner trying to call restricted function
    error InvalidAmount();          // Invalid operation amount (e.g., zero value)

These events are a way for smart contracts to communicate with each other and with external applications which will be emitted after the functions are excuted


    // Events
    event Transfer(address indexed _from, address indexed _to, uint256 _value);  // Token transfers
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);  // Approvals
    event Minted(address indexed _to, uint256 _value);  // Token minting (NOT emitted in current code)

This is a modifier to limit the access control on who can call some function which allows us to restrict access to any address except the owners address

 modifier onlyOwner() {
        if(msg.sender != owner) revert OnlyOwnerAllowed();
        _;  // Continue function execution if check passes
    }

We define a constructor function to initialize the ERC20 token contract and sets the token's name, symbol, decimals, and total supply, and assign the total supply to the owner's balance.


constructor() {
    _name = "ERC20"; // Token name
    _symbol = "ERC"; // Token symbol
    _decimals = 18; // Number of decimal places for the token
    _totalSupply = 1000000 * 10 ** uint256(_decimals); // Total supply of the token (1 million tokens with 18 decimals)
    owner = msg.sender; // Sets the owner of the contract to the account deploying it
    balances[owner] = _totalSupply; // Assigns the total supply of tokens to the owner's balance
}

Declaration of function to all state variables which we already declare above

 function name() public view returns (string memory) {
        return _name;  // Returns uninitialized string (needs constructor)
    }

    function symbol() public view returns (string memory) {
        return _symbol;  // Returns uninitialized string (needs constructor)
    }

    function decimals() public view returns (uint8) {
        return _decimals;  // Returns uninitialized value (typically should be 18)
    }

    function totalSupply() public view returns (uint256) {
        return _totalSupply;  // Returns current total token supply
    }

This function allows us to transfer tokens to the address that we input and the amount that we input from the person calling the smart contract, if it is successful it returns a bool

function transfer(address _to, uint256 _value) public returns (bool success) {
        if(_to == address(0)) revert InvalidAddress();
        if(_value > balances[msg.sender]) revert InsufficientFunds();

        // Update balances
        balances[msg.sender] -= _value;
        balances[_to] += _value;

        emit Transfer(msg.sender, _to, _value);  // Emit transfer event
        return true;
    }

This function allows users to transfer from one particular address to another address and the amount to be transfer

  function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        // Input validation
        if(msg.sender == address(0)) revert InvalidAddress();
        if(_to == address(0)) revert InvalidAddress();
        if(_from == address(0)) revert InvalidAddress();
        if(_value > balances[_from]) revert InsufficientFunds();

        // Check and update allowance
        if(allowances[_from][msg.sender] < _value) revert InsufficientAllowance();
        allowances[_from][msg.sender] -= _value;

        // Update balances
        balances[_from] -= _value;
        balances[_to] += _value;

        emit Transfer(_from, _to, _value);  // Emit transfer event
        return true;
    }

This function allows users to approve certain addresses and spend their tokens on their behalf mostly contract addresses. This allows contract address to spend or receive tokens

function approve(address _spender, uint256 _value) public returns (bool) {
        if(_spender == address(0)) revert InvalidAddress();
        // Non-standard check: Should NOT validate owner's balance for approval
        if(balances[msg.sender] < _value) revert InsufficientFunds();

        allowances[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);  // Emit approval event
        return true;
    }

The function checks the allowance of the user approves and returns the amount from the owner.

    function allowance(address _owner, address _spender) public view returns (uint256) {
        return allowances[_owner][_spender];  // Return approved amount
    }

This function allows the owner to mint to the total supply of the token deployed.

    function mint(address _to, uint256 _value) public onlyOwner returns (bool) {
        if(_to == address(0)) revert InvalidAddress();
        if(_value == 0) revert InvalidAmount();  // Should use >0 check (current ==0 allows 1+)

        _totalSupply += _value;
        balances[_to] += _value;

        return true;
    }

This is the implementation of the ERC20 Token standard for Ethereum.

0
Subscribe to my newsletter

Read articles from Muhdsodiq Bolarinwa directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Muhdsodiq Bolarinwa
Muhdsodiq Bolarinwa