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!
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.
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:
const treasuryId = await accountCreator(privateKey, initialBalance);
Note that you can use the accountCreator function to create other accounts if you need to.
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.
//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.
//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:
Done! You are now a proud owner of your custom fungible token created using Hedera SDK.
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
// 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:
npm install -g solc
And then to compile your contract you just run:
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
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.
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}`);
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.
// 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`);
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 Hedera SDK example code on GitHubCheck out the Smart Contract example code on GitHub
Hedera Service Solidity Libraries (Hedera Documentation) Hedera Token Service (Hedera Documentation)What are Smart Contracts? (Hedera Learning Center)