Skip to main content

Create in-game assets

Estimate time to complete: 20 minutes

This tutorial covers one of the most important parts in constructing your web3 game. Here you will mint, and configure NFTs to power your in-game items. As part of this, you'll learn how to do this with our preset contracts for ERC721.

Note: This tutorial will only cover minting and will not cover when and how you would initiate a mint within a gameplay context.

create game assetscreate game assets

This is a beginners guide, lots of the helpful context, important links and preparation material are in the blue collapsed sections. For those more confident, you can skip those.

We cover minting NFTs by contract function call and Minting API. For more information on the Minting API, check out our following product page.

To start, you may want to first familiarise yourself with these concepts
ConceptsDefinition
In-game itemsIn-game items include cards, consumables, collectables, weapons, clothing and equipment that power the aesthetics and mechanics of your game.
On-chain assets (NFTs)In Web3 games, one of the fundamental value propositions is to power some, if not all your in-game items with on-chain assets. This tutorial uses ERC721 smart contracts to do this.
CollectionsWhen minting NFTs, individual NFTs are created as part of a collection. This guide will teach you how to do this.
MetadataTo enable NFTs to be more descriptive, smart contracts can contain metadata, which is information about the special characteristics of each NFT. The metadata of an NFT can describe its characteristics and properties, such as its name, description, transaction history, traits, link to the hosted image, and more. This tutorial will teach you how to configure this.

Task 1: Set up basic metadata hosting

To enable NFTs to be more descriptive, metadata is used to contain information about the special characteristics of each token. This can include its name, description, transaction history, traits, link to the hosted image, and more.

At scale, you will need to provide this information through a server, but we'll use Github Pages today to minimize the infrastructure setup. Begin by forking our Sample Project Metadata repository:

Sample Project Metadata

You should now have your very own repository! Next, we need to make this repository visible through Github Pages:

  1. Your Repository > Settings > Pages
  2. Set the Source to "deploy from a branch".
  3. Set the Branch to main or master branch and click save.
Visual guide for setting up your Metadata repo

From the Sample Project Metadata repository you can select "Fork" in the toolbar.

Forking your repository

Once forked, you should see "Settings" appear in your forked version of the repository.

Selecting settings

Once in Settings, locte "Pages" on the left hand side menu and set up according to the instructions.

  • Set the Source to "deploy from a branch".
  • Set the Branch to main or master branch and click save.
Selecting up your branch

Task 2: Customise your NFT metadata

We've already provided you with 3 sample metadata files and images out of the box - let's make a few quick changes to customise your collection!

The minimum files you'll need to update are:

  • Metadata files in the ../tokens/ directory: URLs for your images for each NFT (file name contains Token ID value: e.g. 1, 2, 3) under the image field; replacing the https://immutable.github.io/sample-project-metadata/tokens/token1.webp, ../tokens/token2.webp and ../tokens/token3.webp values from the 3 samples provided.
  • collection.json: Name of your collection under the name and description fields. Also populate the collection image URL under the image field
💡If you host your images within your forked GitHub repo
Your URL will look similar to this:
https://<your github name>.github.io/<your fork name>/<directory>/<filename>
First, we need to configure the collection-level metadata for our project by modifying our `collection.json` file:
{
"name": "YOUR_COLLECTION_NAME",
"description": "YOUR_COLLECTION_DESCRIPTION",
"image": "YOUR_IMAGE_URL",
"external_link": "YOUR_WEBSITE_URL"
}

To modify the metadata of the individual NFTs, we need to modify the json files in the /tokens folder. You'll note that the files are named 1, 2 and 3: this corresponds exactly to the unique token_id of each token. NFT metadata follows the standard format defined in ERC-721, and should look roughly like this:

{
"id": 1,
"image": "YOUR_IMAGE_URL",
"token_id": "1",
"background_color": null,
"animation_url": null,
"youtube_url": null,
"name": "Test zkEVM NFT",
"description": "This NFT is my first zkEVM NFT created on Immutable",
"external_url": null,
"attributes": [
{
"trait_type": "Hat",
"value": "Top Hat"
},
{
"trait_type": "Coat",
"value": "Tails"
},
{
"trait_type": "Neck",
"value": "Bow Tie"
}
]
}

As you've probably noticed, modifying this metadata for each NFT individually is slow and frustrating. This is OK for our quickstart tutorial, but is not recommended for real games! If you want to learn how to set up metadata hosting at scale, see our metadata documentation.

We now have two very important URLs - remember these for later!

  • Contract Metadata URI: https://<your github name>.github.io/<your fork name>/collection.json
  • Token Base URI: https://<your github name>.github.io/<your fork name>/tokens/
tip

Blockscout currently requires a '/' at the end of the Token Base URI to index metadata correctly. Immutable's Blockchain Data API does not require this, however for consistency we recommend adding a '/' to the end of the Token Base URI for Blockscout compatibility.

Task 3: Setup admin wallet

For the purpose of this tutorial, all you'll need to do is download the Metamask browser wallet and follow the steps to store your seed phrase in a safe location.

Immutable Hub will take care of setting up the chain network details and faucet the tIMX tokens (for Testnet only) you'll need to pay for gas automatically in Task 4 as you deploy your contract.

If you need to manually top up your tIMX tokens you can do so via Immutable Hub by visiting the Faucet.

Task 4: Deploy preset contract

Go to the project you've previously set up in Immutable Developer Hub.

Connect your minting Metamask wallet by clicking the Connect Wallet button on the top right menu of Hub and navigate to your project and environment.

In the Collections submenu, click Deploy contract:

  • Create a Name for your collection
  • Create a Symbol for your collection that is 2-3 characters long
  • Paste the Token Base URI from above into the Base URI field
  • Paste the Contract Metadata URI from above into the Collection Metadata URI field
Deploy contract modal
  • Enter the wallet address you created earlier as the royalty recipient
  • Enter 5 for Royalty fee. For the purpose of this tutorial, we will set royalty to be 5% default.
  • Click Deploy
  • Hub will automatically check your wallet's connected network. If your network is not already connected to the respective chain (IMX zkEVM Testnet or IMX zkEVM Mainnet), then you will prompted in Metamask to switch. Here, select Switch Network. If you are deploying on Testnet, tIMX will be automatically given to you via our faucet as part of the process.
Switching network
  • You will be prompted to sign a transaction with your wallet. This step costs gas and will deploy your contract.
Deploying contract
  • You will be prompted to sign a message with your wallet. This step is gasless and will link your collection to your project's environment.
Linking collection
  • Finally, you will be prompted to sign a transaction with your wallet. This step costs gas and will assign your wallet the minter role, so that you can mint tokens on the collection.
Granting minter role
🎉Contract Deployed Successfully!
You can now view your contract on the Immutable zkEVM Testnet Explorer or the Immutable zkEVM Mainnet Explorer by searching for your collection address (visible in Hub). Alternatively, you can click on your deployed contract in the Hub and click the Block Explorer link.
💡Advanced: launch contract manually
Instead of using Immutable Hub, you can launch your contracts via code with these steps:
  1. Set up your admin wallet and the zkEVM Testnet Network by following instructions here
  2. Follow instructions on deploying your contracts via code and request to be allowlisted
All collections on zkEVM are required to use Immutable's operator allowlist to protect content creators royalties and Immutable's 2% protocol fee. All Immutable Developer Hub collections automatically utilise this functionality.

Task 5: Set up your project backend (node.js)

note

This step is not required if you are using the Minting API.

We have already created a sample project which you can clone to mint quickly and easily:

Basic Preset Minting

git clone https://github.com/immutable/basic-preset-minting
cd basic-preset-minting
npm i

Task 6: Give your wallet the "minter" role

note

This step is not required if you are using the Minting API.

💡This may already be done for you
If you have deployed a contract through the Immutable Hub, you will have already been granted the minter role for your deployer wallet. If not, you can follow the steps below.

To mint NFTs, we need to use our "owner" wallet (which deployed our contract) to grant another wallet minting rights for our collection. In this tutorial, we're going to add the "minter" role to our existing "owner", so you don't need to set up a new wallet.

First, we will need to export your owner wallet's private key so it can be used in local scripts.

6.1 Locate your wallet's private key

💡Protect your private key
The script needs your wallet's private key, obtainable from Metamask by following these steps. Be cautious not to expose it in public or production code to safeguard your wallet's security.
  1. Open Metamask
  2. Make sure the network at the top of the screen is the test network you wish to deploy to
  3. Open Account details by clicking on the following button and selecting Account details
Upload File
  1. Select Show Private Key and enter your password
  2. Copy the long string provided (your private key) as this will be needed in the next step.

6.2 Add your private key to the .env file

We now need to configure your project with your private key in order to grant it the requisite authorisation to mint tokens. First, copy the code in .env.sample into a new .env file. Next, add the two variables below - the remaining variables will be set later:

  • CONTRACT_ADDRESS - The contract address of your collection - you can find this on Immutable Hub.
  • OWNER_PRIVATE_KEY - The private key you exported.

6.3 Perform the role grant

To complete the grant, simply run the following script:

npm run grant-role

Task 7.1: Option 1 - Mint tokens via contract function call

caution

Immutable's recommended ERC721 preset contract has multiple batch minting strategies tailored for different minting scenarios, which can save significant gas costs while minting.

To mint our first NFTs, we're once again going to use a sample script from the repository we cloned earlier. In the sample script, we mint 3 NFTs and distribute them to 2 recipient wallets - you can change this to suit your requirements.

All we need to do is ensure the remaining variables are now set in our .env file:

  • MINTER_PRIVATE_KEY - The private key of the wallet we just granted the minter role (may be same as Owner Private Key)
  • RECIPIENT_ONE - The first address of the wallet that will own the NFTs being minted in the batch
  • RECIPIENT_TWO - The second address of the wallet that will own the NFTs being minted in the batch

Now all that's left is to execute the mint itself:

npm run mint
🎉Congratulations on minting your first zkEVM NFTs!
You can use the tokens section of the Immutable zkEVM Testnet Explorer or the Immutable zkEVM Mainnet Explorer to verify that your assets have been minted on-chain (search for your collection address). You can also verify that the NFT is minted via the Immutable Hub interface.

Task 7.2: Option 2 - Mint tokens via Minting API

💡Minting API Enablement
The Minting API is now available to all developers using Immutable's preset contracts on testnet. This product is in an experimental phase; during this period the feature may undergo unannounced changes as we incorporate partner feedback.

We anticipate making the Minting API available on mainnet soon.

To gain access to the minting API on mainnet, please complete the following steps in Hub for Mainnet access. Kindly note that during the initial launch period, the minting API is exclusively available to partners under contract with Immutable.

The Minting API allows you to mint NFTs along with associated metadata through a straightforward API call. It leverages Immutable's preset contract function mintBatchByQuantity(), known for its gas efficiency.

For testing the Minting API, we suggest using an API platform such as Postman.

The following fields will be required to use the Minting API:

  • CONTRACT_ADDRESS - The contract address of your collection - you can find this on Immutable Hub.
  • SECRET_API_KEY - Secret key for your environment. Follow this guide to set yours up.
  • REFERENCE_ID_ONE - The internal content creator reference ID of the first asset being minted. This internal ID is used to link the request to the system-generated token ID. Each number must be unique for each collection's successful mints.
  • REFERENCE_ID_TWO - The internal content creator reference ID of the second asset being minted. This internal ID is used to link the request to the system-generated token ID. Each number must be unique for each collection's successful mints.
  • RECIPIENT_ONE - The first address of the wallet that will own the NFTs being minted in the batch
  • RECIPIENT_TWO - The second address of the wallet that will own the NFTs being minted in the batch

7.2.1: Authorizing Minting API for Collection Minting

The initial step involves authorizing the Minting API to perform minting operations for your collection.

Run the following command:

cast send "CONTRACT_ADDRESS" "grantMinterRole(address)" "0x9CcFbBaF5509B1a03826447EaFf9a0d1051Ad0CF" --rpc-url https://rpc.testnet.immutable.com/ --private-key "SECRET_API_KEY" --priority-gas-price 101000000000 --gas-price 101000000000

7.2.2: Minting Assets with Metadata

Next, we will proceed to mint our initial batch of NFTs. In this example, we will mint 2 NFTs destined for 2 different recipients.

It's important to note that every minting request through the Minting API must include an internal, unique reference_id. Once a mint is successful, this reference_id cannot be reused for additional mints within the same collection.

const chainName = 'imtbl-zkevm-testnet';
const contractAddress = CONTRACT_ADDRESS;
const response = await client.createMintRequest({
chainName,
contractAddress,
createMintRequestRequest: {
assets: [
{
owner_address: RECIPIENT_ONE,
reference_id: REFERENCE_ID_ONE,
metadata: {
image:
'https://immutable.github.io/sample-project-metadata/tokens/token1.webp',
animation_url: null,
youtube_url: null,
name: 'Test zkEVM NFT #1',
description:
'This NFT is my first zkEVM NFT created on Immutable',
external_url: null,
attributes: [
{
trait_type: 'Hat',
value: 'Top Hat',
},
{
trait_type: 'Coat',
value: 'Tails',
},
{
trait_type: 'Neck',
value: 'Bow Tie',
}
]
}
},
{
owner_address: RECIPIENT_TWO,
reference_id: REFERENCE_ID_TWO,
metadata: {
image:
'https://immutable.github.io/sample-project-metadata/tokens/token2.webp',
animation_url: null,
youtube_url: null,
name: 'Test zkEVM NFT #2',
description:
'This NFT is my second zkEVM NFT created on Immutable',
external_url: null,
attributes: [
{
trait_type: 'Hat',
value: 'Top Hat',
},
{
trait_type: 'Coat',
value: 'Tails',
},
{
trait_type: 'Neck',
value: 'Bow Tie',
}
]
}
}
]
}
});

7.2.3: Retrieving the Token ID

Execute the following command to retrieve the token_id of your newly minted NFT:

const chainName = 'imtbl-zkevm-testnet';
const contractAddress = CONTRACT_ADDRESS;
const referenceId = REFERENCE_ID_ONE;
const response = await client.getMintRequest({chainName, contractAddress, referenceId});

If the status in the results is "pending", wait a few seconds and try again. Once the mint is successful, the status will change to "succeeded".

The returned results should resemble the following sample, with the status indicating "succeeded" to confirm the successful mint.


{
"page": {
"next_cursor": null,
"previous_cursor": null
},
"result": [
{
"chain": {
"id": "eip155:13473",
"name": "imtbl-zkevm-testnet"
},
"collection_address": "0xe2e94d611d50370612e9721254807b7874093fb6",
"created_at": "2024-02-12T05:35:35.743242Z",
"error": null,
"owner_address": "0x68209e7086032941a8Cb14352c2F43b086288791",
"reference_id": "REFERENCE_ID_ONE",
"status": "succeeded",
"token_id": "TOKEN_ID_ONE",
"activity_id": "4e28df8d-f65c-4c11-ba04-6a9dd47b179b",
"transaction_hash": "0x6890c450a43e6f3e90b311e2c0e80e1e6880cbc93ab977fc5357ac66cd255800",
"updated_at": "2024-02-12T05:35:35.743242Z"
},
]
}


Get the corresponding token_id for both REFERENCE_ID_ONE and REFERENCE_ID_TWO.

7.2.4: Updating Metadata Files

If you've been following this guide, you'll need to update the corresponding metadata file that you set up in Task 2 for each asset.

Here are the changes you need to make:

  1. Rename the file to match the system-generated token_id obtained from the previous step.
  2. Update the id attribute to match the system-generated token_id obtained from the previous step.
  3. Update the token_id attribute to match the system-generated token_id obtained from the previous step.
  4. Save the file.
tip

For future mints, you can delay Task 2 until you've obtained the token_id.

However, after minting, ensure that the metadata file is created and that the metadata submitted with the mint request matches this file. Some ecosystem partners use the metadata source file rather than the Blockchain Data API. To ensure a consistent experience across the platform, always ensure that the Blockchain Data API and the local metadata file are consistent.

🎉Congratulations on minting your first zkEVM NFTs!
You can use the tokens section of the Immutable zkEVM Testnet Explorer or the Immutable zkEVM Mainnet Explorer to verify that your assets have been minted on-chain (search for your collection address). You can also verify that the NFT is minted via the Immutable Hub interface.