How to Create Hedera Tokens Using SDKs and Smart Contract - Part 2: Non-Fungible Tokens
Screen Shot 2022 01 27 at 9 52 08 PM
Jun 30, 2022
by Francesco Coacci
Developer Evangelist

In Part 1 you learned how to create a fungible token using SDK and a Solidity Smart Contract. Now let’s explore the equivalent but for NFTs. This tutorial is similar to Part 1 but it’s worth practicing a little bit more with token creation especially because of parameter differences between fungible and non-fungible tokens.

Try It Yourself

  • Get a Hedera testnet account
  • Use this Codesandbox to try the Hedera SDK example.
  • Use this Codesandbox to try the Smart Contract example.
    • Fork the sandbox
    • Remember to provide testnet account credentials in the .env file
    • Open a new terminal to execute index.js or deploy.js
  • Get the Hedera SDK example code from Github
  • Get the Smart Contract example code from Github

Create an NFT using Hedera SDK

1. Define Hedera Accounts

As for Part 1, in this example, there is only one Treasury Account. You can use the same function you created in Part 1 to simplify the account creation.

Code Snippet Background
async function accountCreator(pvKey, iBal) {
 
   const response = await new AccountCreateTransaction()
       .setInitialBalance(new Hbar(iBal))
       .setKey(pvKey.publicKey)
       .execute(client);
 
   const receipt = await response.getReceipt(client);
 
   return receipt.accountId;
}

And use it like this:

Code Snippet Background
const treasuryId = await accountCreator(privateKey, initialBalance);

Note that you can use the accountCreator function to create other accounts if you need to.

2. Create your NFT on Hedera

In this example when creating your NFT using the TokenCreateTransaction() function you must specify these parameters:

  • Name

  • Symbol

  • TokenType

  • Decimals (0 for NFTs)

  • Token Memo

  • Initial Supply (0 for NFTs)

  • Treasury Account

  • Supply Type

  • Supply Key

  • Max Supply

  • Auto-renew Account ID

  • Auto-renew period

    Code Snippet Background
    //Create the NFT
    const nftCreate = await new TokenCreateTransaction()
            .setTokenName("Fall Collection")
            .setTokenSymbol("LEAF")
            .setTokenType(TokenType.NonFungibleUnique)
            .setDecimals(0)
            .setTokenMemo("Just a memo")
            .setInitialSupply(0)
            .setTreasuryAccountId(treasuryId)
            .setSupplyType(TokenSupplyType.Finite)
            .setSupplyKey(treasuryKey)
            .setMaxSupply(250)
            .setAutoRenewAccountId(treasuryId)
            .setAutoRenewPeriod(7000000)
            .freezeWith(client);
     
    //Sign the transaction with the treasury key
    const nftCreateTxSign = await nftCreate.sign(treasuryKey);
     
    //Submit the transaction to a Hedera network
    const nftCreateSubmit = await nftCreateTxSign.execute(client);
    

    You just created a non-fungible token with a maximum supply of 250. Make sure you sign the transaction using a treasury Key before execution.

    As you did before, to get your token ID you can just get the transaction receipt.

    Code Snippet Background
    //Get the transaction receipt
    const nftCreateRx = await nftCreateSubmit.getReceipt(client);
    //Get the token ID
    const tokenId = nftCreateRx.tokenId;
    //Log the token ID
    console.log(`Created NFT with ID: ${tokenId} \n`);
    

    Console Output:

    NFT created SDK

    Perfect! You created an NFT! Now, if you want, you can copy and paste your token ID to HashScan to explore a little more what you just created on testnet.

    Create an NFT using Solidity

    1. Write and Compile your Contract

    Now, as you did in Part 1, you need to create your contract. The contract name is TokenCreator.sol, and you must import these files again into your working directory by downloading them from the contracts folder here:

    • IHederaTokenService.sol

    • HederaTokenService.sol

    • HederaResponseCodes.sol

    • ExpiryHelper.sol

    • FeeHelper.sol

    • KeyHelper.sol

      Solidity Contract:

      Code Snippet Background
      // SPDX-License-Identifier: GPL-3.0
      pragma solidity >=0.6.0 <0.9.0;
       
      import './HederaResponseCodes.sol';
      import './IHederaTokenService.sol';
      import './HederaTokenService.sol';
      import './ExpiryHelper.sol';
       
      contract TokenCreator is ExpiryHelper{
       
         function createNonFungible(
                 string memory name,
                 string memory symbol,
                 string memory memo,
                 uint32 maxSupply,
                 uint32 autoRenewPeriod
             ) external payable returns (address){
       
             // Instantiate the list of keys we'll use for token create
              IHederaTokenService.TokenKey[] memory keys = new IHederaTokenService.TokenKey[](1);
              // use the helper methods in KeyHelper to create basic key
              keys[0] = createSingleKey(HederaTokenService.SUPPLY_KEY_TYPE, KeyHelper.CONTRACT_ID_KEY, address(this));
      
              IHederaTokenService.HederaToken memory token;
              token.name = name;
              token.symbol = symbol;
              token.memo = memo;
              token.treasury = address(this);
              token.tokenSupplyType = true; // set supply to FINITE
              token.tokenKeys = keys;
              token.maxSupply = maxSupply;
              token.freezeDefault = false;
              token.expiry = createAutoRenewExpiry(address(this), autoRenewPeriod); // Contract automatically renew by himself
       
             (int responseCode, address createdToken) = HederaTokenService.createNonFungibleToken(token);
       
             if(responseCode != HederaResponseCodes.SUCCESS){
                 revert("Failed to create non-fungible token");
             }
             return createdToken;
         }
       
      }
      

      And then to compile your contract you just run:

      Code Snippet Background
      solcjs --bin TokenCreator.sol -o binaries
      

      This command will create a new directory called /binaries that contains multiple .bin files. The one you are going to use it’s called TokenCreator_sol_TokenCreator.bin.

      You can find the contract bytecode in this Codesandbox. (remember to fork and modify the .env file)

      2. Store your bytecode on the Hedera Network

      You will store your contract on Hedera using the ContractCreateFlow() method. This single call performs FileCreateTransaction(), FileAppendTransaction(), and ContractCreateTransaction() for you.

      Always ensure that the Gas fee you specify as a parameter is enough to execute the transaction, or you'll get an error.

      Code Snippet Background
      const createContract = new ContractCreateFlow()
             .setGas(150000) // Increase if revert
             .setBytecode(bytecode); // Contract bytecode
      const createContractTx = await createContract.execute(client);
      const createContractRx = await createContractTx.getReceipt(client);
      const contractId = createContractRx.contractId;
       
      console.log(`Contract created with ID: ${contractId}`);
      

      Console Output:

      NFT Contract created

      3. Execute a Contract function to create an NFT collection

      Now you can execute your contract function by using ContractExecuteTransaction() to create your NFT collection.

      Make sure every parameter is correct and the number of parameters you pass is the same as the ones in your contract, or you will get a CONTRACT_REVERT_EXECUTED error.

      Code Snippet Background
      // Create NFT using precompile function
      const createToken = new ContractExecuteTransaction()
             .setContractId(contractId)
             .setGas(300000) // Increase if revert
             .setPayableAmount(20) // Increase if revert
             .setFunction("createNonFungible",
                 new ContractFunctionParameters()
                 .addString("Fall Collection") //NFT name
                 .addString("LEAF") // NFT symbol
                 .addString("Just a memo") // NFT memo
                 .addUint32(250) // NFT max supply
                 .addUint32(7000000)); // auto renew period
             
      const createTokenTx = await createToken.execute(client);
       
      const createTokenRx = await createTokenTx.getRecord(client);
      const tokenIdSolidityAddr = createTokenRx.contractFunctionResult.getAddress(0);
      const tokenId = AccountId.fromSolidityAddress(tokenIdSolidityAddr);
       
      console.log(`Token created with ID: ${tokenId} \n`);
      
      

      Console Output:

      NFT created SOL

      Great! Now you know how to create Hedera Tokens using SDKs and Smart Contracts.

      For feedback or further explanation on this article, you can contact us on Hedera Discord Server

      Check out the Code

      Check out the Hedera SDK example code on Github

      Check out the Smart Contract example code on Github

      Continue Learning

      Hedera Service Solidity Libraries (Hedera Documentation)

      Hedera Token Service (Hedera Documentation)

      What are Smart Contracts? (Hedera Learning Center)