ERC20 from the ground up

Building Your Own Magic Token: A Beginner’s Guide

Have you ever played a video game where you collect coins or stars? Imagine creating your own special coin that you can share with friends or use in a game. That’s kind of like making a token on the Ethereum blockchain! Let’s learn how to create a simple token, step by step, like a digital piggy bank you can program. 🪙

What is an ERC20 Token?

An ERC20 token is like a magical digital coin that lives on the Ethereum network. The ERC20 standard is a set of rules that every token follows so it can be used in different apps, games, and exchanges — just like how we all agree that a soccer ball is round and can be kicked to score a goal.

Why Create a Token?

  • Money for games: You can create coins players can earn and spend.

  • Voting power: People can use tokens to vote on decisions.

  • Rewards and points: Like collecting stars for doing something awesome!

Where Are Tokens Used?

  • Uniswap (UNI): Trade tokens like a digital marketplace.

  • Aave (AAVE): Borrow or lend tokens to earn rewards.

  • Compound (COMP): Save tokens and earn extra tokens over time!

Let’s Build a Simple Token!

Here’s the magic recipe (code) to create your own token. It’s like telling a robot how your coin should work.

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

contract ERC20 {
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;
    address public owner;

    mapping(address => uint256) public balances;
    mapping(address => mapping(address => uint256)) public allowances;

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

    constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _totalSupply) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
        totalSupply = _totalSupply;
        owner = msg.sender;
        balances[owner] = _totalSupply;
    }

    function balanceOf(address account) public view returns (uint256) {
        return balances[account];
    }

    function transfer(address to, uint256 amount) public returns (bool) {
        require(to != address(0), "Invalid address");
        require(amount > 0, "Amount must be greater than zero");
        require(balances[msg.sender] >= amount, "Insufficient balance");

        balances[msg.sender] -= amount;
        balances[to] += amount;

        emit Transfer(msg.sender, to, amount);
        return true;
    }

    function approve(address spender, uint256 amount) public returns (bool) {
        require(spender != address(0), "Invalid address");
        allowances[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function allowance(address _owner, address spender) public view returns (uint256) {
        return allowances[_owner][spender];
    }

    function transferFrom(address from, address to, uint256 amount) public returns (bool) {
        require(from != address(0) && to != address(0), "Invalid address");
        require(amount > 0, "Amount must be greater than zero");
        require(balances[from] >= amount, "Insufficient balance");
        require(allowances[from][msg.sender] >= amount, "Allowance exceeded");

        allowances[from][msg.sender] -= amount;
        balances[from] -= amount;
        balances[to] += amount;

        emit Transfer(from, to, amount);
        return true;
    }
}

What Does This Code Do?

  • Create the token: Name, symbol, and how many coins exist.

  • Check balances: See how many tokens someone has.

  • Send tokens: Move tokens from one account to another.

  • Approve spending: Let someone else spend tokens for you (like giving your friend some game credits).

Testing Your Token

Imagine testing your token like trying out a new board game to make sure the rules work.

import {
    time,
    loadFixture,
  } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { expect } from "chai";
import hre from "hardhat";
import { Signer } from "ethers";

describe("ERC20", function () {

    async function deployErc20() {

        const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'

        const [owner, otherAccount] = await hre.ethers.getSigners();

        const Token = await hre.ethers.getContractFactory("ERC20");
        const token = await Token.deploy("JAYTOKEN", "JAY", 18);

        return { owner, otherAccount, ADDRESS_ZERO, token };
      }

    it("Should deploy with initial supply", async function () {
        it("Should deploy the contract", async () => {
            const { token, ADDRESS_ZERO } = await deployErc20();
            expect(token.target).to.be.not.equal(ADDRESS_ZERO);
        });
    });
});

Wrap-Up

Creating a token is like inventing your own digital treasure. With just a bit of code, you can build tokens for games, communities, or even start your own mini economy. The possibilities are endless ; so keep learning and dreaming big.