# "Architecting High-Performance DeFi Infrastructure on Injective inEVM" > A deep dive into Tendermint BFT consensus, gas optimization, and production-grade deployment patterns **Published by:** [Injective](https://paragraph.com/@kaptan_web3/) **Published on:** 2026-01-16 **Categories:** injective, solidity, defi, web3, ethereum **URL:** https://paragraph.com/@kaptan_web3/injective ## Content # 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.** ## Publication Information - [Injective](https://paragraph.com/@kaptan_web3/): Publication homepage - [All Posts](https://paragraph.com/@kaptan_web3/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@kaptan_web3): Subscribe to updates