Skip to main content

12. Crafting assets

💡Info
The complete code for this step can be found in the branch named step_12.

Crafting in gaming is a game mechanic that allows players to combine or manipulate in-game assets, items, or resources to create new, more valuable, or unique items. This process involves taking various components or materials and using them to "craft" something else within the game world.

One of the ways to craft in-game assets is through "minting and burning". This involves creating a new asset by collecting and burning other assets in the crafting operation. For example, in Immutable Runner, players can create or 'craft' a new skin for their fox by burning the coins they have collected

In this tutorial, you will use the craftSkin() function inside the Immutable Runner Token ERC20 contract you previously deployed in step 10 to craft a new skin for the player's fox.

Request pre-approval

To interact with a contract using the Immutable Unity SDK, you need to use the zkEVM Send Transaction method. This method requires our pre-approval, so please contact us before using it.

You will be required to provide us with the following details when asking for pre-approval:

  • Your game’s client ID.
  • The environment, i.e. Sandbox/Testnet, for this tutorial.
  • The contract address of the Immutable Runner Token.
  • The signature of the contract function you want to interact with, i.e. craftSkin(). We will cover how to calculate the signature later on in this section.

Send Transaction

When you want to call a function, you usually write expressions like functionName(requiredArguments). However, EVM does not understand such expressions. Instead, it understands hexadecimal expressions encoded in terms of its ABI (Application Binary Interface).

To call the Immutable Runner Token craftSkin() function, you must send 0x1e957f1e as the data or payload to the EVM. This payload is constructed by calculating the function's signature and encoding the function’s arguments, if any.

Calculate function signature

Every function in a smart contract has a signature derived from the function name and its parameters. The signature is calculated using the Keccak-256 hash function and consists of the first four bytes of the hash output.

For instance, if you take the function craftSkin() and calculate its signature using an online tool like this (keccak256(craftSkin())), and grab the first four bytes of the output, you get 0x1e957f1e.

Keccak-256 craft skin

Encode the function arguments

As craftSkin() does not require any arguments, there is no need to encode any.

💡Argument encoding
This tutorial does not cover argument encoding. If your contract function needs arguments, please refer to our guide on sendTransaction Data Encoding or this page for an example of how encoding works.

Construct the transaction

By concatenating the function signature, followed by any encoded arguments, you now have the payload to tell the EVM which function to call. The payload is the function signature if the function doesn't require any arguments, as with craftSkin().

To use the zkEVM Send Transaction method, you need to provide three things:

  1. to: The address of the contract you want to interact with, in this case, the Immutable Runner Token contract.
  2. value: The value to transfer for the transaction. Since you are only interacting with the contract and not sending any value to it, you can set this to zero.
  3. data: A byte string that contains the associated data or payload of the message. This is the payload you calculated from the function's signature and arguments: 0x1e957f1e.

Craft skin

In the LevelCompleteScreen.cs file, the 'Next' button will only be visible to the player if logged in to Passport. Modify the 'Next' button so that it redirects the player to the Unlocked Skin screen instead of the next level if their fox is not already using a new skin.

Assets/Shared/Scripts/UI/LevelCompleteScreen.cs

private void OnNextButtonClicked()
{
// Check if the player is already using a new skin
if (!SaveManager.Instance.UseNewSkin)
{
// Player is not using a new skin, take player to Unlocked Skin screen
m_UnlockedSkinEvent.Raise();
}
else
{
// Player is already using a new skin, take player to the next level
m_NextLevelEvent.Raise();
}
}

Update the Craft() function to craft a skin by burning three coins. Note that the game will not check whether the player has enough coins to burn, to keep it simple.

Assets/Shared/Scripts/UI/UnlockedSkinScreen.cs

using Immutable.Passport;
using Immutable.Passport.Model;

private async void Craft()
{
m_CraftState = CraftSkinState.Crafting;

// Burn tokens and mint a new skin i.e. crafting a skin
string transactionHash = await Passport.Instance.ZkEvmSendTransaction(new TransactionRequest()
{
to = "YOUR_IMMUTABLE_RUNNER_TOKEN_CONTRACT_ADDRESS", // Immutable Runner Token contract address
data = "0x1e957f1e", // Call craftSkin() in the contract
value = "0"
});
Debug.Log($"Craft transaction hash: {transactionHash}");

m_CraftState = CraftSkinState.Crafted;

// If successfully crafted skin and this screen is visible, go to collect skin screen
// otherwise it will be picked in the OnEnable function above when this screen reappears
if (m_CraftState == CraftSkinState.Crafted && gameObject.active)
{
CollectSkin();
}
}
Immutable Runner skin unlocked

When the player clicks "Burn three coins to collect at the end of the next level" button in the game, it initiates the zkEVM transaction, which takes some time to complete. To make the waiting period more productive, the game crafts a new skin while the player plays the next level.

If the skin is created successfully, the player can collect it after completing the next level and use it to customise their fox.

Craftunig

View your newly crafted skin by checking the Tokens tab of your wallet address in the block explorer.

You can also find the craft transaction in the Token Transfers tab. It should look like this:

  • Three IMR (Immutable Runner Token) burnt.
  • One IMRS (Immutable Runner Skin) minted.
Block explorer transaction details