Build a Multi-Token Game Economy with ERC-1155

Want to understand how Enjin gaming assets, Gods Unchained cards, or OpenSea shared collections work? Build your own multi-token contract.

In 90-120 minutes, you'll deploy a contract managing unlimited token types: fungible currencies, unique items, and everything in between. One contract powering an entire game economy. You'll see why developers call ERC-1155 the multi-tool of token standards and how batch operations can save 50-80% on gas costs.

Note: This guide builds on concepts from the ERC-721 guidearrow-up-right. If you haven't completed it, you'll still be able to follow along, but some concepts will be more familiar if you've worked with NFTs before.

What You'll Learn

This guide goes beyond basic token creation. You'll understand the architecture powering blockchain gaming:

  • Why one contract can replace dozens - ERC-20 needs one contract per token. ERC-721 needs one per collection. ERC-1155 manages unlimited token types in a single deployment.

  • How batch operations slash gas costs - Minting 10 different items in one transaction instead of 10 separate ones. The savings add up fast.

  • What "semi-fungible" actually means - Concert tickets for the same event but different seats. Game items that start identical but become unique through use.

  • The {id} metadata pattern - How one base URI serves metadata for thousands of token types without storing thousands of strings on-chain.

What You Need

Requirement
Why It Matters
Get It Here

Node.js & npm

Runs the Hardhat development environment and manages code dependencies

MetaMask wallet

Holds test funds and signs the deployment transaction that creates your contract

Sepolia test ETH

Pays for gas fees (~$0 in real value, but required for test network)

Alchemy RPC URL

Your connection point to Ethereum. Like an API key for blockchain access.

Pinata account

Hosts your token images and metadata on IPFS, the decentralized storage layer"

Understanding What You're Building

ERC-1155 solves a problem that becomes obvious once you think about game economies.

Imagine building a blockchain game. You need:

  • Gold coins - Players earn and spend millions of these. Fungible, like ERC-20.

  • Health potions - Common items, maybe 10,000 exist. Semi-fungible.

  • Legendary Sword of Fire - Only one exists. Non-fungible, like ERC-721.

  • Event tickets - 500 for the same tournament, but each has a seat number.

With previous standards, you'd deploy separate contracts: one ERC-20 for gold, one ERC-721 for the sword, another ERC-721 for potions … Managing dozens of contracts, each with deployment costs, each requiring separate approvals for marketplaces.

ERC-1155 consolidates everything into one contract. Each token type gets an ID:

Token ID
Name
Supply
Type

1

Gold Coin

1,000,000

Fungible

2

Health Potion

10,000

Semi-fungible

3

Legendary Sword

1

Non-fungible

4

Tournament Ticket

500

Semi-fungible

The key insight: fungibility is determined by supply, not by the standard. Token ID 3 with supply of 1 behaves like an NFT. Token ID 1 with supply of 1,000,000 behaves like a currency. Same contract, same interface, different configurations.

Time to build.

Project Setup With Hardhat

We'll create a new Hardhat project for your multi-token contract.

The setup process is identical to the ERC-721 guidearrow-up-right. Please see that guide for detailed explanations of each step.

1. Initialize Your Project

Select:

  • Version: Hardhat 3 Beta

  • Project location: my-game-items

  • Project type: TypeScript + Viem

  • Dependencies: Confirm with Y

2. Install OpenZeppelin Contracts

3. Create Your Contract File

Smart Contract Development

We'll build your multi-token contract step by step, inheriting from OpenZeppelin's ERC1155 and Ownable. Unlike ERC-721 which needed URIStorage for per-token metadata, ERC-1155 handles this differently with a base URI pattern.

1. Initial Imports and Contract Structure

Open contracts/GameItems.sol and add the foundation:

What's different from ERC-721:

  • ERC1155: The multi-token standard. One contract, unlimited token types. Each token ID can have any supply.

  • No URIStorage extension: ERC-1155 uses a base URI with {id} substitution instead of storing URIs per token.

  • Constructor takes a URI string (we'll set it properly later).

2. State Variables and Token Configuration

Add the state variables that define your token economy. In contracts/GameItems.sol:

Key differences from ERC-721:

  • _totalSupply mapping: Tracks supply PER token ID. Token ID 1 might have 1,000,000 minted, token ID 2 might have just 5.

  • maxSupply mapping: Optional cap PER token ID. Token ID 3 (legendary sword) has max 1. Token ID 1 (gold) might be unlimited (0).

  • mintPrice mapping: Different prices for different items. Legendary items cost more than common ones.

  • tokenExists: Prevents minting unconfigured tokens. Owner must set up a token type before anyone can mint it.

3. Token Type Configuration

Before tokens can be minted, the owner must configure each token type. Add this to contracts/GameItems.sol:

Why this pattern:

Real game economies don't let anyone create arbitrary token types. The owner (game developer) defines what items exist:

  • Token ID 1: Gold coins, unlimited supply, can't be bought directly

  • Token ID 2: Health potion, max 10,000, costs 0.001 ETH

  • Token ID 3: Legendary sword, max 1, costs 0.1 ETH

This mirrors how actual games work. Developers control the item catalog.

4. Public Mint Function

The core minting logic, with payment and supply validation. Add to contracts/GameItems.sol:

The power of batch operations:

mintBatch is where ERC-1155 shines. Instead of:

You get:

For games where players acquire multiple items at once (loot drops, shop purchases), this adds up fast.

5. Owner Mint Functions

Free minting for the game owner: initial distribution, rewards, airdrops. Add to contracts/GameItems.sol:

Same pattern as ERC-721's ownerMint, but with batch capability. Useful for:

  • Initial token distribution at game launch

  • Tournament rewards (batch mint prizes to winners)

  • Airdrops to community members

6. Helper Functions

Utility functions for querying and managing the contract. Add to contracts/GameItems.sol:

The uri() function explained:

ERC-1155's metadata pattern differs from ERC-721:

  • ERC-721: Store unique URI per token (tokenURI[tokenId] = "ipfs://Qm.../1.json")

  • ERC-1155: One base URI, dynamically construct per-token URI

If _baseURI is "ipfs://QmMeta.../":

  • uri(1) returns "ipfs://QmMeta.../1.json"

  • uri(42) returns "ipfs://QmMeta.../42.json"

  • uri(1000) returns "ipfs://QmMeta.../1000.json"

This saves gas (no storage writes for URIs) and scales to unlimited token types.

Your multi-token contract is complete. It handles fungible currencies, unique items, and everything in between. Batch operations, configurable supplies, and dynamic pricing make up the same architecture powering blockchain games worth billions.

Writing Tests

Your multi-token contract is more complex than ERC-721. It handles multiple token types with different configurations, batch operations with payment calculations, and supply tracking per token ID. More moving parts means more potential bugs.

We'll test with the same dual approach: Solidity unit tests for individual functions, TypeScript integration tests for complete user flows.

Solidity Unit Tests

1. Setup

Create the test file:

Add the test contract with setup. Open contracts/GameItems.t.sol:

Setup notes:

  • Three token types configured: unlimited free gold, 10k potions at 0.001 ETH, unique sword at 0.1 ETH

  • This mirrors a real game economy with currency, consumables, and rare items

2. Test Deployment and Configuration

3. Test Single Minting

4. Test Batch Minting

5. Test Owner Minting

6. Test Withdrawals

7. Test URI Generation

8. Run Solidity Tests

TypeScript End-to-End Tests

1. Setup

Create the TypeScript test file:

Add the test structure. Open test/GameItems.ts:

2. Implement Complete Game Economy Test

3. Run TypeScript Tests

ERC-1155 uses a different metadata pattern than ERC-721. Instead of storing a unique URI for each token, it uses a base URI with {id} substitution.

For detailed Pinata setup instructions, see ERC-721: Setting Up Pinataarrow-up-right.

The {id} Pattern

ERC-721 stores individual URIs per token:

ERC-1155 constructs URIs dynamically from a base:

Why this matters: No storage writes for URIs. Scales to unlimited token types. Gas savings compound as your game grows.

Create a folder structure:

Metadata JSON structure (same as ERC-721, but with game-specific properties):

1.json (Gold Coin - Fungible):

2.json (Health Potion - Semi-fungible):

3.json (Legendary Sword - Non-fungible):

Upload Process

  1. Upload images folder to Pinata → Get Images CID

  2. Update metadata JSON files with Images CID in the "image" field

  3. Upload metadata folder to Pinata → Get Metadata CID

  4. Use Metadata CID as your contract's base URI: ipfs://YOUR_METADATA_CID/

The contract's uri() function will append the token ID and .json automatically.

Setting Up for Deployment

1. Setting Up Environment Variables

Same process as ERC-721. Set your RPC URL and private key in Hardhat's keystore:

2. Create the Deployment Script

Create the deployment file:

Add the deployment configuration. Open ignition/modules/GameItems.ts:

3. Deploy Your Contract

Save your deployed contract address!

Interacting with Your Contract

Configure Token Types

After deployment, configure your token types. Create scripts/configureTokens.ts:

Run with:

Mint Tokens

Create scripts/mint.ts:

Viewing on Rarible

Rarible supports ERC-1155 collections. To view your tokens:

  1. Connect your MetaMask wallet (Sepolia network)

  2. Navigate to your profile

  3. Your tokens should appear with their quantities

ERC-1155 tokens display differently than ERC-721; specifically, you'll see quantities like 'x5' for fungible/semi-fungible tokens.

Conclusion

You've built a complete multi-token game economy. Let's recap what you accomplished:

  1. Built a production-ready ERC-1155 contract with configurable token types, batch operations, supply caps, and dynamic pricing. This is the same architecture powering Enjin and other blockchain gaming platforms.

  2. Understood the multi-token paradigm where fungibility is determined by configuration, not by the standard. One contract managing currencies, items, and unique collectibles.

  3. Implemented batch operations that can save 50-80% on gas costs for complex transactions like loot drops or shop purchases.

  4. Mastered the {id} metadata pattern for scalable, gas-efficient metadata serving unlimited token types.

  5. Deployed and configured a live contract on Sepolia, minting tokens that appear on Rarible.

What You Built vs. Production Games

Your contract contains the core mechanics of blockchain gaming:

  • Multi-token management: One contract for entire economies

  • Batch operations: Gas-efficient mass distributions

  • Configurable supplies: Fungible currencies to unique legendaries

  • Payment handling: Item shop functionality built-in

What production games add:

  • Crafting/burning: Combine items to create new ones

  • Staking mechanics: Lock items for rewards

  • Royalties (ERC-2981): Earn from secondary sales

  • Access control: Multiple admin roles, not just owner

Explore advanced features: Add crafting (burn X potions to create Y), implement staking for passive rewards, or integrate ERC-2981 royalties.

Build a game frontend: Connect your contract to a web interface where players can view inventory, trade items, and interact with the economy.

Study production implementations: Read Enjin's contracts, examine Gods Unchained's architecture, understand how Loot (for Adventurers) structured their drops.

You've moved from understanding individual token types to managing entire economies. That's the foundation of blockchain gaming.

Last updated