Skip to main content
ERC-20 tokens are fungible—each unit is identical and interchangeable. Use them for in-game currencies, reward points, governance tokens, or any divisible asset.

Why Use ERC-20?

Players own their currency on-chain. They keep it even if they stop playing your game.
List on DEXes or enable peer-to-peer trading. Players can buy/sell currency with real market prices.
Same token can work across multiple games. Build partnerships and shared economies.
All supply, distribution, and transactions are verifiable on-chain. Players trust what they can verify.

Deploy via Hub

Deploy Contracts

Deploy ERC-20 contracts in Hub

Deploy via Code

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

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

contract GameCurrency is ERC20, Ownable {
    constructor() ERC20("Gold Coins", "GOLD") Ownable(msg.sender) {
        _mint(msg.sender, 1000000 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) external onlyOwner {
        _mint(to, amount);
    }
}

Distribution Patterns

Achievement Rewards

const REWARDS = {
  'first_kill': 100n * 10n ** 18n,
  'level_10': 500n * 10n ** 18n,
  'boss_defeated': 1000n * 10n ** 18n,
};

async function grantAchievement(player: string, achievement: string) {
  const reward = REWARDS[achievement];
  if (reward) await currencyContract.mint(player, reward);
}

Daily Login

async function claimDailyReward(player: string) {
  const lastClaim = await getLastClaimTime(player);
  if (Date.now() - lastClaim < 24 * 60 * 60 * 1000) {
    throw new Error('Already claimed today');
  }
  
  await currencyContract.mint(player, 50n * 10n ** 18n);
  await setLastClaimTime(player, Date.now());
}

Spending Currency

In-Game Purchases

async function purchaseItem(player: string, itemId: string, price: bigint) {
  // Transfer from player to treasury
  await currencyContract.transferFrom(player, TREASURY, price);
  
  // Grant the item
  await grantItem(player, itemId);
}

Approval Flow

Players must approve your contract to spend their tokens:
// Frontend: Request approval
async function approveSpending(amount: bigint) {
  const signer = await ethersProvider.getSigner();
  const currency = new ethers.Contract(CURRENCY_ADDRESS, ERC20_ABI, signer);
  await currency.approve(GAME_CONTRACT, amount);
}

Balance Queries

// Direct contract call
const balance = await currencyContract.balanceOf(playerAddress);
console.log(`${ethers.formatEther(balance)} GOLD`);

// Via Indexer API
const tokens = await indexer.listTokensByAccountAddress({
  chainName: 'imtbl-zkevm-mainnet',
  accountAddress: playerAddress,
});

Economy Design

  • Set maximum supply caps
  • Implement burning mechanics (consumables, fees)
  • Balance earn rates with spending sinks
  • Soft currency: Earned through gameplay, unlimited
  • Hard currency: Purchased or rare, limited supply
  • Seasonal currency: Resets each season
  • Rate limit claims per wallet
  • Require game actions, not just API calls
  • Monitor for suspicious patterns