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);
}
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;
}
}
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;
}
}
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);
}
}
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);
}
}
Top comments (0)