Cover photo

"Architecting High-Performance DeFi Infrastructure on Injective inEVM"

A deep dive into Tendermint BFT consensus, gas optimization, and production-grade deployment patterns

# Zero to Hero: Deploying Your First ERC-20 Token on Injective inEVM with Hardhat

> **TL;DR**: Hardhat + Injective inEVM = sub-second finality, EVM compatibility, and the tooling you already know. Ship faster.


**Why Hardhat + Injective inEVM?**

Injective's inEVM brings the entire Ethereum toolchain to a chain with **~1 second block times** and **instant finality**. No waiting for confirmations. No gas wars. Just deploy and iterate.

Hardhat gives you:
- Native TypeScript support
- Built-in testing framework
- Seamless contract verification
- Plugin ecosystem (ethers.js, OpenZeppelin upgrades, etc.)

**This is the stack for builders who ship.**


**Prerequisites**

```bash
node -v  # v18.0.0 or higher
npm -v   # v9.0.0 or higher
```

If you don't have Hardhat globally:
```bash
npm install --save-dev hardhat
```


**Project Setup**

```bash
mkdir injective-token && cd injective-token
npx hardhat init
```

Select: **Create a JavaScript project**

Install dependencies:
```bash
npm install --save-dev @nomicfoundation/hardhat-toolbox
npm install @openzeppelin/contracts
```


**Configuration: hardhat.config.js**

Replace your `hardhat.config.js` with:

```javascript
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: {
    version: "0.8.20",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    injectiveTestnet: {
      url: "https://testnet.rpc.inevm.com",
      chainId: 2424,
      accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
      gasPrice: 500000000, // 0.5 gwei
    },
    injectiveMainnet: {
      url: "https://mainnet.rpc.inevm.com",
      chainId: 2525,
      accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
      gasPrice: 500000000,
    },
  },
  etherscan: {
    apiKey: {
      injectiveTestnet: "no-api-key-needed",
      injectiveMainnet: "no-api-key-needed",
    },
    customChains: [
      {
        network: "injectiveTestnet",
        chainId: 2424,
        urls: {
          apiURL: "https://testnet.explorer.inevm.com/api",
          browserURL: "https://testnet.explorer.inevm.com",
        },
      },
      {
        network: "injectiveMainnet",
        chainId: 2525,
        urls: {
          apiURL: "https://explorer.inevm.com/api",
          browserURL: "https://explorer.inevm.com",
        },
      },
    ],
  },
};
```

Create a `.env` file:
```bash
PRIVATE_KEY=your_private_key_here_without_0x_prefix
```

> โš ๏ธ **Never commit your `.env` file. Add it to `.gitignore`.**


**The Contract: contracts/InjectiveToken.sol**

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

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

/**
 * @title InjectiveToken
 * @dev Production-ready ERC-20 token for Injective inEVM
 * @notice Includes burn functionality and EIP-2612 permit for gasless approvals
 */
contract InjectiveToken is ERC20, ERC20Burnable, ERC20Permit, Ownable {
    uint8 private immutable _decimals;

    /**
     * @dev Constructor that mints initial supply to deployer
     * @param name_ Token name
     * @param symbol_ Token symbol
     * @param decimals_ Token decimals (typically 18)
     * @param initialSupply_ Initial token supply (in whole tokens, not wei)
     */
    constructor(
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        uint256 initialSupply_
    ) ERC20(name_, symbol_) ERC20Permit(name_) Ownable(msg.sender) {
        _decimals = decimals_;
        _mint(msg.sender, initialSupply_ * 10 ** decimals_);
    }

    function decimals() public view virtual override returns (uint8) {
        return _decimals;
    }

    /**
     * @dev Allows owner to mint additional tokens
     * @param to Recipient address
     * @param amount Amount to mint (in wei)
     */
    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}
```


**Deployment Script: scripts/deploy.js**

```javascript
const hre = require("hardhat");

async function main() {
  const [deployer] = await hre.ethers.getSigners();
  
  console.log("Deploying contracts with account:", deployer.address);
  console.log("Account balance:", (await deployer.provider.getBalance(deployer.address)).toString());

  // Token parameters
  const TOKEN_NAME = "Injective Builder Token";
  const TOKEN_SYMBOL = "IBT";
  const TOKEN_DECIMALS = 18;
  const INITIAL_SUPPLY = 1_000_000; // 1 million tokens

  console.log("\n๐Ÿ“ฆ Deploying InjectiveToken...");
  
  const InjectiveToken = await hre.ethers.getContractFactory("InjectiveToken");
  const token = await InjectiveToken.deploy(
    TOKEN_NAME,
    TOKEN_SYMBOL,
    TOKEN_DECIMALS,
    INITIAL_SUPPLY
  );

  await token.waitForDeployment();
  const tokenAddress = await token.getAddress();

  console.log("\nโœ… InjectiveToken deployed successfully!");
  console.log("โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”");
  console.log("Contract Address:", tokenAddress);
  console.log("Token Name:", TOKEN_NAME);
  console.log("Token Symbol:", TOKEN_SYMBOL);
  console.log("Total Supply:", INITIAL_SUPPLY.toLocaleString(), TOKEN_SYMBOL);
  console.log("โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”");
  
  console.log("\n๐Ÿ” View on Explorer:");
  console.log(`https://testnet.explorer.inevm.com/address/${tokenAddress}`);

  // Return deployment info for verification
  return {
    address: tokenAddress,
    constructorArgs: [TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS, INITIAL_SUPPLY],
  };
}

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


**Deploy to Injective Testnet**

**1. Get Testnet INJ**

Fund your wallet with testnet INJ from the [Injective Faucet](https://testnet.faucet.injective.network/).

**2. Compile**

```bash
npx hardhat compile
```

**3. Deploy**

```bash
npx hardhat run scripts/deploy.js --network injectiveTestnet
```

Expected output:
```
Deploying contracts with account: 0xYourAddress
Account balance: 1000000000000000000

๐Ÿ“ฆ Deploying InjectiveToken...

โœ… InjectiveToken deployed successfully!
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Contract Address: 0xDeployedContractAddress
Token Name: Injective Builder Token
Token Symbol: IBT
Total Supply: 1,000,000 IBT
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

๐Ÿ” View on Explorer:
https://testnet.explorer.inevm.com/address/0xDeployedContractAddress
```


**Contract Verification**

Verify your contract on the Injective Explorer:

```bash
npx hardhat verify --network injectiveTestnet \
  DEPLOYED_CONTRACT_ADDRESS \
  "Injective Builder Token" \
  "IBT" \
  18 \
  1000000
```

Replace `DEPLOYED_CONTRACT_ADDRESS` with your actual contract address.

**Manual Verification (Alternative)**

If automated verification fails:

1. Go to [Injective Testnet Explorer](https://testnet.explorer.inevm.com)
2. Search for your contract address
3. Click "Verify & Publish"
4. Select:
   - Compiler: `0.8.20`
   - Optimization: `Yes (200 runs)`
   - License: `MIT`
5. Flatten your contract:
   ```bash
   npx hardhat flatten contracts/InjectiveToken.sol > Flattened.sol
   ```
6. Paste the flattened code and submit


**Testing Your Token**

Create `test/InjectiveToken.test.js`:

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

describe("InjectiveToken", function () {
  let token;
  let owner;
  let addr1;
  
  const NAME = "Injective Builder Token";
  const SYMBOL = "IBT";
  const DECIMALS = 18;
  const INITIAL_SUPPLY = 1_000_000;

  beforeEach(async function () {
    [owner, addr1] = await ethers.getSigners();
    const InjectiveToken = await ethers.getContractFactory("InjectiveToken");
    token = await InjectiveToken.deploy(NAME, SYMBOL, DECIMALS, INITIAL_SUPPLY);
  });

  it("Should have correct name and symbol", async function () {
    expect(await token.name()).to.equal(NAME);
    expect(await token.symbol()).to.equal(SYMBOL);
  });

  it("Should mint initial supply to deployer", async function () {
    const expectedSupply = ethers.parseUnits(INITIAL_SUPPLY.toString(), DECIMALS);
    expect(await token.totalSupply()).to.equal(expectedSupply);
    expect(await token.balanceOf(owner.address)).to.equal(expectedSupply);
  });

  it("Should allow owner to mint", async function () {
    const mintAmount = ethers.parseUnits("1000", DECIMALS);
    await token.mint(addr1.address, mintAmount);
    expect(await token.balanceOf(addr1.address)).to.equal(mintAmount);
  });

  it("Should allow burning", async function () {
    const burnAmount = ethers.parseUnits("1000", DECIMALS);
    await token.burn(burnAmount);
    const expectedBalance = ethers.parseUnits((INITIAL_SUPPLY - 1000).toString(), DECIMALS);
    expect(await token.balanceOf(owner.address)).to.equal(expectedBalance);
  });
});
```

Run tests:
```bash
npx hardhat test
```


**Quick Reference**

| Network | Chain ID | RPC URL | Explorer |
|---------|----------|---------|----------|
| Testnet | 2424 | https://testnet.rpc.inevm.com | https://testnet.explorer.inevm.com |
| Mainnet | 2525 | https://mainnet.rpc.inevm.com | https://explorer.inevm.com |


**What's Next?**

You just deployed on **the fastest EVM chain**. Here's what you can build next:

- ๐Ÿ”„ **DEX Integration**: List your token on Injective DEXs
- ๐ŸŒ‰ **Cross-chain Bridges**: Connect to Ethereum, Cosmos, Solana
- ๐Ÿ“Š **DeFi Protocols**: Build lending, staking, or yield protocols
- ๐ŸŽฎ **Gaming/NFTs**: Leverage instant finality for gaming assets


**Resources**

- [Injective inEVM Docs](https://docs.injective.network/develop/guides/inEVM/)
- [Hardhat Documentation](https://hardhat.org/docs)
- [OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts)
- [Injective Discord](https://discord.gg/injective)


**Built with ๐Ÿฅท for the Injective ecosystem.**