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:
ERC20is the standard interface that definesbalanceOf,transfer, etc.- The constructor sets the token name and symbol, then mints the initial supply to the deployer’s address.
initialSupplyis expressed in wei‑like units, so if you want 1,000 tokens with 18 decimals you pass1000 * 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.parseUnitsconverts 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
| Issue | Why it Happens | Fix |
|---|---|---|
| “invalid opcode” or “out of gas” | Deploying with too low a gas limit or using an outdated Solidity version | Hardhat 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 prefix | Double‑check the .env file and restart the terminal if needed. |
| Contract not verified | API key missing or wrong format | Verify 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
mintfunction with anonlyOwnerguard 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!
- → Cut SaaS churn by 30% with cohort analysis: a 30‑day action plan @retentionradar
- → How to Boost SaaS ARR by 30% Using Data‑Driven Retention Experiments @growthlab
- → How to Build a Blockchain‑Backed Personal Brand That Generates Passive Income for Decades @digitalassetforge
- → How to Build a Metaverse Gallery with Simple Web3 Tools @web3canvas
- → How to Build a Scalable SaaS Pricing Model That Turns Leads Into Loyal Customers @techgrowthinsights