Creating an ERC-20 token is a foundational step in Ethereum blockchain development. ERC-20 is a technical standard for smart contracts on the Ethereum blockchain for implementing tokens. These tokens are interoperable with a wide range of decentralized applications (DApps), wallets, and exchanges that support Ethereum.
This tutorial will guide you through writing and deploying a simple ERC-20 token using Solidity, the Remix IDE, and MetaMask.
Prerequisites
Before starting, ensure you have the following:
- MetaMask wallet installed and configured
- Access to Remix IDE (https://remix.ethereum.org/)
- Basic understanding of Solidity and Ethereum
- Testnet ETH for deploying the contract (Goerli or Sepolia)
Step 1: Understand the Standard ERC-20 Functions
ERC-20 defines a set of functions and events that a token smart contract must implement. These include:
- name: The token’s name
- symbol: A short symbol (e.g., ETH, USDT)
- decimals: How divisible the token is (commonly 18)
- totalSupply: The total token supply
- balanceOf: Returns the balance of a given address
- transfer: Transfers tokens to a specified address
- approve: Allows a third party to spend tokens
- transferFrom: Transfers tokens on behalf of an approved address
- allowance: Returns how many tokens an address can spend on behalf of the owner
Step 2: Write the ERC-20 Smart Contract
Open Remix IDE and create a new file named MyToken.sol
. Paste the following Solidity code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyToken {
string public name = "MyToken";
string public symbol = "MTK";
uint8 public decimals = 18;
uint public totalSupply = 1000000 * 10 ** uint(decimals);
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
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;
return true;
}
function approve(address spender, uint256 value) public returns (bool success) {
allowance[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;
return true;
}
}
Step 3: Compile the Contract
- In Remix, click on the “Solidity Compiler” tab.
- Select the appropriate compiler version (for example, 0.8.0 or later).
- Click “Compile MyToken.sol”.
Step 4: Deploy the Contract
- Click the “Deploy and Run Transactions” tab.
- Choose “Injected Web3” as the environment to connect with MetaMask.
- Ensure you are on a test network like Goerli or Sepolia in MetaMask.
- Click “Deploy” and approve the transaction in MetaMask.
Step 5: Interact with the Deployed Contract
Once deployed, you can interact with the following functions directly from Remix:
- balanceOf: Check the balance of any Ethereum address
- transfer: Send tokens to another wallet address
- approve and transferFrom: Delegate token spending authority to other addresses
Step 6: Testing with Testnet ETH
To fully test your token:
- Use a faucet to obtain test ETH.
- Transfer some of your tokens to other addresses.
- Use approve and transferFrom to simulate third-party transfers.
- Observe changes using balanceOf and allowance.
Security Considerations for Production
If you plan to release a token in a real-world environment:
- Use the OpenZeppelin ERC-20 implementation, which is professionally audited.
- Emit events such as Transfer and Approval for transparency and tracking.
- Add access controls using Ownable or similar mechanisms.
- Avoid hardcoding critical values unless necessary.
- Thoroughly audit your smart contract for vulnerabilities.
Alternative: Using OpenZeppelin’s ERC-20 Implementation
A safer and more concise way to build a token is to inherit from OpenZeppelin’s ERC-20 contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply);
}
}
This version automatically includes all required ERC-20 functions and safety checks.