Skip to main content

Craft, burn and transfer assets

Crafting, burning and transferring assets are important gameplay mechanisms.

Not only do they enhance player engagement and satisfaction, they allow you to manage and regulate your game economy.

displaying player inventoriesdisplaying player inventories

📋Prerequisites
  • If you'd like to test the transfer and burn functionality below with your own wallet, it will need to contain NFTs. Learn how to create and deploy assets to your wallet here.
  • Understand the terms "crafting", "burning" and "transferring" of assets in our concepts page.

Setup

Prerequisites

Node version

The Immutable SDK requires Node v18 (Active LTS version) or higher. Node v18 can be installed via nvm which allows to quickly install and use different versions of node via the command line.

The installation steps for nvm for Linux, Mac, and Windows Install & Update Script. You are now ready to install the Node LTS version:

nvm install --lts

Install the Immutable SDK

Run the following command in your project root directory.

npm install -D @imtbl/sdk
Troubleshooting

The Immutable SDK is still in early development. Should complications arise during the installation, please use the following commands to ensure the most recent release of the SDK is correctly installed:

rm -Rf node_modules
npm cache clean --force
npm i

Dependencies

npm install -D typescript ts-node

Transfer or burn assets

You might want to enable the transfer of assets in your application. This can be between users or between the application wallet and users (i.e. distributing newly minted assets to users or receiving assets from users).

An asset transfer simply involves transferring the ownership of an asset from one wallet to another, and must be authorised by the sending wallet. This transaction requires a small amount of gas, which is paid by the transferring wallet.

💡Token transfers can typically only be authorised by their owner
As token actions are defined by the smart contract, it is the token collection owner (deployer of the smart contract) who defines what actions can be taken. For security reasons, the functionality defined by the standard NFT (ERC721) contract stipulates that tokens can only be transferred by its owner. Of course, contracts can be modified so that owners can give permission to other wallets to make transfers on their behalf.

Why "burn" assets?

Games and applications may want to take tokens out of circulation to balance the economy or to decrease the supply of a particular asset for some reason.

The mechanism for doing this is called "burning" and it simply means transferring a token to a null wallet address (0x0000000000000000000000000000000000000000). (This null address is also the address from which a new token is minted - sender or from variable).

1. Create signer from user wallet

💡What is a Signer?

A signer is a representation of a user's wallet (account) that is used to authorise transactions. These transactions typically involve transferring the ownership of assets (currencies or NFTs) from one account to another, hence why the user is required to "sign" these transactions. Applications use signers to obtain user signatures to execute payments, asset transfers, and more. For more information, see the Signers definition from the ethers library.

In order to create a signer, you must first establish a connection to the user's wallet. This is how you connect to different user wallets:

To initialise the passport module, please see the Passport Setup guide.

const passportWallet = passport.connectEvm();

2. Transfer NFT

To transfer an asset, you first create a contract instance then call a transfer method on it.

Creating a contract instance is the initial step to interacting with smart contracts. This establishes a connection between your application and the contract's address on the network which allows you execute contract functions.

The following are two methods of facilitating asset transfers:

  • Immutable SDK - Use the ERC721 class, which simplifies methods like token transfers and minting operations with predefined functions.
  • Ethers.js - Directly interface with the contract's ABI, which provides flexibility and control over method calls.

The following parameters will be required:

ParameterDescription
signerFrom the step above
CONTRACT_ADDRESSThe address of the contract
RECIPIENTAddress of the wallet that will be the new owner of the NFT when the transfer is completed
TOKEN_IDUnique ID of the NFT
import { Signer } from 'ethers'; // ethers v5
import { ERC721Client } from '@imtbl/zkevm-contracts';

const contractInstance = () => {
const CONTRACT_ADDRESS = '';

return new ERC721Client(CONTRACT_ADDRESS);
};

const transfer = async (signer: Signer) => {
const RECIPIENT = '';
const TOKEN_ID = '';

const sender = await signer.getAddress();

const contract = contractInstance();

const populatedTransaction = await contract[
'populateSafeTransferFrom(address,address,uint256)'
](sender, RECIPIENT, TOKEN_ID);
// If burning asset:
// const populatedTransaction = await contract.populateBurn(TOKEN_ID);

const transaction = await signer.sendTransaction(populatedTransaction);

return transaction;
};

3. Transfer Multiple NFTs (Batch Transfers)

The preset ERC721 contract includes functionality for transferring multiple NFTs in one transaction. Batch transfers, like batch minting, are more gas efficient than sending multiple single transfer requests.

The following are two methods of facilitating asset transfers:

  • Immutable SDK - Use the ERC721 class, which simplifies methods like token transfers and minting operations with predefined functions.
  • Ethers.js - Directly interface with the contract's ABI, which provides flexibility and control over method calls.

The following parameters will be required:

ParameterDescription
signerFrom the step above
CONTRACT_ADDRESSThe address of the contract
RECIPIENTAddress of the wallet that will be the new owner of the NFT when the transfer is completed
TOKEN_IDSUnique IDs of the NFTs to transfer
import { Signer } from 'ethers'; // ethers v5
import { ERC721Client } from '@imtbl/zkevm-contracts';

const contractInstance = () => {
const CONTRACT_ADDRESS = '';

return new ERC721Client(CONTRACT_ADDRESS);
};

const batchTransfer = async (signer: Signer) => {
const RECIPIENTS = ['', ''];
const TOKEN_IDS = ['', ''];

const sender = await signer.getAddress();

const contract = contractInstance();

const transfers = {
from: sender,
tos: RECIPIENTS,
tokenIds: TOKEN_IDS,
};

const populatedTransaction = await contract.populateSafeTransferFromBatch(
transfers
);

const transaction = await signer.sendTransaction(populatedTransaction);

return transaction;
};

4. Burn NFTs

The following parameters will be required to burn an asset:

tip

Burning multiple assets in a single transaction, like batch minting, is more gas efficient than sending multiple single burn requests. This powerful feature enables game studios to reduce their operating costs when performing actions like crafting that burn multiple assets at the same time.

ParameterDescription
signerFrom the step above
CONTRACT_ADDRESSThe address of the contract
TOKEN_IDSUnique IDs of the NFTs to burn
import { Signer } from 'ethers'; // ethers v5
import { ERC721Client } from '@imtbl/zkevm-contracts';

const contractInstance = () => {
const CONTRACT_ADDRESS = '';

return new ERC721Client(CONTRACT_ADDRESS);
};

const transfer = async (signer: Signer) => {
const TOKEN_IDS = ['', ''];

const sender = await signer.getAddress();

const contract = contractInstance();

const populatedTransaction = await contract.populateBurnBatch(TOKEN_IDS);

const transaction = await signer.sendTransaction(populatedTransaction);

return transaction;
};

Obtain type safety using the TypeChain library

Constructing the contract interface using the ABI is not type-safe. To make it type-safe, we can use Typechain to generate typescript interfaces from the contract ABI.

The contract ABI could be stored or exported to a file and then used to generate the typescript interfaces.

typechain --target=ethers-v5 -out-dir=app/contracts abis/ERC721.json

Here's how you create a contract instance to use type-safe methods. This function returns a contract factory on which you can call the safeTransferFrom method:

import { Signer } from 'ethers'; // ethers v5
import { ERC721_factory, ERC721 } from './contracts';

const contractInstance = async (signer: Signer) => {
const CONTRACT_ADDRESS = '';

const contract: ERC721 = ERC721_factory.connect(
CONTRACT_ADDRESS,
signer,
);

return contract;

// You can call the `safeTransferFrom` method on this contract:
// contract.safeTransferFrom(sender, RECIPIENT, TOKEN_ID);
};

Craft assets

Crafting assets is a broad term for the process of combining various in-game resources or items to create new and unique items or equipment. The benefits of enabling this in your game includes enriching players' gaming experience, providing additional gameplay mechanisms, and fostering a dynamic and interconnected gaming ecosystem.

At its core, crafting consists of:

  • Receiving existing assets from users
  • Destroying, or locking the use, of the assets
  • Creating new assets with different characteristics (i.e. metadata) to replace the old assets
  • Distributing the new assets to users

An example of how a crafting mechanism could be implemented is through the use of a specialised NFT contract that contains a crafting function. Please note, however, that this is just an example and it is up to you how you would like to implement crafting in your game on the basis of understanding the transfer and burn mechanisms above.