javascripthedera-hashgraph

How to Associate/Dissociate an HTS token using Hashgraph JS SDK


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?


Solution

  • 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()

    💡 The account is required to have a zero balance of the token you wish to dissociate. If a token balance is present, you will receive a `TRANSACTION_REQUIRES_ZERO_TOKEN_BALANCES` error.
    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;
    }