Technology, Tutorials, for Developer

How to Token-Gate a Unity game using Chainsafe and Thirdweb on Klaytn

Table of Content

  • Background
  • Prerequisites
  • Getting Started
  • Downloading ChainSafe Gaming SDK
  • Initializing and setting up Unity project
  • Importing ChainSafe SDK into your project
  • ChainSafe Server Settings
  • Setting up WebLogin Prefab and Gaming Scene
  • Creating and deploying NFT smart contract using Thirdweb
  • Creating Game Objects
  • Creating C# Script on Unity
  • Connecting C# Script with game objects
  •  Testing and running game application
  • Conclusion

Background

Token gating is a system that gives holders of specific tokens (fungible or non-fungible) access to exclusive contents, events, experiences, and much more. Think of these tokens as the key to accessing the world of exclusivity.

As it is, token gating wields the immutable, decentralized and  transparent nature of blockchain and smart contracts to give members of a community exclusive experiences. That said, once a member attempts to access the token-gated content or experience, the system checks their digital wallet to confirm if the required token is present. If the user’s wallet contains the required token, access is granted; otherwise, it is denied.

This exciting innovation is a powerful tool for creating exclusivity and rewarding loyal community members, which in turn fosters a strong sense of community among members. In the past years, token-gating has been applied and implemented for the following use cases:

  • Exclusive communities and Discord channels:In this case, access to all community channels, or some, is restricted to token holders. A popular example of this is Developer DAO, a DAO on a mission to accelerate the education and impact of a new wave of web3 builders. To access the Developer DAO Discord, you need to hold one of either the original Devs for Revolution (D4R) NFT or at least 400 CODE tokens.
  • Online experiences: Online experiences can also be token-gated. From token-gated metaverse spaces to online webinars and community meetups, this model is exemplified by platforms such as SandBox and Decentraland, which allow holders of specific tokens access to exclusive areas in their metaverse or game.
  • Token-gated contents: access to articles, video content, and educational resources can also be token-gated, hence giving the user an exclusive experience. An example of this is The Block, which token-gates access to exclusive articles.
  • Real-life events: Access to special events in real life has been transformed by the exciting feature that token-gating brings. Simply put, token gating can be used to manage access to exclusive concerts, VIP parties, and conferences. This model is exemplified in scenarios where NFT communities such as Deadfellaz and Bored Ape Yacht Club have hosted token-gated events where attendance is based on owning the required NFT.

Token gating is redefining access and exclusivity in online communities and beyond, and as such, it is a transformative concept in the digital asset space. In this tutorial, you will build a token-gated Unity game using ChainSafe SDK and Thirdweb on Klaytn.

The final output will look like this:

Prerequisites

  1. Download Unity Hub
  2. Project ID from Chainsafe dashboard

Getting Started

By the end of this article you will have your Unity game token-gated by leveraging ChainSafe SDK and thirdweb. To get started, follow through this step by step guide. 

Downloading ChainSafe Gaming SDK

  • Navigate to the releases, and click version 2.1.0 release
  • Click on web3.unitypackage to download the package

Initializing and setting up Unity project

  • Make sure to have installed Unity hub and Unity editor (for this guide we installed Unity editor version 2022.3.16f1).
  • Create a new 3D Unity project: To create a new project, do these:
    • Navigate to the Projects tab,
    • Click on the New project button
  • Select All templates. We will use a 3D template.
  • Fill the project name field in the Project Settings tab
  • Click on Create project

Importing ChainSafe SDK into your project

  • Drag the downloaded web3.unitypackage file in the Installation section into the Unity project
  • To have a smooth run using the ChainSafe SDK, you might want to install the NewtonSoft package. This is important to avoid this error as seen below in the console:
  • Import the package as follows: Window -> Package Manager -> My Assets -> JSON. NET For Unity -> Import

ChainSafe Server Settings 

While setting up your Unity project, you are required to register your project with ChainSafe in order to successfully build with the SDK. In the case where you get a ChainSafeServerSettings prompt while importing the ChainSafe SDK  in the step above, do the following

  • Fill each field of the prompt box with the necessary value (Project ID, Chain ID, Chain, Network, RPC)
  • Click the Save Settings button. 

You can as well look up this guide for more details. 

Setting up WebLogin Prefab and Gaming Scene

In this section, we will  set the WebLogin prefab to enable web3 wallet connection and also the gaming scene where the token-gating action takes place.

  • Under Assets → Web3Unity → Scenes, double-click on WebLogin. This is the prefab used to connect a wallet in a WebGL project.
  • Go to File → Build Settings → WebGL → Switch 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 Settings → Player → Resolution and Presentation, under WebGL Template, select the one with the same as our Unity version (WebGL 2020 for our case).

Gaming Scene

  • Go back to the Unity project. Under Assets, select Scenes and double-click on SampleScene (current gaming scene) to use it as our second scene (FYI the first one is the login scene)
  • Go to File → Build Settings → Add Open Scenes. The SampleScene will appear under the WebLogin scene. The SampleScene is where we will create the buttons to read and write to the contract. This scene will pop-up after the WebLogin.
*Note: Make sure the WebLogin scene is at the top because the order matters. 

Creating and deploying NFT smart contract using Thirdweb

In this section we will deploy an NFT drop contract using the thirdweb dashboard. This contract allows players to claim an NFT having fulfilled the claim condition set by the creator of the NFT.  We would create and deploy the NFT drop contracts in the following steps:

  1. Navigate to the contracts tab, explore section and select the NFT Drop contract.

2. Click on the Deploy Now button

3. Fill in the contract parameters such as NAME (YouniversePassCard), SYMBOL (YPC), Description etc, configure the chain (Klaytn Testnet Baobab) you want to deploy to and hit the Deploy Now button. 

4.  Confirm the transaction and wait for your contract to be deployed and added to the contract dashboard.

5. Once the newly deployed contract dashboard is loaded, navigate to NFT section to Lazy mint new tokens by clicking the Single Upload button

6. Fill in the metadata of the NFT you want to mint

7. Confirm the transaction and wait for the mint process to be completed. 

Next is to set the claim condition for the newly minted NFT so that game players can easily claim. To set the claim condition, do the following:

  • Navigate to the Claim Condition section under the extension tab and click the Add Phase button 
  • Select the Public option from the add phase option
  • Fill in the claim conditions you want during this claim phase. As you can see below, we did set the following:
    • How many NFTs will you drop in this phase: Unlimited
    • How much do you want to charge to claim each NFT: 0 KLAY
    • How many NFTs can be claimed per wallet: 1
  • Click the Save Phases button to save this claim phase.

Creating game objects 

In this section, we will create 3 game objects with their corresponding sub-components, which are:

a. playGame: This is a button component which when clicked checks if the player has the Youniverse PassCard NFT or not and is eligible to start the game.
b. hasNFT: This is a combination of text  and button UI components. It is displayed when the player have the PassCard NFT
c. noNFT : This is a combination of text and button UI components. It is displayed when the player doesn’t have the PassCard NFT.

To create the playGame component, 

  • Right-click on the Sample Scene, click on GameObject → UI → Button (Text Mesh Pro) and rename the button to playGame
  • Make sure to rename the Text UI component to playGame

To create the hasNFT component, 

  • Right-click on the Canvas component, click on GameObject → UI → Text Mesh Pro and rename the text object to hasNFT
  • Make sure to fill the text object with the text you want the player to see if verified to have a PassCard NFT. For example “Proceed to enter Youniverse. You have the PassCard”
  • Right-click on the hasNFT component, click on GameObject → UI → Button (Text Mesh Pro) and rename the text to startGame. This button allows passCard NFT owners to start the game.
  • Make sure to rename the Button Text to startGame

To create the noNFT component, 

  • Right-click on the Canvas component, click on GameObject → UI → Text Mesh Pro and rename the text object to noNFT
  • Make sure to fill the text object with the text you want the player to see if verified not to have a PassCard NFT. For example “You can’t proceed to enter Youniverse. You do not have the PassCard”
  • Right-click on the noNFT component, click on GameObject → UI → Button (Text Mesh Pro) and rename the text to claimNFT. Thos button allows none passCard NFT holders to be able to claim one.
  • Make sure to rename the Button Text to claimNFT

Creating C# Script on Unity

  • Under Asset tab, right-click on Scenes, click on Create → C# Script and rename it to tokenGating
  • Open the script in VS Code and paste the code below.
  • You can change some values like the contract address in the script to fit yours.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Numerics;
using UnityEngine.UI;
using Newtonsoft.Json;
using Web3Unity.Scripts.Library.ETHEREUEM.EIP;
using Web3Unity.Scripts.Library.Ethers.Providers;
using Web3Unity.Scripts.Library.Ethers.Contracts;
public class tokenGating : MonoBehaviour
{
    public GameObject playGame;
    public GameObject hasNFT;
    public GameObject noNFT;
    private string contractAddress = "PASTE CONTRACT ADDRESS";
    private readonly string contractAbi = "[ { \"type\": \"constructor\", \"name\": \"\", \"inputs\": [], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"error\", \"name\": \"ApprovalCallerNotOwnerNorApproved\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"ApprovalQueryForNonexistentToken\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"ApprovalToCurrentOwner\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"ApproveToCaller\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"BalanceQueryForZeroAddress\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"MintToZeroAddress\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"MintZeroQuantity\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"OwnerQueryForNonexistentToken\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"TransferCallerNotOwnerNorApproved\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"TransferFromIncorrectOwner\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"TransferToNonERC721ReceiverImplementer\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"TransferToZeroAddress\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"error\", \"name\": \"URIQueryForNonexistentToken\", \"inputs\": [], \"outputs\": [] }, { \"type\": \"event\", \"name\": \"Approval\", \"inputs\": [ { \"type\": \"address\", \"name\": \"owner\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"approved\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"tokenId\", \"indexed\": true, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"ApprovalForAll\", \"inputs\": [ { \"type\": \"address\", \"name\": \"owner\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"operator\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"bool\", \"name\": \"approved\", \"indexed\": false, \"internalType\": \"bool\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"BatchMetadataUpdate\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_fromTokenId\", \"indexed\": false, \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"_toTokenId\", \"indexed\": false, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"ClaimConditionsUpdated\", \"inputs\": [ { \"type\": \"tuple[]\", \"name\": \"claimConditions\", \"components\": [ { \"type\": \"uint256\", \"name\": \"startTimestamp\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"maxClaimableSupply\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"supplyClaimed\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"quantityLimitPerWallet\", \"internalType\": \"uint256\" }, { \"type\": \"bytes32\", \"name\": \"merkleRoot\", \"internalType\": \"bytes32\" }, { \"type\": \"uint256\", \"name\": \"pricePerToken\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"currency\", \"internalType\": \"address\" }, { \"type\": \"string\", \"name\": \"metadata\", \"internalType\": \"string\" } ], \"indexed\": false, \"internalType\": \"struct IClaimCondition.ClaimCondition[]\" }, { \"type\": \"bool\", \"name\": \"resetEligibility\", \"indexed\": false, \"internalType\": \"bool\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"ContractURIUpdated\", \"inputs\": [ { \"type\": \"string\", \"name\": \"prevURI\", \"indexed\": false, \"internalType\": \"string\" }, { \"type\": \"string\", \"name\": \"newURI\", \"indexed\": false, \"internalType\": \"string\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"DefaultRoyalty\", \"inputs\": [ { \"type\": \"address\", \"name\": \"newRoyaltyRecipient\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"newRoyaltyBps\", \"indexed\": false, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"FlatPlatformFeeUpdated\", \"inputs\": [ { \"type\": \"address\", \"name\": \"platformFeeRecipient\", \"indexed\": false, \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"flatFee\", \"indexed\": false, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"Initialized\", \"inputs\": [ { \"type\": \"uint8\", \"name\": \"version\", \"indexed\": false, \"internalType\": \"uint8\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"MaxTotalSupplyUpdated\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"maxTotalSupply\", \"indexed\": false, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"MetadataFrozen\", \"inputs\": [], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"OwnerUpdated\", \"inputs\": [ { \"type\": \"address\", \"name\": \"prevOwner\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"newOwner\", \"indexed\": true, \"internalType\": \"address\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"PlatformFeeInfoUpdated\", \"inputs\": [ { \"type\": \"address\", \"name\": \"platformFeeRecipient\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"platformFeeBps\", \"indexed\": false, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"PlatformFeeTypeUpdated\", \"inputs\": [ { \"type\": \"uint8\", \"name\": \"feeType\", \"indexed\": false, \"internalType\": \"enum IPlatformFee.PlatformFeeType\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"PrimarySaleRecipientUpdated\", \"inputs\": [ { \"type\": \"address\", \"name\": \"recipient\", \"indexed\": true, \"internalType\": \"address\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"RoleAdminChanged\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"indexed\": true, \"internalType\": \"bytes32\" }, { \"type\": \"bytes32\", \"name\": \"previousAdminRole\", \"indexed\": true, \"internalType\": \"bytes32\" }, { \"type\": \"bytes32\", \"name\": \"newAdminRole\", \"indexed\": true, \"internalType\": \"bytes32\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"RoleGranted\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"indexed\": true, \"internalType\": \"bytes32\" }, { \"type\": \"address\", \"name\": \"account\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"sender\", \"indexed\": true, \"internalType\": \"address\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"RoleRevoked\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"indexed\": true, \"internalType\": \"bytes32\" }, { \"type\": \"address\", \"name\": \"account\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"sender\", \"indexed\": true, \"internalType\": \"address\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"RoyaltyForToken\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"tokenId\", \"indexed\": true, \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"royaltyRecipient\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"royaltyBps\", \"indexed\": false, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"TokenURIRevealed\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"index\", \"indexed\": true, \"internalType\": \"uint256\" }, { \"type\": \"string\", \"name\": \"revealedURI\", \"indexed\": false, \"internalType\": \"string\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"TokensClaimed\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"claimConditionIndex\", \"indexed\": true, \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"claimer\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"receiver\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"startTokenId\", \"indexed\": false, \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"quantityClaimed\", \"indexed\": false, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"TokensLazyMinted\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"startTokenId\", \"indexed\": true, \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"endTokenId\", \"indexed\": false, \"internalType\": \"uint256\" }, { \"type\": \"string\", \"name\": \"baseURI\", \"indexed\": false, \"internalType\": \"string\" }, { \"type\": \"bytes\", \"name\": \"encryptedBaseURI\", \"indexed\": false, \"internalType\": \"bytes\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"event\", \"name\": \"Transfer\", \"inputs\": [ { \"type\": \"address\", \"name\": \"from\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"to\", \"indexed\": true, \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"tokenId\", \"indexed\": true, \"internalType\": \"uint256\" } ], \"outputs\": [], \"anonymous\": false }, { \"type\": \"function\", \"name\": \"DEFAULT_ADMIN_ROLE\", \"inputs\": [], \"outputs\": [ { \"type\": \"bytes32\", \"name\": \"\", \"internalType\": \"bytes32\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"approve\", \"inputs\": [ { \"type\": \"address\", \"name\": \"to\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"balanceOf\", \"inputs\": [ { \"type\": \"address\", \"name\": \"owner\", \"internalType\": \"address\" } ], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"batchFrozen\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"burn\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"claim\", \"inputs\": [ { \"type\": \"address\", \"name\": \"_receiver\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_quantity\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"_currency\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_pricePerToken\", \"internalType\": \"uint256\" }, { \"type\": \"tuple\", \"name\": \"_allowlistProof\", \"components\": [ { \"type\": \"bytes32[]\", \"name\": \"proof\", \"internalType\": \"bytes32[]\" }, { \"type\": \"uint256\", \"name\": \"quantityLimitPerWallet\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"pricePerToken\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"currency\", \"internalType\": \"address\" } ], \"internalType\": \"struct IDrop.AllowlistProof\" }, { \"type\": \"bytes\", \"name\": \"_data\", \"internalType\": \"bytes\" } ], \"outputs\": [], \"stateMutability\": \"payable\" }, { \"type\": \"function\", \"name\": \"claimCondition\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"currentStartId\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"count\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"contractType\", \"inputs\": [], \"outputs\": [ { \"type\": \"bytes32\", \"name\": \"\", \"internalType\": \"bytes32\" } ], \"stateMutability\": \"pure\" }, { \"type\": \"function\", \"name\": \"contractURI\", \"inputs\": [], \"outputs\": [ { \"type\": \"string\", \"name\": \"\", \"internalType\": \"string\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"contractVersion\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint8\", \"name\": \"\", \"internalType\": \"uint8\" } ], \"stateMutability\": \"pure\" }, { \"type\": \"function\", \"name\": \"encryptDecrypt\", \"inputs\": [ { \"type\": \"bytes\", \"name\": \"data\", \"internalType\": \"bytes\" }, { \"type\": \"bytes\", \"name\": \"key\", \"internalType\": \"bytes\" } ], \"outputs\": [ { \"type\": \"bytes\", \"name\": \"result\", \"internalType\": \"bytes\" } ], \"stateMutability\": \"pure\" }, { \"type\": \"function\", \"name\": \"encryptedData\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"bytes\", \"name\": \"\", \"internalType\": \"bytes\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"freezeBatchBaseURI\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_index\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"getActiveClaimConditionId\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getApproved\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getBaseURICount\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getBatchIdAtIndex\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_index\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getClaimConditionById\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_conditionId\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"tuple\", \"name\": \"condition\", \"components\": [ { \"type\": \"uint256\", \"name\": \"startTimestamp\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"maxClaimableSupply\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"supplyClaimed\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"quantityLimitPerWallet\", \"internalType\": \"uint256\" }, { \"type\": \"bytes32\", \"name\": \"merkleRoot\", \"internalType\": \"bytes32\" }, { \"type\": \"uint256\", \"name\": \"pricePerToken\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"currency\", \"internalType\": \"address\" }, { \"type\": \"string\", \"name\": \"metadata\", \"internalType\": \"string\" } ], \"internalType\": \"struct IClaimCondition.ClaimCondition\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getDefaultRoyaltyInfo\", \"inputs\": [], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" }, { \"type\": \"uint16\", \"name\": \"\", \"internalType\": \"uint16\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getFlatPlatformFeeInfo\", \"inputs\": [], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getPlatformFeeInfo\", \"inputs\": [], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" }, { \"type\": \"uint16\", \"name\": \"\", \"internalType\": \"uint16\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getPlatformFeeType\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint8\", \"name\": \"\", \"internalType\": \"enum IPlatformFee.PlatformFeeType\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getRevealURI\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_batchId\", \"internalType\": \"uint256\" }, { \"type\": \"bytes\", \"name\": \"_key\", \"internalType\": \"bytes\" } ], \"outputs\": [ { \"type\": \"string\", \"name\": \"revealedURI\", \"internalType\": \"string\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getRoleAdmin\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" } ], \"outputs\": [ { \"type\": \"bytes32\", \"name\": \"\", \"internalType\": \"bytes32\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getRoleMember\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" }, { \"type\": \"uint256\", \"name\": \"index\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"address\", \"name\": \"member\", \"internalType\": \"address\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getRoleMemberCount\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" } ], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"count\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getRoyaltyInfoForToken\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" }, { \"type\": \"uint16\", \"name\": \"\", \"internalType\": \"uint16\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"getSupplyClaimedByWallet\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_conditionId\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"_claimer\", \"internalType\": \"address\" } ], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"supplyClaimedByWallet\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"grantRole\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" }, { \"type\": \"address\", \"name\": \"account\", \"internalType\": \"address\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"hasRole\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" }, { \"type\": \"address\", \"name\": \"account\", \"internalType\": \"address\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"hasRoleWithSwitch\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" }, { \"type\": \"address\", \"name\": \"account\", \"internalType\": \"address\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"initialize\", \"inputs\": [ { \"type\": \"address\", \"name\": \"_defaultAdmin\", \"internalType\": \"address\" }, { \"type\": \"string\", \"name\": \"_name\", \"internalType\": \"string\" }, { \"type\": \"string\", \"name\": \"_symbol\", \"internalType\": \"string\" }, { \"type\": \"string\", \"name\": \"_contractURI\", \"internalType\": \"string\" }, { \"type\": \"address[]\", \"name\": \"_trustedForwarders\", \"internalType\": \"address[]\" }, { \"type\": \"address\", \"name\": \"_saleRecipient\", \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"_royaltyRecipient\", \"internalType\": \"address\" }, { \"type\": \"uint128\", \"name\": \"_royaltyBps\", \"internalType\": \"uint128\" }, { \"type\": \"uint128\", \"name\": \"_platformFeeBps\", \"internalType\": \"uint128\" }, { \"type\": \"address\", \"name\": \"_platformFeeRecipient\", \"internalType\": \"address\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"isApprovedForAll\", \"inputs\": [ { \"type\": \"address\", \"name\": \"owner\", \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"operator\", \"internalType\": \"address\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"isEncryptedBatch\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_batchId\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"isTrustedForwarder\", \"inputs\": [ { \"type\": \"address\", \"name\": \"forwarder\", \"internalType\": \"address\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"lazyMint\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_amount\", \"internalType\": \"uint256\" }, { \"type\": \"string\", \"name\": \"_baseURIForTokens\", \"internalType\": \"string\" }, { \"type\": \"bytes\", \"name\": \"_data\", \"internalType\": \"bytes\" } ], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"batchId\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"maxTotalSupply\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"multicall\", \"inputs\": [ { \"type\": \"bytes[]\", \"name\": \"data\", \"internalType\": \"bytes[]\" } ], \"outputs\": [ { \"type\": \"bytes[]\", \"name\": \"results\", \"internalType\": \"bytes[]\" } ], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"name\", \"inputs\": [], \"outputs\": [ { \"type\": \"string\", \"name\": \"\", \"internalType\": \"string\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"nextTokenIdToClaim\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"nextTokenIdToMint\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"owner\", \"inputs\": [], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"ownerOf\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"primarySaleRecipient\", \"inputs\": [], \"outputs\": [ { \"type\": \"address\", \"name\": \"\", \"internalType\": \"address\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"renounceRole\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" }, { \"type\": \"address\", \"name\": \"account\", \"internalType\": \"address\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"reveal\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_index\", \"internalType\": \"uint256\" }, { \"type\": \"bytes\", \"name\": \"_key\", \"internalType\": \"bytes\" } ], \"outputs\": [ { \"type\": \"string\", \"name\": \"revealedURI\", \"internalType\": \"string\" } ], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"revokeRole\", \"inputs\": [ { \"type\": \"bytes32\", \"name\": \"role\", \"internalType\": \"bytes32\" }, { \"type\": \"address\", \"name\": \"account\", \"internalType\": \"address\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"royaltyInfo\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"salePrice\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"address\", \"name\": \"receiver\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"royaltyAmount\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"safeTransferFrom\", \"inputs\": [ { \"type\": \"address\", \"name\": \"from\", \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"to\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"safeTransferFrom\", \"inputs\": [ { \"type\": \"address\", \"name\": \"from\", \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"to\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" }, { \"type\": \"bytes\", \"name\": \"_data\", \"internalType\": \"bytes\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setApprovalForAll\", \"inputs\": [ { \"type\": \"address\", \"name\": \"operator\", \"internalType\": \"address\" }, { \"type\": \"bool\", \"name\": \"approved\", \"internalType\": \"bool\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setClaimConditions\", \"inputs\": [ { \"type\": \"tuple[]\", \"name\": \"_conditions\", \"components\": [ { \"type\": \"uint256\", \"name\": \"startTimestamp\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"maxClaimableSupply\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"supplyClaimed\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"quantityLimitPerWallet\", \"internalType\": \"uint256\" }, { \"type\": \"bytes32\", \"name\": \"merkleRoot\", \"internalType\": \"bytes32\" }, { \"type\": \"uint256\", \"name\": \"pricePerToken\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"currency\", \"internalType\": \"address\" }, { \"type\": \"string\", \"name\": \"metadata\", \"internalType\": \"string\" } ], \"internalType\": \"struct IClaimCondition.ClaimCondition[]\" }, { \"type\": \"bool\", \"name\": \"_resetClaimEligibility\", \"internalType\": \"bool\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setContractURI\", \"inputs\": [ { \"type\": \"string\", \"name\": \"_uri\", \"internalType\": \"string\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setDefaultRoyaltyInfo\", \"inputs\": [ { \"type\": \"address\", \"name\": \"_royaltyRecipient\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_royaltyBps\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setFlatPlatformFeeInfo\", \"inputs\": [ { \"type\": \"address\", \"name\": \"_platformFeeRecipient\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_flatFee\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setMaxTotalSupply\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_maxTotalSupply\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setOwner\", \"inputs\": [ { \"type\": \"address\", \"name\": \"_newOwner\", \"internalType\": \"address\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setPlatformFeeInfo\", \"inputs\": [ { \"type\": \"address\", \"name\": \"_platformFeeRecipient\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_platformFeeBps\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setPlatformFeeType\", \"inputs\": [ { \"type\": \"uint8\", \"name\": \"_feeType\", \"internalType\": \"enum IPlatformFee.PlatformFeeType\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setPrimarySaleRecipient\", \"inputs\": [ { \"type\": \"address\", \"name\": \"_saleRecipient\", \"internalType\": \"address\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"setRoyaltyInfoForToken\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_tokenId\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"_recipient\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_bps\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"supportsInterface\", \"inputs\": [ { \"type\": \"bytes4\", \"name\": \"interfaceId\", \"internalType\": \"bytes4\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"symbol\", \"inputs\": [], \"outputs\": [ { \"type\": \"string\", \"name\": \"\", \"internalType\": \"string\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"tokenURI\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [ { \"type\": \"string\", \"name\": \"\", \"internalType\": \"string\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"totalMinted\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"totalSupply\", \"inputs\": [], \"outputs\": [ { \"type\": \"uint256\", \"name\": \"\", \"internalType\": \"uint256\" } ], \"stateMutability\": \"view\" }, { \"type\": \"function\", \"name\": \"transferFrom\", \"inputs\": [ { \"type\": \"address\", \"name\": \"from\", \"internalType\": \"address\" }, { \"type\": \"address\", \"name\": \"to\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"tokenId\", \"internalType\": \"uint256\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"updateBatchBaseURI\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_index\", \"internalType\": \"uint256\" }, { \"type\": \"string\", \"name\": \"_uri\", \"internalType\": \"string\" } ], \"outputs\": [], \"stateMutability\": \"nonpayable\" }, { \"type\": \"function\", \"name\": \"verifyClaim\", \"inputs\": [ { \"type\": \"uint256\", \"name\": \"_conditionId\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"_claimer\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_quantity\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"_currency\", \"internalType\": \"address\" }, { \"type\": \"uint256\", \"name\": \"_pricePerToken\", \"internalType\": \"uint256\" }, { \"type\": \"tuple\", \"name\": \"_allowlistProof\", \"components\": [ { \"type\": \"bytes32[]\", \"name\": \"proof\", \"internalType\": \"bytes32[]\" }, { \"type\": \"uint256\", \"name\": \"quantityLimitPerWallet\", \"internalType\": \"uint256\" }, { \"type\": \"uint256\", \"name\": \"pricePerToken\", \"internalType\": \"uint256\" }, { \"type\": \"address\", \"name\": \"currency\", \"internalType\": \"address\" } ], \"internalType\": \"struct IDrop.AllowlistProof\" } ], \"outputs\": [ { \"type\": \"bool\", \"name\": \"isOverride\", \"internalType\": \"bool\" } ], \"stateMutability\": \"view\" } ]";

    
    public string playerAccount;

     void Start() 
     { 
        string account = PlayerPrefs.GetString("Account");
        playerAccount = account;
        print("User account is :" + " " + playerAccount);     
        hasNFT = GameObject.Find("Canvas/hasNFT");
        noNFT = GameObject.Find("Canvas/noNFT");
        playGame = GameObject.Find("Canvas/playGame");
        if(hasNFT) {
            hasNFT.SetActive(false);
            print("hasNFT is false at start");     
        }
        if(noNFT) {
            noNFT.SetActive(false);
            print("noNFT is false at start");     
        }  
     }
    
    // calls the "balanceOf" function
    async public void checkBalance()
    {
        var provider = new JsonRpcProvider("https://klaytn-baobab-rpc.allthatnode.com:8551");
        var contract = new Contract(contractAbi, contractAddress, provider);
        var calldata = await contract.Call("balanceOf", new object[]
        {
            PlayerPrefs.GetString("Account"),
        });
        Debug.Log(calldata[0].ToString());
        string balance = calldata[0].ToString();
        float bal = float.Parse(balance);
        if(bal > 0){
            hasNFT.SetActive(true);
        } else {
            noNFT.SetActive(true); 
        }      
    }
    // call claim function
        async public void claimNFT()
    {
        int quantity = 1;
        string currencyAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
        int pricePerToken = 0;
        object[] allowProof = new object[]{
            new string[] {},
            quantity,
            pricePerToken,
            currencyAddress
        };
        string data = "0x";
      
        // function name
        string method = "claim";
        // put arguments in an array of string
        object[] obj = new object[]{playerAccount, quantity, currencyAddress, pricePerToken, allowProof, data};
        // serialize arguments
        string args = JsonConvert.SerializeObject(obj);
        // value in peb (wei) in a transaction
        string value = "0";
        // gas limit: REQUIRED
        string gasLimit = "1000000";
        // gas price: REQUIRED
        string gasPrice = "250000000000";
        try
        {          
        string response = await Web3GL.SendContract(method, contractAbi, contractAddress, args, value, gasLimit, gasPrice);            
            Debug.Log(response);
        } catch(Exception e) 
        {
            Debug.LogException(e, this);
        }
    }
}

Connecting C# Script with game objects

In this section, we will connect the following buttons with their respective functions from the tokenGating script:

A. playGame: 

  • Click on playGame button from the Hierarchy window
  • Drag the tokenGating script into the right window (Add Component tab)
  • Add an OnClick() function by clicking on the ➕ button
  • Drag the playGame button from Hierarchy window into the On Click() function
  • Click on No Function → tokenGating → checkBalance()

B. claimNFT

  • Navigate to the claimNFT button in the noNFT component from the Hierarchy window
  • Drag the tokenGating script into the right window (Add Component tab)
  • Add an OnClick() function by clicking on the ➕ button
  • Drag the claimNFT button from Hierarchy window into the On Click() function
  • Click on No Function → tokenGating → claimNFT()

Testing and running game application

In this section, we will test the token-gating functionality in the game application. We expect that anyone who owns a Youniverse PassCard NFT will get a prompt to start the game and if otherwise will be able to claim one Youniverse PassCard NFT.

To see this in action, 

  • Build and run the project: Navigate to File → Build and Run
  • When the project builds and run, it opens a tab in your browser — webLogin scene
  • Click on Login to connect Metamask. 
  • Once connected, click on playGame to confirm if the player is eligible.

If the player is not eligible, you should see this prompt on your screen and a button to claim a Youniverse PassCard NFT. Once an ineligible player claims the NFT, he/she would be able to start the game. 

If a player is eligible, you should see the message below on your screen and a button to start the game. 

Conclusion

Congratulations on successfully token-gating your Unity game application. In this tutorial, we learnt the concept of token-gating, how it is applied in the real world, and how to make your Unity game application token-gated.

From here, you could also explore some other options in your game like adding a functionality to the start game button. If you want more information, visit Klaytn Docs and Chainsafe Docs. If you have any questions, visit Klaytn Forum.