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

The Hedera Token Service enables you to create, mint, and transfer a custom fungible/non-fungible token. There are two ways of creating a token on Hedera, one is using the Hedera SDKs, and the other one is using a Solidity Smart Contract.

In this article, you will learn how to create a fungible token using the Hedera SDK and a Solidity Smart Contract. Let's start with the SDK!

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 a Fungible Token using Hedera SDK

1. Define Hedera Accounts

First off, in this example, you will need to create a Treasury account. To create an account, you need to use the AccountCreateTransaction() function. It’s useful to create an accountCreator method to simplify the account creation process like this one below.

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;
}

Now you can create your treasury account 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 Fungible Token on Hedera

Use the TokenCreateTransaction() function to create your token using Hedera SDK. In this example, you will specify these parameters:

  • Name

  • Symbol

  • Treasury Account

  • Initial Supply

  • Decimals

  • Auto-renew Account Id

  • Auto-renew Period

  • Max Transaction Fee

    You have to specify Auto-renew Account ID because you'll need to pay an auto-renewal fee for entities to persist on the Hedera Network. To better understand how auto-renew works you can check out HIP-16 and HIP-372.

    Code Snippet Background
    //Create the transaction and freeze for manual signing
     const transaction = await new TokenCreateTransaction()
         .setTokenName("USD Bar")
         .setTokenSymbol("USDB")
         .setTreasuryAccountId(treasuryId)
         .setInitialSupply(10000)
         .setDecimals(2)
         .setAutoRenewAccountId(treasuryId)
         .setAutoRenewPeriod(7000000)
         .setMaxTransactionFee(new Hbar(30)) //Change the default max transaction fee
         .freezeWith(client);
    
     //Sign the transaction with the token treasury account private key
     const signTx =  await transaction.sign(treasuryKey);
    
     //Sign the transaction with the client operator private key and submit it to a Hedera network
     const txResponse = await signTx.execute(client);
    
    

    Awesome! You just created a fungible token with an initial supply of 100. Before executing the transaction, make sure you sign it using treasuryKey.

    Now you can get your token ID from the transaction receipt.

    Code Snippet Background
    //Get the receipt of the transaction
    const receipt = await txResponse.getReceipt(client);
     
    //Get the token ID from the receipt
    const tokenId = receipt.tokenId;
     
    console.log("The new token ID is " + tokenId);
    

    Console Output:

    FT created SDK

    Done! You are now a proud owner of your custom fungible token created using Hedera SDK.

    Create a Fungible Token using Solidity

    1. Write and Compile your Contract

    Using the SDK is usually easier than using a smart contract to create a token. However, contracts can give you additional flexibility and help you automate certain flows.

    So to start, you have to create a new Solidity contract, in this case, it’s called TokenCreator.sol but you can give it the name you prefer. In the contract, a createFungible function deals with creating your token by calling the HederaTokenService.createFungibleToken() method. As you can see other than that it's all about specifying a bunch of parameters.

    Notice that in this smart contract example, the contract itself will act as a treasury and auto-renew account. This ensures a trustless workflow where the contract is the only entity managing various aspects of the token.

    Since you will use the Hedera Token Service precompile functions, you need to import these files 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{
     
       // create a fungible Token with no custom fees
       function createFungible(
           string memory name,
           string memory symbol,
           uint initialSupply,
           uint decimals,
           uint32 autoRenewPeriod
       ) external payable returns (address createdTokenAddress) {
     
           IHederaTokenService.HederaToken memory token;
           token.name = name;
           token.symbol = symbol;
           token.treasury = address(this);
     
           // create the expiry schedule for the token using ExpiryHelper
           token.expiry = getAutoRenewExpiry(address(this), autoRenewPeriod);
     
           // call HTS precompiled contract, passing initial supply and decimals
           (int responseCode, address tokenAddress) =
                       HederaTokenService.createFungibleToken(token, initialSupply, decimals);
     
           if (responseCode != HederaResponseCodes.SUCCESS) {
               revert ();
           }
     
           createdTokenAddress = tokenAddress;
       }
     
    }
    
    

    As your contract is going to run on the EVM you first need to compile it and get low-level machine code. To do that, you need to install solc using this command:

    Code Snippet Background
    npm install -g solc
    

    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 check out the bytecode that will run on the EVM in this Codesandbox

    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 make sure that the Gas fee you are specifying 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:

    Screen Shot 2022 06 27 at 6 34 27 PM

    3. Execute a Contract function to create a Fungible Token

    Now it’s time to execute your contract function by using ContractExecuteTransaction() to create your fungible token. Make sure every parameter is correct and the number of parameters you are passing is the same as the ones in your contract or you will get a CONTRACT_REVERT_EXECUTED error.

    Code Snippet Background
    // Create FT using precompile function
        const createToken = new ContractExecuteTransaction()
            .setContractId(contractId)
            .setGas(300000) // Increase if revert
            .setPayableAmount(20) // Increase if revert
            .setFunction("createFungible", 
                new ContractFunctionParameters()
                .addString("USD Bar") // FT name
                .addString("USDB") // FT symbol
                .addUint256(1000000000) // FT initial supply
                .addUint256(2) // FT decimals
                .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:

    Screen Shot 2022 06 27 at 6 34 42 PM

    Perfect! So this wraps up Part 1 of How to Create Hedera Tokens. Check out Part 2 to learn how to create an NFT using Hedera SDK and a Solidity Contract.

    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)