ERC-20: The Standard for Fungible Tokens

Introduction

ERC-20 is the most widely used Ethereum token standard for fungible tokens, meaning each token is identical and interchangeable (e.g., USDT, DAI, LINK). It defines a set of rules that all Ethereum-based tokens must follow.

Architecture

An ERC-20 token smart contract includes:

  • Balance Mapping: Stores token balances for each address

  • Total Supply: Defines the total number of tokens created

  • Transfer Mechanism: Allows tokens to be sent between addresses

  • Allowance Mechanism: Enables third-party contracts to spend tokens on behalf of users

Key Functions of ERC-20

Function
Description

totalSupply()

Returns total token supply

balanceOf(address)

Returns the balance of an address

transfer(address, uint256)

Transfers tokens to another address

approve(address, uint256)

Allows a spender to use a set amount

transferFrom(address, address, uint256)

Transfers tokens using the allowance

allowance(address, address)

Checks how many tokens a spender can use

Workflow of ERC-20 Transactions

  1. Token Deployment: The ERC-20 smart contract is deployed on Ethereum.

  2. Minting: The contract owner mints tokens.

  3. Transfer: Users can send tokens to other addresses using transfer().

  4. Approval & Spending:

    • User A calls approve(spender, amount), allowing Spender to use a specific amount.

    • Spender calls transferFrom(userA, userB, amount) to transfer the tokens.

Example: ERC-20 Smart Contract

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

contract MyERC20Token {
    string public name = "MyToken";
    string public symbol = "MTK";
    uint8 public decimals = 18;
    uint256 public totalSupply = 1000000 * 10**18;
    
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

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

    constructor() {
        balanceOf[msg.sender] = totalSupply;
    }

    function transfer(address _to, uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value, "Insufficient balance");
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    function approve(address _spender, uint256 _value) public returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value, "Insufficient balance");
        require(allowance[_from][msg.sender] >= _value, "Allowance exceeded");
        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        allowance[_from][msg.sender] -= _value;
        emit Transfer(_from, _to, _value);
        return true;
    }
}

ERC-20 Token Flow

[ User A ]  ---> (transfer 100 tokens) --->  [ User B ]
[ DApp ]   ---> (approve & transferFrom) ---> [ Marketplace ]

Last updated

Was this helpful?