> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hedera.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create and Transfer an NFT using a Solidity Contract

## Summary

Besides creating NFTs using Hedera SDK, you can use a Solidity Contract to create, mint, and transfer NFTs by calling contract functions directly. These are the contracts you will need to import into your working directory provided by Hedera that you can find in the **contracts** folder [here](https://github.com/hiero-ledger/hiero-contracts):

* HederaTokenService.sol
* HederaResponseCodes.sol
* IHederaTokenService.sol
* ExpiryHelper.sol
* FeeHelper.sol
* KeyHelper.sol

***

## Prerequisites

We recommend you complete the following introduction to get a basic understanding of Hedera transactions. This example does not build upon the previous examples.

1. Get a [Hedera testnet account](https://portal.hedera.com/register).
2. Set up your environment [here](/native/quickstart/javascript).

If you are interested in creating, minting, and transferring NFTs using Hedera SDKs you can find the example [here](https://docs.hedera.com/guides/getting-started/try-examples/create-and-transfer-your-first-nft).

<Warning>
  In this example, you will set gas for smart contract transactions multiple times. If you don't have enough gas you will receive an`INSUFFICIENT_GAS` response. If you set the value too high you will be refunded a maximum of 20% of the amount that was set for the transaction.
</Warning>

***

## 1. Create an “NFT Creator” Smart Contract

You can find an NFTCreator Solidity contract sample below with the contract bytecode obtained by compiling the solidity contract using [Remix IDE](https://remix.ethereum.org/). If you are not familiar with Solidity, you can take a look at the docs [here](https://docs.soliditylang.org/en/v0.8.14/).

The following contract is composed of three functions:

* `createNft`
* `mintNft`
* `transferNft`

The important thing to know is that the NFT created in this example will have the contract itself as **Treasury Account, Supply Key,** and **Auto-renew account**. There’s **NO** admin key for the NFT or the contract.

<CodeGroup>
  ```solidity NFTCreator.sol theme={null}
  // SPDX-License-Identifier: GPL-3.0
  pragma solidity >=0.5.0 <0.9.0;

  import "./HederaResponseCodes.sol";
  import "./IHederaTokenService.sol";
  import "./HederaTokenService.sol";
  import "./ExpiryHelper.sol";
  import "./KeyHelper.sol";

  contract NFTCreator is ExpiryHelper, KeyHelper, HederaTokenService {

      function createNft(
              string memory name, 
              string memory symbol, 
              string memory memo, 
              int64 maxSupply,  
              int64 autoRenewPeriod
          ) external payable returns (address){

          IHederaTokenService.TokenKey[] memory keys = new IHederaTokenService.TokenKey[](1);
          // Set this contract as supply for the token
          keys[0] = getSingleKey(KeyType.SUPPLY, KeyValueType.CONTRACT_ID, 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.maxSupply = maxSupply;
          token.tokenKeys = keys;
          token.freezeDefault = false;
          token.expiry = createAutoRenewExpiry(address(this), autoRenewPeriod); // Contract auto-renews the token

          (int responseCode, address createdToken) = HederaTokenService.createNonFungibleToken(token);

          if(responseCode != HederaResponseCodes.SUCCESS){
              revert("Failed to create non-fungible token");
          }
          return createdToken;
      }

      function mintNft(
          address token,
          bytes[] memory metadata
      ) external returns(int64){

          (int response, , int64[] memory serial) = HederaTokenService.mintToken(token, 0, metadata);

          if(response != HederaResponseCodes.SUCCESS){
              revert("Failed to mint non-fungible token");
          }

          return serial[0];
      }

      function transferNft(
          address token,
          address receiver, 
          int64 serial
      ) external returns(int){

          int response = HederaTokenService.transferNFT(token, address(this), receiver, serial);

          if(response != HederaResponseCodes.SUCCESS){
              revert("Failed to transfer non-fungible token");
          }

          return response;
      }

  }
  ```
</CodeGroup>

Store your contract on Hedera using `ContractCreateFlow()`. This single call performs `FileCreateTransaction()`,`FileAppendTransaction()`, and `ContractCreateTransaction()` for you. See the difference [here](https://docs.hedera.com/guides/docs/sdks/smart-contracts/create-a-smart-contract).

<CodeGroup>
  ```java Java theme={null}
  // Create contract
  ContractCreateFlow createContract = new ContractCreateFlow()
     .setBytecode(bytecode) // Contract bytecode
     .setGas(4_000_000); // Increase if revert

  TransactionResponse createContractTx = createContract.execute(client);
  TransactionReceipt createContractRx = createContractTx.getReceipt(client);
  // Get the new contract ID
  ContractId newContractId = createContractRx.contractId;
                  
  System.out.println("Contract created with ID: " + newContractId);
  ```

  ```javascript JavaScript theme={null}
  // Create contract
  const createContract = new ContractCreateFlow()
      .setGas(4000000) // 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} \n`);
  ```

  ```go Go theme={null}
  //Create the transaction
  createContract := hedera.NewContractCreateFlow().
  	SetGas(4000000).
  	SetBytecode([]byte(bytecode))

  //Sign the transaction with the client operator key and submit to a Hedera network
  txResponse, err := createContract.Execute(client)
  if err != nil {
  	panic(err)
  }

  //Request the receipt of the transaction
  receipt, err := txResponse.GetReceipt(client)
  if err != nil {
  	panic(err)
  }

  //Get the contract ID
  newContractId := *receipt.ContractID

  fmt.Printf("The new contract ID is %v\n", newContractId)
  ```
</CodeGroup>

## 3. Execute the Contract to Create an NFT

The parameters you need to specify for this contract call are Name, Symbol, Memo, Maximum Supply, and Expiration. The smart contract "rent" feature is currently *NOT* enabled. Once enabled in the future, setting an expiration date *in seconds* is required because entities on Hedera will need to pay "rent" to persist. In this case, the contract entity will pay all NFT auto-renewal fees.

<Warning>
  **Note:** The expiration must be between 82 and 91 days, **specified in seconds**. This window will change when [HIP-372](https://hips.hedera.com/hip/hip-372) replaces [HIP-16](https://hips.hedera.com/hip/hip-16).
</Warning>

<CodeGroup>
  ```java Java theme={null}
  // Create NFT using contract
  ContractExecuteTransaction createToken = new ContractExecuteTransaction()
  		.setContractId(newContractId) // Contract id
  		.setGas(4_000_000) // Increase if revert
  		.setPayableAmount(new Hbar(50)) // Increase if revert
  		.setFunction("createNft", new ContractFunctionParameters()
          .addString("Fall Collection") // NFT Name
          .addString("LEAF") // NFT Symbol
          .addString("Just a memo") // NFT Memo
          .addInt64(250) // NFT max supply
          .addInt64(7_000_000)); // Expiration: Needs to be between 6999999 and 8000001

  TransactionResponse createTokenTx = createToken.execute(client);
  TransactionRecord createTokenRx = createTokenTx.getRecord(client);

  String tokenIdSolidityAddr = createTokenRx.contractFunctionResult.getAddress(0);
  AccountId tokenId = AccountId.fromSolidityAddress(tokenIdSolidityAddr);

  System.out.println("Token created with ID: " + tokenId);
  ```

  ```javascript JavaScript theme={null}
  // Create NFT from precompile
  const createToken = new ContractExecuteTransaction()
      .setContractId(contractId)
      .setGas(4000000) // Increase if revert
      .setPayableAmount(50) // Increase if revert
      .setFunction("createNft",
          new ContractFunctionParameters()
          .addString("Fall Collection") // NFT name
          .addString("LEAF") // NFT symbol
          .addString("Just a memo") // NFT memo
          .addInt64(250) // NFT max supply
          .addInt64(7000000) // Expiration: Needs to be between 6999999 and 8000001
          );
  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`);
  ```

  ```go Go theme={null}
  contractParams := hedera.NewContractFunctionParameters().
  	AddString("Fall Collection"). // NFT name
  	AddString("LEAF").            // NFT symbol
  	AddString("Just a memo").     // NFT memo
  	AddInt64(250).               // NFT max supply
  	AddInt64(7000000)            // Expiration: Needs to be between 6999999 and 8000001
  //Create NFT
  createToken, err := hedera.NewContractExecuteTransaction().
  	//The contract ID
  	SetContractID(newContractId).
  	//The max gas
  	SetGas(4000000).
  	SetPayableAmount(hedera.NewHbar(50)).
  	//The contract function to call and parameters
  	SetFunction("createNft", contractParams).
  	Execute(client)

  if err != nil {
  	panic(err)
  }

  //Get the record
  txRecord, err := createToken.GetRecord(client)
  if err != nil {
  	panic(err)
  }

  //Get transaction status
  contractResult, err := txRecord.GetContractExecuteResult()
  if err != nil {
  	panic(err)
  }
  tokenIdSolidityAddr := hex.EncodeToString(contractResult.GetAddress(0))

  tokenId, err := hedera.AccountIDFromSolidityAddress(tokenIdSolidityAddr)
  if err != nil {
  	panic(err)
  }

  fmt.Printf("Token created with ID: %v\n", tokenId)
  ```
</CodeGroup>

## 4. Execute the Contract to Mint a New NFT

After the token ID is created, you mint each NFT under that ID using the `mintNft` function. For the minting, you must specify the token ID as a Solidity address and the NFT metadata.

Both the NFT image and metadata live in the InterPlanetary File System (IPFS), which provides decentralized storage. The file metadata.json contains the metadata for the NFT. An IPFS URI pointing to the metadata file is used during minting of a new NFT. Notice that the metadata file contains a URI pointing to the NFT image.

<Info>
  ***Note:** For the latest NFT Token Metadata JSON Schema see* [*HIP-412*](https://hips.hedera.com/hip/hip-412)*.*
</Info>

<CodeGroup>
  ```java Java theme={null}
  // Mint NFT
  ContractExecuteTransaction mintToken = new ContractExecuteTransaction()
  		.setContractId(newContractId)
  		.setGas(4_000_000)
                  .setMaxTransactionFee(new Hbar(20)) //Use when HBAR is <10 cents
  		.setFunction("mintNft", new ContractFunctionParameters()
  		.addAddress(tokenIdSolidityAddr) // Token address
  		.addBytesArray(byteArray)); // Metadata

  TransactionResponse mintTokenTx = mintToken.execute(client);
  TransactionRecord mintTokenRx = mintTokenTx.getRecord(client);
  // NFT serial number
  long serial = mintTokenRx.contractFunctionResult.getInt64(0);

  System.out.println("Minted NFT with serial: " + serial);
  ```

  ```javascript JavaScript theme={null}
  // IPFS URI
  metadata = "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json";
   
  // Mint NFT
  const mintToken = new ContractExecuteTransaction()
      .setContractId(contractId)
      .setGas(4000000)
      .setMaxTransactionFee(new hbar(20)) //Use when HBAR is under 10 cents
      .setFunction("mintNft",
          new ContractFunctionParameters()
          .addAddress(tokenIdSolidityAddr) // Token address
          .addBytesArray([Buffer.from(metadata)]) // Metadata
          );
          
  const mintTokenTx = await mintToken.execute(client);
  const mintTokenRx = await mintTokenTx.getRecord(client);
  const serial = mintTokenRx.contractFunctionResult.getInt64(0);

  console.log(`Minted NFT with serial: ${serial} \n`);
  ```

  ```go Go theme={null}
  // ipfs URI
  metadata := "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json"
  bytesArray := [][]byte{}
  bytesArray = append(bytesArray, []byte(metadata))

  // Add token address to params
  mintParams, err := hedera.NewContractFunctionParameters().
  	AddAddress(tokenIdSolidityAddr)

  if err != nil {
  	panic(err)
  }

  // Add metadata to params
  mintParams = mintParams.AddBytesArray(bytesArray)

  // Mint NFT
  mintToken, err := hedera.NewContractExecuteTransaction().
  	//The contract ID
  	SetContractID(newContractId).
  	//The max gas
  	SetGas(4000000).
  	//The contract function to call and parameters
  	SetFunction("mintNft", mintParams).
  	//The max transaction fee. Use when HBAR is under 10 cents
  	SetMaxTransactionFee(hedera.HbarFrom(20, hedera.HbarUnits.Hbar)).
  	Execute(client)

  if err != nil {
  	panic(err)
  }

  //Get the record
  mintRecord, err := mintToken.GetRecord(client)
  if err != nil {
  	panic(err)
  }

  //Get transaction status
  mintResult, err := mintRecord.GetContractExecuteResult()
  if err != nil {
  	panic(err)
  }
  serial := mintResult.GetInt64(0)

  fmt.Printf("Minted NFT with serial: %v\n", serial)
  ```
</CodeGroup>

<CodeGroup>
  ```json metadata.json theme={null}
  {
      "name": "LEAF1.jpg",
      "creator": "Mother Nature",
      "description": "Autumn",
      "type": "image/jpg",
      "format": "none",
      "properties": {
          "city": "Boston",
          "season": "Fall",
          "decade": "20's"
      },
      "image": "ipfs://bafybeig35bheyqpi4qlnuljpok54ud753bnp62fe6jit343hv3oxhgnbfm/LEAF1.jpg"
  }
  ```
</CodeGroup>

***

## 5. Execute the Contract to Transfer the NFT

The NFT is minted to the contract address because the contract is the treasury for the token. Now transfer the NFT to another account or contract address. In this example, you will transfer the NFT to Alice. For the transfer, you must specify the token address and NFT serial number.

The `transferNft` function in the Solidity contract contains a call to an `associateToken` function that will automatically associate Alice to the token ID. This association transaction must be signed using Alice's private key. After signing, Alice will receive the NFT.

<Info>
  **Note:** For a more comprehensive explanation of how auto token association works, check out the *Auto Token Associations* section [here](/learn/core-concepts/accounts/account-properties#automatic-token-associations). Reference Hedera Improvement Proposal: [HIP-23](https://hips.hedera.com/hip/hip-23)
</Info>

<CodeGroup>
  ```java Java theme={null}
  // Transfer NFT to Alice
  ContractExecuteTransaction transferToken = new ContractExecuteTransaction()
  		.setContractId(newContractId)
  		.setGas(4_000_000)
  		.setFunction("transferNft", new ContractFunctionParameters()
          .addAddress(tokenIdSolidityAddr) // Token id
          .addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
          .addInt64(serial)) // Serial number
  		.freezeWith(client) // Freeze transaction using client
  		.sign(aliceKey); //Sign using Alice Private Key

  TransactionResponse transferTokenTx = transferToken.execute(client);
  TransactionReceipt transferTokenRx = transferTokenTx.getReceipt(client);

  System.out.println("Transfer status: " + transferTokenRx.status);
  ```

  ```javascript JavaScript theme={null}
  // Transfer NFT to Alice
  const transferToken = await new ContractExecuteTransaction()
      .setContractId(contractId)
      .setGas(4000000)
      .setFunction("transferNft",
          new ContractFunctionParameters()
          .addAddress(tokenIdSolidityAddr) // Token address
          .addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
          .addInt64(serial)) // NFT serial number
      .freezeWith(client) // freezing using client
      .sign(aliceKey); // Sign transaction with Alice
      
  const transferTokenTx = await transferToken.execute(client);
  const transferTokenRx = await transferTokenTx.getReceipt(client);

  console.log(`Transfer status: ${transferTokenRx.status} \n`);
  ```

  ```go Go theme={null}
  // Add token address to params
  transferParams, err := hedera.NewContractFunctionParameters().
  	AddAddress(tokenIdSolidityAddr)
  // Add Alice address to params
  transferParams, err = transferParams.AddAddress(aliceAccountId.ToSolidityAddress())
  if err != nil {
  	panic(err)
  }
  transferParams = transferParams.AddInt64(serial)

  // Transfer NFT
  transferToken, err := hedera.NewContractExecuteTransaction().
  	//The contract ID
  	SetContractID(newContractId).
  	//The max gas
  	SetGas(4000000).
  	//The contract function to call and parameters
  	SetFunction("transferNft", transferParams).
  	FreezeWith(client)

  if err != nil {
  	panic(err)
  }

  transferSubmit, err := transferToken.Sign(aliceKey).Execute(client)
  if err != nil {
  	panic(err)
  }

  //Get the record
  transferRecord, err := transferSubmit.GetReceipt(client)
  if err != nil {
  	panic(err)
  }

  fmt.Printf("Transfer status: %v\n", transferRecord.Status)
  ```
</CodeGroup>

***

## Code Check ✅

<Accordion title="Java">
  ```java theme={null}
  package _nft_hscs_hts.hedera;

  import java.io.IOException;
  import java.nio.file.Files;
  import java.nio.file.Paths;
  import java.util.Objects;
  import java.util.concurrent.TimeoutException;

  import com.hedera.hashgraph.sdk.*;
  import io.github.cdimascio.dotenv.Dotenv;

  public class Deploy {
      private static AccountId accountCreator(PrivateKey pvKey, int iBal, Client client)
              throws TimeoutException, PrecheckStatusException, ReceiptStatusException {
          AccountCreateTransaction transaction = new AccountCreateTransaction()
                  .setKey(pvKey.getPublicKey())
                  .setMaxAutomaticTokenAssociations(10)
                  .setInitialBalance(new Hbar(iBal));

          TransactionResponse txResponse = transaction.execute(client);

          TransactionReceipt receipt = txResponse.getReceipt(client);

          return receipt.accountId;

      }

      public static void main(String[] args)
              throws TimeoutException, PrecheckStatusException, ReceiptStatusException, IOException {
          // ipfs URI
          String metadata = ("ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json");
          byte[][] byteArray = new byte[1][metadata.length()];
          byteArray[0] = metadata.getBytes();

          AccountId operatorId = AccountId.fromString(Objects.requireNonNull(Dotenv.load().get("ACCOUNT_ID")));
          PrivateKey operatorKey = PrivateKey.fromString(Objects.requireNonNull(Dotenv.load().get("PRIVATE_KEY")));

          Client client = Client.forTestnet();
          client.setOperator(operatorId, operatorKey);

          PrivateKey aliceKey = PrivateKey.generateECDSA();
          AccountId aliceId = accountCreator(aliceKey, 100, client);
          System.out.print(aliceId);

          String bytecode = Files.readString(Paths.get("./NFTCreator_sol_NFTCreator.bin"));

          // Create contract
          ContractCreateFlow createContract = new ContractCreateFlow()
                  .setBytecode(bytecode) // Contract bytecode
                  .setGas(4_000_000); // Increase if revert

          TransactionResponse createContractTx = createContract.execute(client);
          TransactionReceipt createContractRx = createContractTx.getReceipt(client);
          // Get the new contract ID
          ContractId newContractId = createContractRx.contractId;

          System.out.println("Contract created with ID: " + newContractId);

          // Create NFT using contract
          ContractExecuteTransaction createToken = new ContractExecuteTransaction()
                  .setContractId(newContractId) // Contract id
                  .setGas(4_000_000) // Increase if revert
                  .setPayableAmount(new Hbar(50)) // Increase if revert
                  .setFunction("createNft", new ContractFunctionParameters()
                          .addString("Fall Collection") // NFT Name
                          .addString("LEAF") // NFT Symbol
                          .addString("Just a memo") // NFT Memo
                          .addInt64(250) // NFT max supply
                          .addInt64(7_000_000)); // Expiration: Needs to be between 6999999 and 8000001

          TransactionResponse createTokenTx = createToken.execute(client);
          TransactionRecord createTokenRx = createTokenTx.getRecord(client);

          String tokenIdSolidityAddr = createTokenRx.contractFunctionResult.getAddress(0);
          AccountId tokenId = AccountId.fromSolidityAddress(tokenIdSolidityAddr);

          System.out.println("Token created with ID: " + tokenId);

          // Mint NFT
          ContractExecuteTransaction mintToken = new ContractExecuteTransaction()
                  .setContractId(newContractId)
                  .setGas(4_000_000)
                  .setMaxTransactionFee(new Hbar(20)) // Use when HBAR is <10 cents
                  .setFunction("mintNft", new ContractFunctionParameters()
                          .addAddress(tokenIdSolidityAddr) // Token address
                          .addBytesArray(byteArray)); // Metadata

          TransactionResponse mintTokenTx = mintToken.execute(client);
          TransactionRecord mintTokenRx = mintTokenTx.getRecord(client);
          // NFT serial number
          long serial = mintTokenRx.contractFunctionResult.getInt64(0);

          System.out.println("Minted NFT with serial: " + serial);

          // Transfer NFT to Alice
          ContractExecuteTransaction transferToken = new ContractExecuteTransaction()
                  .setContractId(newContractId)
                  .setGas(4_000_000)
                  .setFunction("transferNft", new ContractFunctionParameters()
                          .addAddress(tokenIdSolidityAddr) // Token id
                          .addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
                          .addInt64(serial)) // Serial number
                  .freezeWith(client) // Freeze transaction using client
                  .sign(aliceKey); // Sign using Alice Private Key

          TransactionResponse transferTokenTx = transferToken.execute(client);
          TransactionReceipt transferTokenRx = transferTokenTx.getReceipt(client);

          System.out.println("Transfer status: " + transferTokenRx.status);

      }
  }
  ```
</Accordion>

<Accordion title="JavaScript">
  ```javascript theme={null}
  console.clear();
  require("dotenv").config();
  const fs = require("fs");
  const {
    AccountId,
    PrivateKey,
    Client,
    ContractCreateFlow,
    ContractExecuteTransaction,
    ContractFunctionParameters,
    AccountCreateTransaction,
    Hbar,
  } = require("@hashgraph/sdk");

  // ipfs URI
  metadata =
    "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json";

  const operatorKey = PrivateKey.fromString(process.env.OPERATOR_KEY);
  const operatorId = AccountId.fromString(process.env.OPERATOR_ID);

  const client = Client.forTestnet().setOperator(operatorId, operatorKey);

  // Account creation function
  async function accountCreator(pvKey, iBal) {
    const response = await new AccountCreateTransaction()
      .setInitialBalance(new Hbar(iBal))
      .setKey(pvKey.publicKey)
      .setMaxAutomaticTokenAssociations(10)
      .execute(client);
    const receipt = await response.getReceipt(client);
    return receipt.accountId;
  }

  const main = async () => {
    // Init Alice account
    const aliceKey = PrivateKey.generateECDSA();
    const aliceId = await accountCreator(aliceKey, 100);

    const bytecode = fs.readFileSync("./binaries/NFTCreator_sol_NFTCreator.bin");

    // Create contract
    const createContract = new ContractCreateFlow()
      .setGas(4000000) // 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} \n`);

    // Create NFT from precompile
    const createToken = new ContractExecuteTransaction()
      .setContractId(contractId)
      .setGas(4000000) // Increase if revert
      .setPayableAmount(50) // Increase if revert
      .setFunction(
        "createNft",
        new ContractFunctionParameters()
          .addString("Fall Collection") // NFT name
          .addString("LEAF") // NFT symbol
          .addString("Just a memo") // NFT memo
          .addInt64(250) // NFT max supply
          .addInt64(7000000) // Expiration: Needs to be between 6999999 and 8000001
      );
    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`);

    // Mint NFT
    const mintToken = new ContractExecuteTransaction()
      .setContractId(contractId)
      .setGas(4000000)
      .setMaxTransactionFee(new Hbar(20)) //Use when HBAR is under 10 cents
      .setFunction(
        "mintNft",
        new ContractFunctionParameters()
          .addAddress(tokenIdSolidityAddr) // Token address
          .addBytesArray([Buffer.from(metadata)]) // Metadata
      );
    const mintTokenTx = await mintToken.execute(client);
    const mintTokenRx = await mintTokenTx.getRecord(client);
    const serial = mintTokenRx.contractFunctionResult.getInt64(0);

    console.log(`Minted NFT with serial: ${serial} \n`);

    // Transfer NFT to Alice
    const transferToken = await new ContractExecuteTransaction()
      .setContractId(contractId)
      .setGas(4000000)
      .setFunction(
        "transferNft",
        new ContractFunctionParameters()
          .addAddress(tokenIdSolidityAddr) // Token address
          .addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
          .addInt64(serial)
      ) // NFT serial number
      .freezeWith(client) // freezing using client
      .sign(aliceKey); // Sign transaction with Alice
    const transferTokenTx = await transferToken.execute(client);
    const transferTokenRx = await transferTokenTx.getReceipt(client);

    console.log(`Transfer status: ${transferTokenRx.status} \n`);
  };

  main();
  ```
</Accordion>

<Accordion title="Go">
  ```go theme={null}
  package main

  import (
  	"encoding/hex"
  	"fmt"
  	"io/ioutil"
  	"os"

  	hedera "github.com/hiero-ledger/hiero-sdk-go/v2/sdk"
  	"github.com/joho/godotenv"
  )

  func main() {
  	godotenv.Load("../.env")

  	metadata := "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json"
  	bytesArray := [][]byte{}
  	bytesArray = append(bytesArray, []byte(metadata))

  	err := godotenv.Load(".env")
  	if err != nil {
  		panic(fmt.Errorf("Unable to load environment variables from .env file. Error:n%v\n", err))
  	}

  	//Grab your testnet account ID and private key from the .env file
  	operatorId, err := hedera.AccountIDFromString(os.Getenv("ACCOUNT_ID"))
  	if err != nil {
  		panic(err)
  	}

  	operatorKey, err := hedera.PrivateKeyFromString(os.Getenv("PRIVATE_KEY"))
  	if err != nil {
  		panic(err)
  	}

  	//Create your testnet client
  	client := hedera.ClientForTestnet()
  	client.SetOperator(operatorId, operatorKey)

  	aliceKey, err := hedera.PrivateKeyGenerateEcdsa()
  	if err != nil {
  		panic(err)
  	}

  	//Create the transaction
  	accountCreate := hedera.NewAccountCreateTransaction().
  		SetKey(aliceKey.PublicKey()).
  		//Do NOT set an alias if you need to update/rotate keys in the future
  		SetMaxAutomaticTokenAssociations(10).
  		SetInitialBalance(hedera.NewHbar(100))

  	//Sign the transaction with the client operator private key and submit to a Hedera network
  	accountCreateSubmit, err := accountCreate.Execute(client)
  	if err != nil {
  		panic(err)
  	}

  	//Request the receipt of the transaction
  	accountCreateReceipt, err := accountCreateSubmit.GetReceipt(client)
  	if err != nil {
  		panic(err)
  	}

  	//Get the account ID
  	aliceAccountId := *accountCreateReceipt.AccountID

  	// Make sure to close client after running
  	defer func() {
  		err = client.Close()
  		if err != nil {
  			println(err.Error(), ": error closing client")
  			return
  		}
  	}()

  	// Read bytecode
  	bytecode, err := ioutil.ReadFile("./NFTCreator_sol_NFTCreator.bin")
  	if err != nil {
  		println(err.Error(), ": error reading bytecode")
  		return
  	}

  	//Create the transaction
  	createContract := hedera.NewContractCreateFlow().
  		SetGas(4000000).
  		SetBytecode([]byte(bytecode))

  	//Sign the transaction with the client operator key and submit to a Hedera network
  	txResponse, err := createContract.Execute(client)
  	if err != nil {
  		panic(err)
  	}

  	//Request the receipt of the transaction
  	receipt, err := txResponse.GetReceipt(client)
  	if err != nil {
  		panic(err)
  	}

  	//Get the contract ID
  	newContractId := *receipt.ContractID

  	fmt.Printf("The new contract ID is %v\n", newContractId)

  	contractParams := hedera.NewContractFunctionParameters().
  		AddString("Fall Collection"). // NFT name
  		AddString("LEAF").            // NFT symbol
  		AddString("Just a memo").     // NFT memo
  		AddInt64(250).                // NFT max supply
  		AddInt64(7000000)             // Expiration: Needs to be between 6999999 and 8000001
  	//Create NFT
  	createToken, err := hedera.NewContractExecuteTransaction().
  		//The contract ID
  		SetContractID(newContractId).
  		//The max gas
  		SetGas(4000000).
  		SetPayableAmount(hedera.NewHbar(50)).
  		//The contract function to call and parameters
  		SetFunction("createNft", contractParams).
  		Execute(client)

  	if err != nil {
  		panic(err)
  	}

  	//Get the record
  	txRecord, err := createToken.GetRecord(client)
  	if err != nil {
  		panic(err)
  	}

  	//Get transaction status
  	contractResult, err := txRecord.GetContractExecuteResult()
  	if err != nil {
  		panic(err)
  	}
  	tokenIdSolidityAddr := hex.EncodeToString(contractResult.GetAddress(0))

  	tokenId, err := hedera.AccountIDFromSolidityAddress(tokenIdSolidityAddr)
  	if err != nil {
  		panic(err)
  	}

  	fmt.Printf("Token created with ID: %v\n", tokenId)

  	// Add token address to params
  	mintParams, err := hedera.NewContractFunctionParameters().
  		AddAddress(tokenIdSolidityAddr)

  	if err != nil {
  		panic(err)
  	}

  	// Add metadata to params
  	mintParams = mintParams.AddBytesArray(bytesArray)

  	// Mint NFT
  	mintToken, err := hedera.NewContractExecuteTransaction().
  		//The contract ID
  		SetContractID(newContractId).
  		//The max gas
  		SetGas(1000000).
  		//The contract function to call and parameters
  		SetFunction("mintNft", mintParams).
  		//The max transaction fee. Use when HBAR is under 10 cents
  		SetMaxTransactionFee(hedera.HbarFrom(20, hedera.HbarUnits.Hbar)).
  		Execute(client)

  	if err != nil {
  		panic(err)
  	}

  	//Get the record
  	mintRecord, err := mintToken.GetRecord(client)
  	if err != nil {
  		panic(err)
  	}

  	//Get transaction status
  	mintResult, err := mintRecord.GetContractExecuteResult()
  	if err != nil {
  		panic(err)
  	}
  	serial := mintResult.GetInt64(0)

  	fmt.Printf("Minted NFT with serial: %v\n", serial)

  	// Add token address to params
  	transferParams, err := hedera.NewContractFunctionParameters().
  		AddAddress(tokenIdSolidityAddr)
  	// Add Alice address to params
  	transferParams, err = transferParams.AddAddress(aliceAccountId.ToSolidityAddress())
  	if err != nil {
  		panic(err)
  	}
  	transferParams = transferParams.AddInt64(serial)

  	// Transfer NFT
  	transferToken, err := hedera.NewContractExecuteTransaction().
  		//The contract ID
  		SetContractID(newContractId).
  		//The max gas
  		SetGas(4000000).
  		//The contract function to call and parameters
  		SetFunction("transferNft", transferParams).
  		FreezeWith(client)

  	if err != nil {
  		panic(err)
  	}

  	transferSubmit, err := transferToken.Sign(aliceKey).Execute(client)
  	if err != nil {
  		panic(err)
  	}

  	//Get the record
  	transferRecord, err := transferSubmit.GetReceipt(client)
  	if err != nil {
  		panic(err)
  	}

  	fmt.Printf("Transfer status: %v\n", transferRecord.Status)
  }
  ```
</Accordion>
