DEV Community

Bagas Hariyanto
Bagas Hariyanto

Posted on

ERC20 in Web3 Smart Contract

Token standard is essential in Web3 Smart Contract development because it ensure Interoperability, compatibility, Security and Community. That mean the smart contract can be used on all Dapp, have compatibility to any Wallet for example Metamask, follow security standard that safe and tested, also has maintained tools and library to develop it. In this article I want to share about Token standard in Web3, ERC20 or known as Fungible Token.

ERC20

ERC20 also known as Fungible Token is a standard to make a Token that can be tradeable (Fungible), and each Token has the same value. The example of this Token in real-life is USDT, BNB, etc.

ERC20 Interface

Each ERC20 token must have this function:

interface IERC20 {
    // Total supply token
    function totalSupply() external view returns (uint256);

    // Balance dari address
    function balanceOf(address account) external view returns (uint256);

    // Transfer token
    function transfer(address to, uint256 amount) external returns (bool);

    // Approve spending
    function approve(address spender, uint256 amount) external returns (bool);

    // Check allowance
    function allowance(address owner, address spender) external view returns (uint256);

    // Transfer from (by approved spender)
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    // Events
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
Enter fullscreen mode Exit fullscreen mode

Setup Contract

Make a file named FungibleToken.sol

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

/**
 * @title FungibleToken
 * @dev ERC20 Token implementation from scratch
 */
contract FungibleToken {
    // Token metadata
    string public name;
    string public symbol;
    uint8 public decimals;

    constructor() {
        name = "My First Token";
        symbol = "MFT";
        decimals = 18;
    }
}
Enter fullscreen mode Exit fullscreen mode

Define Key Variables

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

contract FungibleToken {
    string public name;
    string public symbol;
    uint8 public decimals;

    // Total supply token yang ada
    uint256 public totalSupply;

    // Mapping address -> balance
    mapping(address => uint256) public balanceOf;

    // Mapping owner -> spender -> amount
    // Untuk approve mechanism
    mapping(address => mapping(address => uint256)) public allowance;

    constructor() {
        name = "My First Token";
        symbol = "MFT";
        decimals = 18;
    }
}
Enter fullscreen mode Exit fullscreen mode

Event and Basic Mint

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

contract FungibleToken {
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    // Events (wajib untuk ERC20!)
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    constructor() {
        name = "My First Token";
        symbol = "MFT";
        decimals = 18;
    }

    /**
     * @dev Mint new tokens
     * @param _to Address yang menerima token
     * @param _amount Jumlah token (dalam wei)
     */
    function mint(address _to, uint256 _amount) public {
        // Validasi input
        require(_to != address(0), "Mint to zero address");
        require(_amount > 0, "Amount must be greater than 0");

        // Update state
        totalSupply += _amount;
        balanceOf[_to] += _amount;

        // Emit event
        emit Transfer(address(0), _to, _amount);
    }
}
Enter fullscreen mode Exit fullscreen mode

Access Control

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

contract FungibleToken {
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;

    address public owner;

    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);

    // Modifier untuk restrict ke owner
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this");
        _;
    }

    constructor() {
        name = "My First Token";
        symbol = "MFT";
        decimals = 18;
        owner = msg.sender;

        // Mint initial supply ke owner
        _mint(msg.sender, 1000000 * 10**decimals); // 1 juta token
    }

    /**
     * @dev Internal mint function
     */
    function _mint(address _to, uint256 _amount) internal {
        require(_to != address(0), "Mint to zero address");

        totalSupply += _amount;
        balanceOf[_to] += _amount;

        emit Transfer(address(0), _to, _amount);
    }

    /**
     * @dev Public mint (only owner)
     */
    function mint(address _to, uint256 _amount) public onlyOwner {
        require(_amount > 0, "Amount must be greater than 0");
        _mint(_to, _amount);
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)