How to Build Multi-Chain ERC-20 Creator With GetBlock RPC

by IleolamiMay 5th, 2025
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

The ERC-20 standard is a technical standard for creating and implementing tokens. It defines a set of rules and functions that a token contract must follow. This ensures that tokens can be easily exchanged and integrated with various decentralised applications (dApps) and platforms within the Ethereum ecosystem.

Company Mentioned

Mention Thumbnail

Coins Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - How to Build Multi-Chain ERC-20 Creator With GetBlock RPC
Ileolami HackerNoon profile picture
0-item

The Ethereum Request for Comment (ERC)-20 is a technical standard for creating and implementing tokens on the Ethereum blockchain. It defines a set of rules and functions that a token contract must follow. This ensures that tokens can be easily exchanged and integrated with various decentralised applications (dApps) and platforms within the Ethereum ecosystem. ERC-20 tokens can be used as rewards, company shares, a sense of identity in a community, or a means of exchange on Layer Two (L2) networks.


Tokens and coins are not the same. Coins are native currencies of Layer 1 blockchains, e.g. BTC for Bitcoin, ETH for Ethereum, and SOL for Solana, etc. Tokens, on the other hand, are cryptocurrencies built on top of existing blockchains, often using smart contracts, e.g. LINK, AAVE, UN,I etc


In this article, you will learn how to build a multi-chain ERC-20 generator using GetBlock RPC (a web3 RPC provider). This means users can create their token from a user interface without writing code, as seen below:

Prerequisites

  1. A web3 wallet, preferably Metamask
  2. A code editor, such as VSCode
  3. Must have installed Node
  4. A package manager installed on your machine, like yarn, npm, or pnpm
  5. Basic programming knowledge
  6. A bottle of water

Tools and Technologies Needed

  1. OpenZeppelin Contract
  2. A frontend framework(I will be using React)
  3. Ether.js
  4. TailwindCss for styling
  5. Smart contract

Setting Up Your GetBlock Account

  1. Sign up on GetBlock using either your Gmail, GitHub or Metamask wallet

  2. After signing up, you will be routed to your dashboard

  3. Scroll down to My endpoints

  4. Select your choice of protocol, network, and then click “Get”

  5. Automatically, a URL will be generated for you containing your access token

Ensure you keep this URL safe.Please note that you are on a free plan, which means you are limited to only two endpoints and cannot access other features like Usage Statistics. I encourage you to upgrade your account to enjoy more features.

Setting Up Your Dev Environment

  1. Create a new Folder with any name of your choice, e.g ERC-20-generator'

  2. Install the frontend framework of your choice

  3. Install Hardhat using the following command:

    //npm
    npm install --save-dev hardhat
    
    //yarn
    yarn add --dev hardhat
    
    //pnpm
    pnpm add -D hardhat
    
  4. Initialise hardhat using this command:

    npx hardhat init
    
  5. Select Create an empty hardhat.config.js using the arrow key and accept all prompts

    ileolami@MacBookAir erc-20 % npx hardhat init
    WARNING: You are currently using Node.js v23.9.0, which is not supported by Hardhat. This can lead to unexpected behavior. See https://hardhat.org/nodejs-versions
    
    
    888    888                      888 888               888
    888    888                      888 888               888
    888    888                      888 888               888
    8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
    888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
    888    888 .d888888 888    888  888 888  888 .d888888 888
    888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
    888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888
    
    👷 Welcome to Hardhat v2.23.0 👷‍
    
    ✔ What do you want to do? · Create an empty hardhat.config.js
    ✨ Config file created ✨
    
    Give Hardhat a star on Github if you're enjoying it! ⭐️✨
    
         https://github.com/NomicFoundation/hardhat
    
  6. Install other dependencies using this command:

    npm install --save-dev @nomicfoundation/hardhat-toolbox
    
    npm install @openzeppelin/contracts ether
    

You may also install your choice of CSS framework at this point

Writing and Compiling the ERC-20 Contract

You're only writing and compiling the ERC-20 contract for this project because it will serve as a template. Users will provide their token details, and deployment will be handled from the frontend.


  1. Create a new folder contract

  2. Create a new file token.sol and import the following code:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    
    contract XToken is ERC20 {
        constructor(string memory name, string memory symbol, uint256 initialSupply)
            ERC20(name, symbol)
        {
            _mint(msg.sender, initialSupply);
        }
    }
    
  • import "@openzeppelin/contracts/token/ERC20/ERC20.sol” : This imports the OpenZeppelin ERC20 implementation, which provides all standard ERC-20 functionality.

  • Inside XToken is ERC20, it defines the template in which the users will be able to create their token. After that, it mints the initialSupply tokens and assigns them to the address that deployed the contract (msg.sender)


  1. To compile this code, run the following command:

    npx hardhat compile
    


    This will compile the smart contract and generate an abi and bytecode. This JSON file is what you will use to interact with the smart contract. You will see this file under artifacts folder:

  2. In your src folder, create two new files and name them token.json and tokenBytecode.json respectively

  3. Copy the abi from XToken.json and paste it inside token.json using this format:

    {
    "abi": [
      ...
     ]
    }
    
  4. In the XToken.json file, scroll down, copy the bytecode, and paste it into tokenBytecode.json using this format:

    {
      "bytecode": "0x608060405234801561001057600080fd5b50604051..."
    }
    

Building the User Interface (UI)

Creating and Storing Access Tokens in .env

  1. Go to your GetBlock account and create multiple node endpoints.

I will be using Ethereum(Sepolia) and Rootstock Testnet.

  1. Create a .env file.

  2. Copy the endpoints you created earlier and store them in the .env file

    ROOTSTOCK_RPC=https://go.getblock.io/<ACCESS_TOKEN>
    ETHEREUM_RPC=https://go.getblock.io/<ACCESS_TOKEN>
    

Network Configuration

  1. Create a config folder under src directory

  2. Create a networks.jsx file and add this code:

    // Ensure to edit this code to suit your choice of networks. 
    export const networks = {
      ethereum: {
        chainId: 11155111,
        rpc: import.meta.env.ETHEREUM_RPC_URL,
        name: "Ethereum",
        nativeCurrency: {
          name: "ETH",
          symbol: "ETH",
          decimals: 18,
        },
        blockExplorer: "https://sepolia.etherscan.io",
      },
      rootstock: {
        chainId: 31, 
        rpc: import.meta.env.ROOTSTOCK_RPC_URL,
        name: "Rootstock",
        nativeCurrency: {
          name: "TRBTC",
          symbol: "TRBTC",
          decimals: 18,
        },
        blockExplorer: "https://rootstock-testnet.blockscout.com",
      },
    };
    

    You can list of networks’ detail here

Utility Functions

  1. Under src folder, create another subfolder and name it utils

  2. Under /utilsCreate two files called token.jsx and wallet.jsx


    At this point, your folder should be looking like this:

    /src
    ├── config/
    │   └── networks.js         # Network configuration
    │
    ├── utils/
    │   ├── tokenUtils.jsx      # Token deployment and wallet integration functions
    │   └── walletUtils.jsx     # Wallet connection and network switching functions
    │
    ├── App.jsx                 # Main TokenCreator component
    ├── index.css               # Global styles including glass effect
    ├── main.jsx                # Entry point for the React application
    ├── token.json              # ERC-20 token ABI
    └── tokenBytecode.json      # ERC-20 token bytecode
    
  3. Inside token.jsx , Copy and paste the following code:

    import { ethers } from "ethers";
    import XToken from "../token.json";
    import XTokenBytecode from "../tokenBytecode.json";
    
    export const deployToken = async (name, symbol, supply, signer) => {
      const factory = new ethers.ContractFactory(
        XToken.abi,
        XTokenBytecode.bytecode,
        signer
      );
    
      const contract = await factory.deploy(
        name,
        symbol,
        ethers.parseUnits(supply, 18)
      );
      
      await contract.waitForDeployment();
      const tokenAddress = await contract.getAddress();
      
      return tokenAddress;
    };
    
    export const addTokenToWallet = async (address, symbol) => {
      await window.ethereum.request({
        method: "wallet_watchAsset",
        params: {
          type: "ERC20",
          options: {
            address,
            symbol,
            decimals: 18,
          },
        },
      });
    };
    

    This codebase:

    • Creates a contract factory using the smart contract ABI and bytecode
    • Deploys the token with its name, symbol, and supply
    • Converts supply to proper units (with 18 decimals)
    • Waits for deployment confirmation
    • Returns the deployed token's address
    • Adds the newly created token to MetaMask
    • Uses the MetaMask API's wallet_watchAsset method
  4. Inside wallet.jsx, Copy and paste the following code:

    import { ethers } from "ethers";
    import { networks } from "../config/networks";
    
    export const connectWallet = async (networkId) => {
      if (!window.ethereum) throw new Error("Please install MetaMask");
    
      const selected = networks[networkId];
      const hexChainId = "0x" + selected.chainId.toString(16);
    
      // Switch or add chain
      try {
        await window.ethereum.request({
          method: "wallet_switchEthereumChain",
          params: [{ chainId: hexChainId }],
        });
      } catch (switchError) {
        // Add the network if it doesn't exist in MetaMask
        if (switchError.code === 4902) {
          await window.ethereum.request({
            method: "wallet_addEthereumChain",
            params: [
              {
                chainId: hexChainId,
                chainName: selected.name,
                rpcUrls: [selected.rpc],
                nativeCurrency: selected.nativeCurrency,
                blockExplorerUrls: [selected.blockExplorer],
              },
            ],
          });
        } else {
          throw switchError;
        }
      }
      
      // Now connect
      const provider = new ethers.BrowserProvider(window.ethereum);
      await provider.send("eth_requestAccounts", []);
      return await provider.getSigner();
    };
    
    export const switchNetwork = async (networkId, currentChainId) => {
      const selected = networks[networkId];
      const hexChainId = "0x" + selected.chainId.toString(16);
      
      if (currentChainId !== selected.chainId) {
        try {
          await window.ethereum.request({
            method: "wallet_switchEthereumChain",
            params: [{ chainId: hexChainId }],
          });
        } catch (switchError) {
          if (switchError.code === 4902) {
            await window.ethereum.request({
              method: "wallet_addEthereumChain",
              params: [
                {
                  chainId: hexChainId,
                  chainName: selected.name,
                  rpcUrls: [selected.rpc],
                  nativeCurrency: selected.nativeCurrency,
                  blockExplorerUrls: [selected.blockExplorer],
                },
              ],
            });
          } else {
            throw switchError;
          }
        }
        
        const provider = new ethers.BrowserProvider(window.ethereum);
        await provider.send("eth_requestAccounts", []);
        return await provider.getSigner();
      }
      
      return null;
    };
    


    This codebase:

    • Auto-adds networks to MetaMask if they don't exist
    • Handles network switching with proper error management
    • Request for transaction approval
    • Converts chain IDs to hex format for MetaMask compatibility

The User Interface

At this point, you must have created the network configuration and the utility functions. In this phase, you are building the UI for your users to create their token.


  1. Clear out what is inside App.jsx and add the following code:

    import React, { useState } from "react";
    import { networks } from "./config/networks";
    import { connectWallet, switchNetwork } from "./utils/wallet";
    import { deployToken, addTokenToWallet } from "./utils/token";
    
    const TokenCreator = () => {
      const [form, setForm] = useState({
        name: "",
        symbol: "",
        supply: "",
        network: "ethereum",
      });
      const [status, setStatus] = useState("");
      const [walletConnected, setWalletConnected] = useState(false);
      const [signer, setSigner] = useState(null);
    
      const handleChange = (e) => {
        setForm({ ...form, [e.target.name]: e.target.value });
      };
      
      const handleConnectWallet = async () => {
        try {
          const signerInstance = await connectWallet(form.network);
          setSigner(signerInstance);
          setWalletConnected(true);
          setStatus("✅ Wallet connected to " + form.network);
        } catch (err) {
          console.error(err);
          setStatus("❌ Failed to connect or switch network");
        }
      };
      
      const handleDeployToken = async () => {
        const { name, symbol, supply, network } = form;
    
        if (!signer) {
          setStatus("❌ Wallet not connected");
          return;
        }
    
        try {
          // Check if we need to switch networks
          const currentNetwork = await signer.provider.getNetwork();
          const selected = networks[network];
          
          if (currentNetwork.chainId !== selected.chainId) {
            setStatus("Switching to " + network + " network...");
            const newSigner = await switchNetwork(network, currentNetwork.chainId);
            if (newSigner) setSigner(newSigner);
          }
          
          setStatus("Deploying token...");
          const tokenAddress = await deployToken(name, symbol, supply, signer);
          setStatus(`✅ Token deployed at ${tokenAddress}`);
    
          await addTokenToWallet(tokenAddress, symbol);
        } catch (err) {
          console.error(err);
          setStatus("❌ Failed to deploy token");
        }
      };
    
      return (
        <div className="glass-background p-4 max-w-md mx-auto my-48 rounded-xl shadow-md border space-y-4">
          <h2 className="text-xl font-semibold text-center">ERC-20 Token Maker</h2>
    
          {!walletConnected ? (
            <button
              onClick={handleConnectWallet}
              className="w-full bg-green-600 text-white p-2 rounded hover:bg-green-700 shadow-2xl"
            >
              Connect Wallet
            </button>
          ) : (
            <>
              <input
                type="text"
                name="name"
                placeholder="Token Name"
                value={form.name}
                onChange={handleChange}
                className="w-full p-2 border rounded"
              />
              <input
                type="text"
                name="symbol"
                placeholder="Token Symbol"
                value={form.symbol}
                onChange={handleChange}
                className="w-full p-2 border rounded"
              />
              <input
                type="number"
                name="supply"
                placeholder="Initial Supply"
                value={form.supply}
                onChange={handleChange}
                className="w-full p-2 border rounded "
              />
              <select
                name="network"
                value={form.network}
                onChange={handleChange}
                className="w-full p-2 border rounded"
              >
                <option value="ethereum">Ethereum</option>
                <option value="rootstock">Rootstock</option>
              </select>
    
              <button
                onClick={handleDeployToken}
                className="w-full bg-blue-600 text-white p-2 rounded hover:bg-blue-700"
              >
                Deploy Token
              </button>
            </>
          )}
    
          {status && <p className="text-sm mt-2">{status}</p>}
        </div>
      );
    };
    
    export default TokenCreator;
    

This codebase contains Tailwindcss styling, ensure to edit this code.

In this codebase:

  • Conditional rendering based on wallet connection
  • Form for token creation (name, symbol, supply)
  • Network selection dropdown
  • Status messages for user feedback


At the end, you should have something like this:


Congratulations 🥂, you just created your own ERC-20 Maker

Conclusion

GetBlock allows developers to create multi-chain dApps using their RPC. This projects eliminate the need for users to write code when creating their token.

You can add extra features to this project e.g:

a. Airdrop feature that lets users distribute their tokens to their community based on activities, contributions, or tasks.

b. Logo for token identity

You can access the GitHub repo here and live site here.

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks