In this tutorial, we'll guide you through the process of working with Hedera Token Service (HTS) for fungible tokens using JavaScript scripts. These scripts cover essential operations such as creating a token, transferring tokens, increasing token supply, querying balance, updating token properties, deleting a token, and burning tokens.
Prerequisites
Before you start, make sure you have the following:
Create a file named createToken.js and add the script for token creation.
Step 3: Write Token Transfer Script
Create a file named transferToken.js and add the script for token transfer.
Step 4: Write Token Increase Supply Script
Create a file named increaseSupply.js and add the script for increasing token supply.
Step 5: Write Query Balance Script
Create a file named queryBalance.js and add the script for querying token balance.
Step 6: Write Token Update Script
Create a file named updateToken.js and add the script for updating token properties.
Step 7: Write Token Deletion Script
Create a file named deleteToken.js and add the script for deleting a token.
Step 8: Write Token Burning Script
Create a file named burnToken.js and add the script for burning tokens.
Step 9: Run the Scripts
Execute each script in the order of token creation, transfer, increase supply, query balance, update, delete, and burn. Ensure that you are following the proper sequence.
Conclusion
Congratulations! You have successfully executed scripts for various Hedera Token Service operations for Fungible Tokens. This tutorial covers fundamental steps, and you can further explore advanced features and integrations based on your specific use case.
const {
TokenCreateTransaction,
Client,
TokenType,
TokenInfoQuery,
AccountBalanceQuery, PrivateKey, Wallet
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });
const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);
if (myAccountId == null ||
myPrivateKey == null ) {
throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}
const otherAccountId = process.env.OTHER_ACCOUNT_ID;
const otherPrivateKey = PrivateKey.fromString(process.env.OTHER_PRIVATE_KEY);
if (otherAccountId == null ||
otherPrivateKey == null ) {
throw new Error("Environment variables otherAccountId and otherPrivateKey must be present");
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
client.setOperator(myAccountId, myPrivateKey);
const adminUser = new Wallet(
myAccountId,
myPrivateKey
)
const supplyUser = new Wallet(
otherAccountId,
otherPrivateKey
)
async function main() {
//Create the transaction and freeze for manual signing
const transaction = await new TokenCreateTransaction()
.setTokenName("Awesome Game Token")
.setTokenSymbol("AGT")
.setTokenType(TokenType.FungibleCommon)
.setTreasuryAccountId(myAccountId)
.setInitialSupply(2000)
.setAdminKey(adminUser.publicKey)
.setSupplyKey(supplyUser.publicKey)
.freezeWith(client);
//Sign the transaction with the client, who is set as admin and treasury account
const signTx = await transaction.sign(myPrivateKey);
//Submit to a Hedera network
const txResponse = await signTx.execute(client);
//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);
//Sign with the client operator private key, submit the query to the network and get the token supply
const name = await queryTokenFunction("name", tokenId);
const symbol = await queryTokenFunction("symbol", tokenId);
const tokenSupply = await queryTokenFunction("totalSupply", tokenId);
console.log('The total supply of the ' + name + ' token is ' + tokenSupply + ' of ' + symbol);
//Create the query
const balanceQuery = new AccountBalanceQuery()
.setAccountId(adminUser.accountId);
//Sign with the client operator private key and submit to a Hedera network
const tokenBalance = await balanceQuery.execute(client);
console.log("The balance of the user is: " + tokenBalance.tokens.get(tokenId));
process.exit();
}
async function queryTokenFunction(functionName, tokenId) {
//Create the query
const query = new TokenInfoQuery()
.setTokenId(tokenId);
console.log("retrieveing the " + functionName);
const body = await query.execute(client);
//Sign with the client operator private key, submit the query to the network and get the token supply
let result;
if (functionName === "name") {
result = body.name;
} else if(functionName ==="symbol") {
result = body.symbol;
} else if(functionName === "totalSupply") {
result = body.totalSupply;
} else {
return;
}
return result
}
main();
const {
TransferTransaction,
Client,
TokenAssociateTransaction,
Wallet,
PrivateKey
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });
const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);
const otherAccountId = process.env.OTHER_ACCOUNT_ID;
const otherPrivateKey = PrivateKey.fromString(process.env.OTHER_PRIVATE_KEY);
const tokenId = process.env.TOKEN_ID;
// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
myPrivateKey == null ) {
throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
client.setOperator(myAccountId, myPrivateKey);
const wallet = new Wallet(
otherAccountId,
otherPrivateKey
);
async function main() {
// Before an account that is not the treasury for a token can receive or send this specific token ID, the account
// must become “associated” with the token.
let associateOtherWalletTx = await new TokenAssociateTransaction()
.setAccountId(wallet.accountId)
.setTokenIds([tokenId])
.freezeWith(client)
.sign(otherPrivateKey)
//SUBMIT THE TRANSACTION
let associateOtherWalletTxSubmit = await associateOtherWalletTx.execute(client);
//GET THE RECEIPT OF THE TRANSACTION
let associateOtherWalletRx = await associateOtherWalletTxSubmit.getReceipt(client);
//LOG THE TRANSACTION STATUS
console.log(`- Token association with the users account: ${associateOtherWalletRx.status} \n`);
//Create the transfer transaction
const transaction = await new TransferTransaction()
.addTokenTransfer(tokenId, client.operatorAccountId, -3)
.addTokenTransfer(tokenId, wallet.accountId, 3)
.freezeWith(client);
//Sign with the sender account private key
const signTx = await transaction.sign(myPrivateKey);
//Sign with the client operator private key and submit to a Hedera network
const txResponse = await signTx.execute(client);
//Request the receipt of the transaction
const receipt = await txResponse.getReceipt(client);
//Obtain the transaction consensus status
const transactionStatus = receipt.status;
console.log("The transaction consensus status " +transactionStatus.toString());
process.exit();
}
main();
const {
TokenMintTransaction,
Client,
TokenInfoQuery, PrivateKey
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });
const otherAccountId = process.env.OTHER_ACCOUNT_ID;
const otherPrivateKey = PrivateKey.fromString(process.env.OTHER_PRIVATE_KEY);
const tokenId = process.env.TOKEN_ID;
// If we weren't able to grab it, we should throw a new error
if (otherAccountId == null ||
otherPrivateKey == null ) {
throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
client.setOperator(otherAccountId, otherPrivateKey);
async function main() {
//Create the transaction and freeze for manual signing
const transaction = await new TokenMintTransaction()
.setTokenId(tokenId)
.setAmount(3000)
.freezeWith(client);
//Sign the transaction with the client, who is set as admin and treasury account
const signTx = await transaction.sign(otherPrivateKey);
//Submit the signed transaction to a Hedera network
const txResponse = await signTx.execute(client);
//Request the receipt of the transaction
const receipt = await txResponse.getReceipt(client);
//Get the transaction consensus status
const transactionStatus = receipt.status.toString();
console.log("The transaction consensus status is " +transactionStatus);
//Create the query
const query = new TokenInfoQuery()
.setTokenId(tokenId);
//Sign with the client operator private key, submit the query to the network and get the token supply
const name = await queryTokenFunction("name", tokenId);
const symbol = await queryTokenFunction("symbol", tokenId);
const tokenSupply = await queryTokenFunction("totalSupply", tokenId);
console.log('The total supply of the ' + name + ' token is ' + tokenSupply + ' of ' + symbol);
process.exit();
}
async function queryTokenFunction(functionName, tokenId) {
//Create the query
const query = new TokenInfoQuery()
.setTokenId(tokenId);
console.log(functionName);
const body = await query.execute(client);
//Sign with the client operator private key, submit the query to the network and get the token supply
let result;
if (functionName === "name") {
result = body.name;
} else if(functionName ==="symbol") {
result = body.symbol;
} else if(functionName === "totalSupply") {
result = body.totalSupply;
} else {
return;
}
return result
}
main();
const {
Client,
AccountBalanceQuery, PrivateKey, Wallet
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });
const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);
const otherAccountId = process.env.OTHER_ACCOUNT_ID;
const otherPrivateKey = PrivateKey.fromString(process.env.OTHER_PRIVATE_KEY);
const tokenId = process.env.TOKEN_ID;
// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
myPrivateKey == null ) {
throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
client.setOperator(myAccountId, myPrivateKey);
const walletUser = new Wallet(
myAccountId,
myPrivateKey
)
const walletOther = new Wallet(
otherAccountId,
otherPrivateKey
);
async function main() {
const userWalletBalance = await queryBalance(walletUser);
const otherWalletBalance = await queryBalance(walletOther);
console.log("The balance of the user is: " + userWalletBalance.tokens.get(tokenId));
console.log("The balance of the other user is: " + otherWalletBalance.tokens.get(tokenId));
process.exit();
}
async function queryBalance(user) {
//Create the query
const balanceQuery = new AccountBalanceQuery()
.setAccountId(user.accountId);
//Sign with the client operator private key and submit to a Hedera network
const tokenBalance = await balanceQuery.execute(client);
return tokenBalance;
}
main();
const {
TokenUpdateTransaction,
Client,
TokenInfoQuery, PrivateKey
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });
const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);
const tokenId = process.env.TOKEN_ID;
// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
myPrivateKey == null ) {
throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
client.setOperator(myAccountId, myPrivateKey);
async function main() {
//Create the transaction and freeze for manual signing
const transaction = await new TokenUpdateTransaction()
.setTokenId(tokenId)
.setTokenName("Bestest Game Token")
.setTokenSymbol("BGT")
.freezeWith(client);
//Sign the transaction with the client, who is set as admin and treasury account
const signTx = await transaction.sign(myPrivateKey);
//Submit the signed transaction to a Hedera network
const txResponse = await signTx.execute(client);
//Request the receipt of the transaction
const receipt = await txResponse.getReceipt(client);
//Get the transaction consensus status
const transactionStatus = receipt.status.toString();
console.log("The transaction consensus status is " +transactionStatus);
//Create the query
const query = new TokenInfoQuery()
.setTokenId(tokenId);
//Sign with the client operator private key, submit the query to the network and get the token supply
const name = await queryTokenFunction("name", tokenId);
const symbol = await queryTokenFunction("symbol", tokenId);
const tokenSupply = await queryTokenFunction("totalSupply", tokenId);
console.log('The total supply of the ' + name + ' token is ' + tokenSupply + ' of ' + symbol);
process.exit();
}
async function queryTokenFunction(functionName, tokenId) {
//Create the query
const query = new TokenInfoQuery()
.setTokenId(tokenId);
console.log(functionName);
const body = await query.execute(client);
//Sign with the client operator private key, submit the query to the network and get the token supply
let result;
if (functionName === "name") {
result = body.name;
} else if(functionName ==="symbol") {
result = body.symbol;
} else if(functionName === "totalSupply") {
result = body.totalSupply;
} else {
return;
}
return result
}
main();
const {
Client,
TokenDeleteTransaction,
Wallet,
PrivateKey
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });
const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);
const tokenId = process.env.TOKEN_ID;
// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
myPrivateKey == null ) {
throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
client.setOperator(myAccountId, myPrivateKey);
async function main() {
//Create the transaction and freeze the unsigned transaction for manual signing
const transaction = await new TokenDeleteTransaction()
.setTokenId(tokenId)
.freezeWith(client);
//Sign with the admin private key of the token
const signTx = await transaction.sign(myPrivateKey);
//Submit the transaction to a Hedera network
const txResponse = await signTx.execute(client);
//Request the receipt of the transaction
const receipt = await txResponse.getReceipt(client);
//Get the transaction consensus status
const transactionStatus = receipt.status;
console.log("The transaction consensus status " +transactionStatus.toString());
process.exit();
}
main();
const {
Client,
TokenBurnTransaction,
PrivateKey
} = require("@hashgraph/sdk");
require('dotenv').config({ path: 'Token_Service/.env' });
const myAccountId = process.env.MY_ACCOUNT_ID;
const myPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);
const otherPrivateKey = PrivateKey.fromString(process.env.OTHER_PRIVATE_KEY);
const tokenId = process.env.TOKEN_ID;
// If we weren't able to grab it, we should throw a new error
if (myAccountId == null ||
myPrivateKey == null ) {
throw new Error("Environment variables myAccountId and myPrivateKey must be present");
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
client.setOperator(myAccountId, myPrivateKey);
async function main() {
//Burn 42 tokens and freeze the unsigned transaction for manual signing
const transaction = await new TokenBurnTransaction()
.setTokenId(tokenId)
.setAmount(42)
.freezeWith(client);
//Sign with the supply private key of the token
const signTx = await transaction.sign(otherPrivateKey);
//Submit the transaction to a Hedera network
const txResponse = await signTx.execute(client);
//Request the receipt of the transaction
const receipt = await txResponse.getReceipt(client);
//Get the transaction consensus status
const transactionStatus = receipt.status;
console.log("The transaction consensus status " +transactionStatus.toString());
process.exit();
}
main();