Hands-On Hardhat Part-3 (Write Your Custom Own Token)
Tags: hardhat, solidity, smartcontract, web3
Published: 2022-08-07 10:43:00

# Hands-On Hardhat Part-3

In the previous parts, we set up the project, wrote and deployed our first contract. In this part, we‘re gonna learn the ERC-20 standard and write our ERC-20 standard token. 

### EIP

To understand ERC, we should first understand EIP (Ethereum Improvement Proposals). As you know, Ethereum and other blockchain networks are community-based. At this point, anyone who wants to improve the network can present a proposal. For example, if Vitalik Buterin wants to do something for the Ethereum network, he presents a proposal or if you want to do something for the Ethereum network, you have to present a proposal for it.  So it is like [Bitcoin Improvement Proposals (BIP)](https://messari.io/resource/bitcoin-improvement-proposal-bip). Simply put, EIPs are drafts of ideas for new features or design functions put forward by any community member to be reviewed by stakeholders in the Ethereum ecosystem.

However, these proposals have fundamental standards and you must clearly state them; **Abstract, Motivation, Specification, Rationale, Backwards Compatibility, Test Cases, Reference Implementation, Security Considerations.**
For now, I’m not gonna detail all of them I’m just giving an example of a [proposal](https://github.com/ethereum/EIPs/blob/master/eip-template.md). 

And also EIPs have 3 types:

1. **Standards Track EIP**
   - Core
   - Networking
   - Interface
   - ERC
2. **Meta EIP**
3. **Informational EIP**

for furthermore details please check out [this](https://eips.ethereum.org/EIPS/eip-1)

In other words, after you have prepared tight documentation, you can present your proposal. But, not everything happens at once because the EIP has its processes. 

> The life cycle of an EIP involves distinct stages. An *'idea'* must first be '*drafted,'* allowing the proposal to be put into the EIP repository by an EIP Editor. The proposal then enters the *'review'* stage, during which an author requests a date for peer review. An Editor assigns the proposal a *'last-call'* status at the end of which it must be granted *a 'final'* state, typically after 14 days. 
Any EIP can be pushed into the '*stagnant*' state if left without progression for six months. A high level of technical competence is required for an EIP to be submitted, and a successful ERC is one that has not only entered a state of 'final' but is also in use by projects.
> 

### EIP Process

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6o2jnnt7l17nmdv1sdeh.jpeg)
 

### ERC20

ERC stands for “Ethereum Request for Comments”, it is a specialized subtype of EIP, relating to application-level changes that do not affect the Ethereum protocol itself. 

It was introduced by Fabian Vogelsteller in 2015-11-19. It was an assigned GitHub issue number 20 and named “ERC20. The ERC20 is a proposal that intends to standardize how a token contract should be defined, how we interact with such a token contract, and how these contracts interact with each other.

→ ERC20 standard is for fungible tokens created using the Ethereum blockchain. 
→ A fungible token is one that is interchangeable with another token. 
→This standard interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges. 

There are many ERCs such as *ERC721 vs ERC1155* I’m not gonna explain all of them to see all ERCs please check out [here](https://eips.ethereum.org/erc).

As I mentioned before every proposal have fundamental standards and you must clearly state them, so according to EIP-20’s documentation **[ERC20 token’s Specification](https://eips.ethereum.org/EIPS/eip-20)** has to provide at least the following **functions** and **events**:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6gr6m9rhuqq9wbr4vw74.png)
 

Before the coding let me explain a few things, for now I’m not gonna implement **ERC20Interface**. Because I don’t wanna reinvent the wheel. Probably my implementation will have some vulnerabilities and don't gas saving. So there are some implementations by various teams I mean I’m just gonna use the wheel, for today I will continue with **[Openzeppelin](https://www.openzeppelin.com/)**.

### OpenZeppelin

OpenZeppelin is an open-source framework to build secure smart contracts it provides a complete suite of security products and audit services to build, manage, and inspect all aspects of software development and operations for decentralized applications.

Now let’s start coding;

First, we need to add openzeppelin dependency, to add this dependency open your terminal and run this command line;

```solidity
npm install @openzeppelin/contracts
```

Second, in your project structure, open **contracts** package, create named **MyOwnToken.sol** file and then import **openzeppelin ERC20 contract.** 

```solidity
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
```

Lastly, write your **MyOwnToken** and inherit it from **ERC20.**

your code should follows as;

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lxd3imw0094g9suws77f.png)
 
Your constructor takes a named **initialSupply** parameter and inherited **ERC20** contract which takes 2 parameters token name and token symbol. And also in the constructor’s scope there is a **_mint()** function which sets how many tokens will be mint. Now maybe some of you get confused why we did like that? When you open **ERC20.sol** file you see it is inherited from **IERC20** interface which is I mentioned above that ERC20 standard all codes that we must write come by openzeppelin. If we didn’t inherit **MyOwnToken** from **ERC20** we would have to write functions that ERC20 has. And probably the codes that we wrote would not be efficient and safety as openzeppelin’s codes. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/skov5uxkr3aegotqgabx.png)
 
That’a all folks we wrote our custom token. 

Next, before writing tests and deploying our smart contract there is one more thing that I want to mention it. For example you want to your token should burnable or has some access controls etc. and you’re struggling to write them, there is an openzeppelin playground, you choose options and the code of your token is written automatically just not for **ERC20** also **ERC721** and **ERC1155** exist. To checkout playground visit [here](https://docs.openzeppelin.com/contracts/4.x/wizard).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4716q3xa6ia1i5u4p69y.png)
 

Now, let’s deploy and write our contract test.
First, open your terminal write compile command line;

```solidity
npx hardhat compile
```

After compiling (I assume that you didn’t get any errors), create a named **deployMyOwnToken.js** file inside **scripts** package write your script codes for deploying;

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/508i30dkcsz0we1kyokn.png)
 

After your script writing is done open 2 terminal one is to launch node and another is for deploying.

in first terminal write 

```solidity
npx hardhat node
```

in the another one write;

```solidity
npx hardhat run ./scripts/deployMyOwnToken.js --network localhost
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98nq198zgo0ii8izfru1.png)
 

So far so so good until now.

Let’s write unit tests. Create a named **my-own-token-test.js** file inside **test** package and files code follows as;
 

```jsx
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("MyOwnToken", function () {
  let totalSupply = "10000000000000000000000"; // 10000 * 1e18
  let MyOwnToken, myOwnToken, owner, address1, address2, address3;

  beforeEach(async function () {
    /**
     * A ContractFactory in ethers.js is an abstraction used to deploy new smart contracts,
     * so MyOwnToken here is a factory for instances of our token contract.
     */
    MyOwnToken = await ethers.getContractFactory("MyOwnToken");

    /** A Signer in ethers.js is an object that represents an Ethereum account.
     * It's used to send transactions to contracts and other accounts.
     * */
    [owner, address1, address2, ...address3] = await ethers.getSigners();

    myOwnToken = await MyOwnToken.deploy(totalSupply);
  });

  describe("Deployment", function () {
    it("Should assign the total supply of tokens to the owner", async function () {
      const ownerBalance = await myOwnToken.balanceOf(owner.address);
      expect(await myOwnToken.totalSupply()).to.equal(ownerBalance);
    });
  });

  describe("Transactions", function () {
    it("Should transfer tokens between accounts", async function () {
      const ownerBalance = await myOwnToken.balanceOf(owner.address);

      // Transfer 2000 tokens from owner to addr1
      await myOwnToken.transfer(address1.address, 2000);
      const address1Balance = await myOwnToken.balanceOf(address1.address);
      expect(address1Balance).to.equal(2000);

      // Transfer 2000 tokens from address1 to address2
      // We use .connect(signer) to send a transaction from another account
      await myOwnToken.connect(address1).transfer(address2.address, 2000);
      const address2Balance = await myOwnToken.balanceOf(address2.address);
      expect(address2Balance).to.equal(2000);
    });

    it("Should fail if sender doesn’t have enough tokens", async function () {
      const initialOwnerBalance = await myOwnToken.balanceOf(owner.address);

      // Try to send 1 token from address1 (0 tokens) to owner (1000000 tokens).
      // `require` will evaluate false and revert the transaction.
      await expect(
        myOwnToken.connect(address1).transfer(owner.address, 1)
      ).to.be.revertedWith("ERC20: transfer amount exceeds balance");

      // Owner balance shouldn't have changed.
      expect(await myOwnToken.balanceOf(owner.address)).to.equal(
        initialOwnerBalance
      );
    });
  });
});
```

specify your `test`folder and run test command line;

```jsx
npx hardhat test ./test/my-own-token-test.js
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9qj7zy6j6oaqs0kgw9uz.png)
 
Well, it's done see you in the next parts.

References:
[https://eips.ethereum.org/EIPS/eip-1](https://eips.ethereum.org/EIPS/eip-1)
[https://eips.ethereum.org/EIPS/eip-20](https://eips.ethereum.org/EIPS/eip-20)
[https://dev.to/yakult/a-concise-hardhat-tutorial-part-2-writing-erc20-2jpm](https://dev.to/yakult/a-concise-hardhat-tutorial-part-2-writing-erc20-2jpm)

Connect with me on social media: [Twitter](https://twitter.com/0xazat) && [LinkedIn](https://www.linkedin.com/in/azatsayan/) && [Github](https://github.com/0xazat)