Deploy Your First ERC‑20 Token on Polygon with Hardhat: A Complete Developer Guide

Read this article in clean Markdown format for LLMs and AI context.

You’ve probably heard “ERC‑20” tossed around in every dev chat, but until you actually push one to a live network it feels like a myth. Polygon’s low fees and fast finality make it the perfect sandbox for a first token, and Hardhat gives you the tooling to do it without pulling your hair out. In this post I’ll walk you through every step, from setting up the project to seeing your token on a block explorer. Grab a coffee, fire up your terminal, and let’s get our hands dirty.

Why Polygon and Hardhat?

Polygon (formerly Matic) is essentially Ethereum’s cheaper cousin. It runs the same EVM bytecode, so any Solidity contract you write for Ethereum works there unchanged. The big win is that a transaction that costs $5 on mainnet is often under $0.01 on Polygon. For a beginner token, that means you can experiment without watching your wallet melt.

Hardhat is a development environment that feels like a Swiss‑army knife. It compiles, runs tests, spins up a local node, and even lets you fork live networks. The community plugins for ethers, waffle, and upgrades make it a one‑stop shop for most Web3 projects. If you’ve used Truffle or Remix before, Hardhat’s workflow will feel familiar but far more flexible.

Prerequisites

Before we dive in, make sure you have:

  • Node.js (v16 or later) and npm installed.
  • A code editor – VS Code works great.
  • A MetaMask wallet with some MATIC on the Polygon Mumbai testnet (you can get free test MATIC from the faucet).
  • Basic familiarity with Solidity and the ERC‑20 standard.

If any of these are missing, pause and get them sorted. Trust me, half the frustration comes from missing a tiny setup step.

Step 1: Bootstrap the Hardhat Project

Open a terminal and run:

mkdir my-polygon-token
cd my-polygon-token
npm init -y
npm install --save-dev hardhat
npx hardhat

When the Hardhat wizard asks what you want to create, choose “Create a basic sample project”. This scaffolds a contracts/, test/, and scripts/ folder plus a hardhat.config.js file.

Install Additional Packages

We’ll need ethers for interacting with the blockchain and dotenv for keeping our private key safe:

npm install --save-dev @nomiclabs/hardhat-ethers ethers dotenv

Add the plugin to hardhat.config.js:

require("@nomiclabs/hardhat-ethers");
require("dotenv").config();

Step 2: Write the ERC‑20 Contract

Inside contracts/ create a file called MyToken.sol. Keep it simple – we’ll inherit from OpenZeppelin’s battle‑tested implementation.

First, install OpenZeppelin contracts:

npm install @openzeppelin/contracts

Now the contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

contract MyToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
        _mint(msg.sender, initialSupply);
    }
}

A quick rundown:

  • ERC20 is the standard interface that defines balanceOf, transfer, etc.
  • The constructor sets the token name and symbol, then mints the initial supply to the deployer’s address.
  • initialSupply is expressed in wei‑like units, so if you want 1,000 tokens with 18 decimals you pass 1000 * 10**18.

Step 3: Configure Hardhat for Polygon Mumbai

Open hardhat.config.js and add a network entry:

module.exports = {
  solidity: "0.8.20",
  networks: {
    mumbai: {
      url: "https://rpc-mumbai.maticvigil.com",
      accounts: [process.env.PRIVATE_KEY]
    }
  }
};

Create a .env file in the project root and paste your MetaMask private key (never commit this file!). Also add your Alchemy or Infura endpoint if you prefer a different RPC provider.

PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE

Step 4: Write a Deployment Script

In scripts/ create deploy.js:

async function main() {
  const [deployer] = await ethers.getSigners();
  console.log("Deploying from:", deployer.address);

  const MyToken = await ethers.getContractFactory("MyToken");
  const initialSupply = ethers.utils.parseUnits("1000000", 18); // 1 million tokens
  const token = await MyToken.deploy(initialSupply);

  await token.deployed();
  console.log("MyToken address:", token.address);
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });

A couple of notes:

  • ethers.getSigners() returns the accounts Hardhat knows about; the first one is the one tied to our private key.
  • parseUnits converts a human‑readable number into the 18‑decimal format ERC‑20 expects.
  • The script logs the contract address so you can verify it later.

Step 5: Deploy to Mumbai

Run the script:

npx hardhat run scripts/deploy.js --network mumbai

If everything is wired correctly you’ll see something like:

Deploying from: 0xAbc...123
MyToken address: 0xDef...456

Copy that address. Open https://polygonscan.com/ and paste it into the search bar. You should see the contract verified (if you haven’t verified yet, you can use the Hardhat verify plugin later). The “Contract” tab will show the name, symbol, and total supply.

Step 6: Interact with Your Token

Let’s do a quick sanity check using a small Node script. Create scripts/checkBalance.js:

async function main() {
  const tokenAddress = "0xDef...456"; // replace with your address
  const MyToken = await ethers.getContractAt("ERC20", tokenAddress);
  const [owner] = await ethers.getSigners();

  const balance = await MyToken.balanceOf(owner.address);
  console.log("Balance of", owner.address, "is", ethers.utils.formatUnits(balance, 18), "MTK");
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });

Run it with the same --network mumbai flag. You should see the 1 000 000 MTK you minted in the constructor.

Optional: Verify on Polygonscan

Verification makes your source code public and lets users read the contract directly on the explorer. Install the plugin:

npm install --save-dev @nomiclabs/hardhat-etherscan

Add to hardhat.config.js:

require("@nomiclabs/hardhat-etherscan");
module.exports = {
  // ... existing config
  etherscan: {
    apiKey: process.env.POLYGONSCAN_API_KEY
  }
};

Create a Polygonscan API key, drop it in .env, then run:

npx hardhat verify --network mumbai DEPLOYED_CONTRACT_ADDRESS "1000000000000000000000000"

The long number is the initial supply in wei. After a few seconds Polygonscan will show your verified source.

Common Pitfalls and How to Avoid Them

IssueWhy it HappensFix
“invalid opcode” or “out of gas”Deploying with too low a gas limit or using an outdated Solidity versionHardhat automatically estimates gas; just let it. Ensure solidity version matches the pragma in your contract.
“invalid private key”.env not loaded or key missing the 0x prefixDouble‑check the .env file and restart the terminal if needed.
Contract not verifiedAPI key missing or wrong formatVerify the key on Polygonscan, then re‑run the verify command.

Next Steps

Now that you have a working ERC‑20 on Polygon, you can:

  • Add a mint function with an onlyOwner guard to allow future token issuance.
  • Build a simple front‑end with ethers.js to let users transfer tokens.
  • Explore Layer‑2 bridges to move your token between Polygon and Ethereum.

Deploying a token is just the first line of code in a longer story. The real fun begins when you start integrating it into a dApp, a game, or a DAO. Keep experimenting, and remember that every bug you squash is a step toward mastery.

Happy coding!

Reactions
Do you have any feedback or ideas on how we can improve this page?