I have created a new token on HTS using the JavaScript SDK:
// Create an HTS Fungible Token
async function createFungibleToken(
client,
treasuryAccountId,
treasuryAccountPrivateKey,
) {
// Generate supply key
const supplyKeyForFT = PrivateKey.generateED25519();
// Confgiure the token
const createFTokenTxn = await new TokenCreateTransaction()
.setTokenName('PowerToken')
.setTokenSymbol('PT')
.setTokenType(TokenType.FungibleCommon)
.setDecimals(1)
.setInitialSupply(100)
.setTreasuryAccountId(treasuryAccountId)
.setSupplyKey(supplyKeyForFT)
.setMaxTransactionFee(new Hbar(30))
.freezeWith(client);
// Sign the transaction with the treasury account private key
const createFTokenTxnSigned = await
createFTokenTxn.sign(treasuryAccountPrivateKey);
const createFTokenTxnResponse = await
createFTokenTxnSigned.execute(client);
const createFtTokenTxnReceipt = await createFTokenTxnResponse.getReceipt(client);
const fungibleTokenId = createFtTokenTxnReceipt.tokenId;
console.log(`Fungible token ID: ${fungibleTokenId}`);
}
And then attempted to send it to an account using a TransferTransaction():
async function transferHtsToken(tokenId, senderAccountId, receiverAccoundId, myPrivateKey) {
const transferTransaction = new TransferTransaction()
.addTokenTransfer(tokenId, senderAccountId, -1)
.addTokenTransfer(tokenId, receiverAccoundId, 1)
.freezeWith(client);
const signTx = await transferTransaction.sign(myPrivateKey);
const txResponse = await signTx.execute(client);
const receipt = await txResponse.getReceipt(client);
const txStatus = receipt.status;
console.log(`Transaction status ${txStatus}`);
}
However, I get the following error:
ReceiptStatusError: receipt for transaction 0.0.565763@1692941232.156398491 contained error status TOKEN_NOT_ASSOCIATED_TO_ACCOUNT
Why is it necessary to “associate” a token on Hedera?
And how can I do so?
On Hedera, HTS allows you to create fungible tokens which behave similarly to ERC20 tokens, but they aren’t an exact match. One of the key differences is that an account needs to explicitly “opt-in” to a particular token in order to interact with it. This is called “token association”.
Note that an account may subsequently dissociate itself from the token which it has previously associated itself with if it no longer wishes to interact with that token.
And how can I do so?
The first step in associating to a token is to build a TokenAssociateTransaction()
:
// Build a tokenAssociateTransaction to associate an account to a token
// and freeze the unsigned transaction for signing
const associateTransaction = await new TokenAssociateTransaction()
.setAccountId(accountId)
.setTokenIds([tokenId])
.freezeWith(client);
Once the transaction is built you will need to sign the transaction using the private key of the account that is being associated to the token.
const associateTransactionSigned = await associateTransaction.sign(accountKey);
Next, submit the signed transaction to the Hedera network using the execute()
method
const associateTransactionResponse = await associateTransactionSigned.execute(client);
Finally, get the receipt from the transaction response and grab the status of if
// Get the receipt of the transaction
const receipt = await associateTransactionResponse.getReceipt(client);
// Get the transaction consensus status
const associateTransactionStatus = receipt.status;
In order to dissociate an account from an HTS token you need to build a TokenDissociateTransaction()
async function dissociateAccountFromToken() {
// Dissociate an account from a token and freeze the unsigned transaction for signing
const dissociateTransaction = await new TokenDissociateTransaction()
.setAccountId(accountId)
.setTokenIds([tokenId])
.freezeWith(client);
// sign using the private key of the account that is dissociating from the token
const dissociateTransactionSigned = await dissociateTransaction.sign(accountKey);
// submit the transaction to a Hedera network
const dissociateTransactionResponse = await dissociateTransactionSigned.execute(client);
// Get the receipt of the transaction
const receipt = await dissociateTransactionResponse.getReceipt(client);
// Get the transaction consensus status
const dissociateTransactionStatus = receipt.status;
}