How To Create ERC-20 Token Using Openzeppelin and Truffle: A Beginner Guide

Obafunso RidwanObafunso Ridwan
7 min read

Introduction

ERC-20 (Ethereum Request for Comment 20) is a standard for creating fungible tokens on the Blockchain Network. In November 2015, the ERC-20 standard was proposed by Vitalik Buterin and Fabian Vogelsteller as EIP-20.

In this tutorial, you will learn how to build and deploy an ERC-20 token on the Ethereum network.

Upon completion of this tutorial, you will have a fully compliant ERC-20 token.

It is recommended that you proceed with caution and attentiveness throughout the tutorial to achieve the desired outcome.

Let's get started.

Prerequisites

To complete this tutorial, you will need:

Create Workspace

Open a terminal to create your working folder with the following commands:

# create directory
$ mkdir ObiDatti
# move into the ObiDatti directory
$ cd ObiDatti
# initialize node.js project
$ npm init -y

Install Dependencies

Run the following commands to install the packages needed for this tutorial:

truffle: A development environment, testing framework, and asset pipeline for blockchains using the Ethereum Virtual Machine (EVM), aiming to make life as a developer easier.

openzeppelin/contracts: A library for secure smart contract development Build on a solid foundation of community-vetted code.

truffle/hdwallet-provider: A simple library that uses private keys, mnemonics, or phrases (12 or 24 words) to sign transactions (deployment).

truffle-plugin-verify: A truffle plugin for verifying smart contracts without leaving your terminal.

dotenv: A library that loads environment variables from a .env file into process.env

$ npm i -g truffle
$ npm i @openzeppelin/contracts @truffle/hdwallet-provider truffle-plugin-verify@0.5.28 dotenv

Create Truffle Project

You will need to initialize a new truffle project using the command below:

$ truffle init

# Init successful, sweet!
# Try our scaffold commands to get started:
#  $ truffle create contract YourContractName # scaffold a contract
#  $ truffle create test YourTestName         # scaffold a test

# http://trufflesuite.com/docs

Scaffold Token Contract

After the creation of the truffle project, it is necessary to scaffold the ERC-20 smart contract through the execution of the following command:

$ truffle create contract ObiDatti

Creating ObiDatti ($OBD) Token

The next step is to create an ERC-20 token named ObiDatti using the Openzeppelin framework. Open the filecontracts/ObiDatti.sol and paste the following code into it.

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract ObiDatti is ERC20, ERC20Burnable, Pausable, Ownable {
    // this execute only on deployment i.e it runs only once.
    constructor() ERC20("ObiDatti", "OBD") {
        // minting 1,000,000 to msg.sender (ObiDatti deployer)
        _mint(msg.sender, 1000000 * 10**decimals());
    }

    /// @dev
    /// mint(address, uint256) function mints new tokens to specific 
    /// address `to`
    /// NB: Only callable by ObiDatti deployer (onlyOwner)
    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }

    /// @dev
    /// pause() function pauses token transfer on ObiDatti
    /// NB: Only callable by ObiDatti deployer (onlyOwner)
    function pause() public onlyOwner {
        _pause();
    }

    /// @dev
    /// unpause() function un-pauses token transfer on ObiDatti
    /// NB: Only callable by ObiDatti deployer (onlyOwner)
    function unpause() public onlyOwner {
        _unpause();
    }

    /// @dev
    /// _beforeTokenTransfer() function override method in `ERC20` i.e
    /// super._beforeTokenTransfer(from, to, amount) making transfer of 
    /// ObiDatti token only possible `whenNotPaused`.
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal override whenNotPaused {
        super._beforeTokenTransfer(from, to, amount);
    }
}

The contract ObiDatti extends OpenzeppelinERC20, ERC20Burnable, Pausable, Ownable to create mintable, burnable, and pausable ERC-20 tokens (ObiDatti).

Scaffold ObiDatti ($OBD) Migration

After the creation of the ObiDatti smart contract, we would need to create a migration file for either test-net or main-net deployment:

$ truffle create migration ObiDatti

Creating ObiDatti ($OBD) Migration

Open the file migrations/xxxxx_obi_datti.js and paste the following code into it.

const ObiDatti = artifacts.require('ObiDatti')

module.exports = function (_deployer) {
  // .deploy(ObiDatti) call ObiDatti constructor and deploy the
  // smart contract to the chosen network.
  _deployer.deploy(ObiDatti)
}

Compiling ObiDatti ($OBD) Smart Contract

To compile the contract, open the terminal and run the following command:

$ truffle compile

# Compiling your contracts...
# ===========================
# > Compiling @openzeppelin\contracts\access\Ownable.sol
# > Compiling @openzeppelin\contracts\security\Pausable.sol
# > Compiling @openzeppelin\contracts\token\ERC20\ERC20.sol
# > Compiling @openzeppelin\contracts\token\ERC20\IERC20.sol
# > Compiling @openzeppelin\contracts\token\ERC20\extensions\ERC20Burnable.sol
# > Compiling @openzeppelin\contracts\token\ERC20\extensions\IERC20Metadata.sol
# > Compiling @openzeppelin\contracts\utils\Context.sol
# > Compiling .\contracts\ObiDatti.sol
# > Artifacts written to ..\ObiDatti\build\contracts
# > Compiled successfully using:
#   - solc: 0.8.18+commit.87f61d96.Emscripten.clang

After a successful compilation, open the build/ folder to check all the contract artifacts containing the contract name, bytecode, ABI, compiler version, deployment details, etc.

Deploying ObiDatti ($OBD) On Testnet (Goerli)

Preparing Environment Variables

Create .env file in the root folder and paste the following code into it.

INFURA_API_URL="https://goerli.infura.io/v3/{INFURA_KEY}" 
MNEMONIC="{PHRASE}"
ETHERSCAN_API_KEY="{ETHERSCAN_KEY}"

INFURA_API_URL: Log into the Infura account you created earlier and click on CREATE NEW KEY then select Web3 API as network and ObiDatti as name, then click on CREATE. Copy and paste your API key into {INFURA_KEY}.

MNEMONIC: Install Metamask from Google Chrome Web Store. After installation, start the extension and create a new wallet. Copy and paste your 12 recovery phrases or words one after the other (with whitespace) into {PHRASE}.

ETHERSCAN_API_KEY: Log into the etherscan.io account you created earlier and click on API Keys > +Add > Enter the app name and click on Create New API Key. Copy and paste your API key token into {ETHERSCAN_KEY}.

Updating Truffle Configuration

Open the file truffle-config.js and paste the following code into it.

const HDWalletProvider = require('@truffle/hdwallet-provider')
const dotenv = require('dotenv')

// load env variables
dotenv.config()

// destructure INFURA_API_URL, MNEMONIC, ETHERSCAN_API_KEY
const { INFURA_API_URL, MNEMONIC, ETHERSCAN_API_KEY } = process.env

module.exports = {
  /**
   * Networks define how you connect to your ethereum client and let you set the
   * defaults web3 uses to send transactions. If you don't specify one truffle
   * will spin up a managed Ganache instance for you on port 9545 when you
   * run `develop` or `test`. You can ask a truffle command to use a specific
   * network from the command line, e.g
   *
   * $ truffle test --network <network-name>
   */

  networks: {
    // Useful for deploying to a public network.
    // Note: It's important to wrap the provider as a function to ensure truffle uses a new provider every time.
    goerli: {
      provider: () => new HDWalletProvider(MNEMONIC, INFURA_API_URL),
      network_id: 5, // Goerli's id
      gas: 5500000,
      networkCheckTimeoutnetworkCheckTimeout: 10000,
      confirmations: 2, // # of confirmations to wait between deployments. (default: 0)
      timeoutBlocks: 200, // # of blocks before a deployment times out  (minimum/default: 50)
      skipDryRun: true, // Skip dry run before migrations? (default: false for public nets )
    },
  },

  // Configure your compilers
  compilers: {
    solc: {
      version: '0.8.18',
    },
  },

  // truffle-plugin-verify configurations
  plugins: ['truffle-plugin-verify'],
  api_keys: {
    etherscan: ETHERSCAN_API_KEY,
  },
}

Getting Some Test ETH For Deployment

Faucets are the easiest way of getting test ETH at zero cost. Open the MetaMask extension you installed previously and copy your wallet address. Go to QuickNode Goerli Faucet and paste the address to get 0.1 ETH for free.

Deploying ObiDatti ($OBD)

Open a terminal and run the following command to deploy the ObiDatti contract to the Goerli test network.

$ truffle migrate --network goerli

# Starting migrations...
# ======================
# > Network name:    'goerli'
# > Network id:      5
# > Block gas limit: 30000000 (0x1c9c380)


# 1676641071_obi_datti.js
# =======================

#    Deploying 'ObiDatti'
#    --------------------
#    > transaction hash:    0x706ffc53a35b4e8bbb9edaf207ca517031651d7e69869160072d7671f83fe757
#    > Blocks: 1            Seconds: 9
#    > contract address:    0xECE49A968924642639429364865b91b95b556E13
#    > block number:        8513220
#    > block timestamp:     1676722824
#    > account:             0x611ac347131c013D5f24ae0189AEfAB8a4c823c2
#    > balance:             0.095303866907851373
#    > gas used:            1878451 (0x1ca9b3)
#    > gas price:           2.500002977 gwei
#    > value sent:          0 ETH
#    > total cost:          0.004696133092148627 ETH

#    Pausing for 2 confirmations...

#    -------------------------------
#    > confirmation number: 1 (block: 8513221)
#    > confirmation number: 2 (block: 8513222)
#    > Saving artifacts
#    -------------------------------------
#    > Total cost:     0.004696133092148627 ETH

# Summary
# =======
# > Total deployments:   1
# > Final cost:          0.004696133092148627 ETH

Verifying ObiDatti ($OBD)

Open a terminal and run the following command to verify the ObiDatti contract.

$ truffle run verify ObiDatti --network goerli

# Verifying ObiDatti
# Pass - Verified: https://goerli.etherscan.io/address/0xECE49A968924642639429364865b91b95b556E13#code
# Successfully verified 1 contract(s).

Conclusion

In this article, we have created a mintable, burnable, and pausable token ($OBD) on Ethereum Goerli Network. We have also verified the smart contract for transparency.

$OBD Contract Address: https://goerli.etherscan.io/address/0xECE49A968924642639429364865b91b95b556E13

$OBD Code: https://goerli.etherscan.io/address/0xECE49A968924642639429364865b91b95b556E13#code

$OBD Deployer (with 1,000,000 $OBD): https://goerli.etherscan.io/address/0x611ac347131c013D5f24ae0189AEfAB8a4c823c2

Thanks for reading ❤️

Solidity Documentation

Openzeppelin ERC-20 Documentation

ERC-20: Token Standard

12
Subscribe to my newsletter

Read articles from Obafunso Ridwan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Obafunso Ridwan
Obafunso Ridwan

I am Obafunso Ridwan Adebayo, A Software Engineer from Lagos, Nigeria.