Skip to main content

🎏 How to create KIP37 tokens

In this section you will see how to build a Unity project using the KIP37 (ERC-1155) token standard on Klaytn.

Getting Started

Start by creating a new project by following the steps at the section Create a new Unity project. Make sure to install all dependencies to fix all bugs.

Use the WebLogin prefab to enable web3 wallet connection

Under AssetsWeb3UnityScenes, double-click on WebLogin. This is the prefab used to connect a wallet in a WebGL project.

Go to FileBuild SettingsWebGLSwitch Platform

From the same window, click on Add Open Scenes (top right) to add the Login scene as the first scene to appear when we run the project.

From the same window, click on Player SettingsPlayerResolution and Presentation, under WebGL Template, select the one with the same as our Unity version (WebGL 2020 for our case).

Go back to the Unity project. Under Assets, select Scenes and double-click on SampleScene to use it as our second scene (FYI the first one is the login scene).

Go to FileBuild SettingsAdd Open Scenes. The SampleScene will appear under the WebLogin scene. It means the SampleScene, where we will create the buttons to read and write to the contract, will be the next scene after the WebLogin.

Make sure the WebLogin scene is at the top because the order matters.

Create your Contract


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@klaytn/contracts/KIP/token/KIP37/KIP37.sol";
import "@klaytn/contracts/utils/Counters.sol";

contract KIP37Token is KIP37 {

mapping (uint256 => string) private _tokenURIs;
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;

constructor() KIP37("MultiTokenNFT") {}

function mintToken(string memory tokenURI, uint256 amount)
public returns(uint256) {
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId, amount, "");
_setTokenUri(newItemId, tokenURI);
_tokenIds.increment();
return newItemId;
}

function uri(uint256 tokenId) override public view
returns (string memory) {
return(_tokenURIs[tokenId]);
}

function _setTokenUri(uint256 tokenId, string memory tokenURI)
private {
_tokenURIs[tokenId] = tokenURI;
}
}

Create your C# script on Unity

Under Project window, right-click on Scenes, click on CreateC# Script Use the script below.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Numerics;
using UnityEngine.UI;
using Newtonsoft.Json;
public class MintKIP37 : MonoBehaviour
{
string chain = "klaytn";
string network = "testnet";
private string contract = "0x02476ac12EAED5d237dd03100aF430A7a378a3DE";
private readonly string abi = "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\",\"signature\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\",\"signature\":\"0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"TransferBatch\",\"type\":\"event\",\"signature\":\"0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TransferSingle\",\"type\":\"event\",\"signature\":\"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"URI\",\"type\":\"event\",\"signature\":\"0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"constant\":true,\"signature\":\"0x00fdd58e\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"owners\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"}],\"name\":\"balanceOfBatch\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"constant\":true,\"signature\":\"0x4e1273f4\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"constant\":true,\"signature\":\"0xe985e9c5\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeBatchTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0x2eb2c2d6\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xf242432a\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xa22cb465\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"constant\":true,\"signature\":\"0x01ffc9a7\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"tokenURI\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mintToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xc046372c\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"uri\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\",\"constant\":true,\"signature\":\"0x0e89341c\"}]";
string rpc = "https://public-node-api.klaytnapi.com/v1/baobab";
private string tokenURI = "https://ipfs.infura.io/ipfs/QmbmNhqKt7mnmFeKE17QwR5s2cTnfskQKDpx8UHwfbHx3v";
private string amount = "10";

// AddValue is called before the first frame update
async public void MintToken()
{
string method = "mintToken";
string[] obj = {tokenURI, amount};
string args = JsonConvert.SerializeObject(obj);
string value = "";
string gasLimit = "1000000";
string gasPrice = "250000000000";

try
{
string response = await Web3GL.SendContract(method, abi, contract, args, value, gasLimit, gasPrice);
Debug.Log(response);
} catch(Exception e)
{
Debug.LogException(e, this);
}
}

async public void BalanceOf()
{
string method = "balanceOf";
string owner = "0x7b9b65d4ee2fd57fc0dcfb3534938d31f63cba65";
string id = "0";
string[] obj = {owner, id};
string args = JsonConvert.SerializeObject(obj);
try
{
string response = await EVM.Call(chain, network, contract, abi, method, args, rpc);
Debug.Log(response);
} catch(Exception e)
{
Debug.LogException(e, this);
}
}
}


Create the buttons

We will create 2 buttons (Balance, Mint) on the UI to interact with our KIP37 token. To create the buttons, follow the steps in the section Custom Interaction with Login.

Test the balanceOf method

Click on ▶️ to run the program and test the Balance button.

You should get a result from the Owner and the Id of the token that we put in the script.

Build and Run the project to test the mint method

Go to FileBuild and Run. Click on Login to connect Metamask. Click on the mint button. Confirm your transaction. Here are the details of the transaction on Klaytnscope.

info

If you have any questions, please join our Discord server, or send us an email at developers@klaytn.foundation