Reputation: 73
Before I can receive an HTS token I need to first associate with the token ID.
If I were using the JS SDK I know to do the following where the accountId
is the account that I want to associate with the token.
const associateTransaction = await new TokenAssociateTransaction()
.setAccountId(accountId)
.setTokenIds([tokenId])
.freezeWith(client);
However, how do you Associate/Dissociate an HTS token using an EVM transaction?
I’ve attempted to do the following in my smart contract
function mintNft(
address token,
bytes[] memory metadata
) public payable returns(int64){
(int response, , int64[] memory serial) = HederaTokenService.mintToken(token, 0, metadata);
if(response != HederaResponseCodes.SUCCESS){
revert("Failed to mint non-fungible token");
}
int res = HederaTokenService.associateToken(
address(msg.sender),
token
);
if(res != HederaResponseCodes.SUCCESS){
revert("Failed to associate non-fungible token");
}
return serial[0];
}
However, when I try to transfer the contract reverts with the following error:
TOKEN_NOT_ASSOCIATED_TO_ACCOUNT
I’d like to be able to do so within a smart contract deployed to HSCS, preferably. If that is not possible, is there another way to do so?
Upvotes: 7
Views: 295
Reputation: 116
Calling associateToken
on HederaTokenService
System Contract is deprecated and can no longer associate to address(msg.sender)
. It can only associate to address(this)
. The user must call the associate function on the token's contract directly.
Smart Contracts cannot change an externally owned accounts state meaning a contract cannot associate, transfer, and approve transaction on a users behalf. Although highly useful, by allowing a contract to change an EOA state it could potentially allow a bad actor to act maliciously on behalf of a user. Therefore, Associating/disassociating HTS tokens within smart contracts is not allowed. You can read further about the security update to smart contracts here.
I will show you how to associate/dissociate using ethers.js
You first start by setting up your ethers provider, requesting access to accounts, and getting your signer.
const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
Next you will construct the abi
which species the contract function you want to execute
const abi = ["function associate()"];
You can can treat HTS tokens as if they were ERC20/ERC721 tokens. This functionality is what allows us to call the associate
/dissociate
function directly on the HTS token. In order to do so, you must first convert the HTS tokenID into it’s solidity address with a ‘0x’ prefix.
const tokenSolidityAddress = '0x' + TokenId.fromString('0.0.572609').tokenSolidityAddress();
Finally, create a contract instance and call associate directly on the contract.
// create contract instance using token solidity address, abi, and signer
const contract = new ethers.Contract(tokenSolidityAddress, abi, signer);
try {
const transactionResult = await contract.associate();
return transactionResult.hash;
} catch (error) {
console.warn(error.message ? error.message : error);
return null;
}
How to dissociate an HTS token:
async function dissociateToken() {
// set up your ethers provider
const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
// request access to the user's account
await provider.send("eth_requestAccounts", []);
// get signer
const signer = provider.getSigner();
const abi = ["function dissociate()"];
const tokenSolidityAddress = '0x' + TokenId.fromString('0.0.572609').tokenSolidityAddress();
// create contract instance using token solidity address, abi, and signer
const contract = new ethers.Contract(tokenSolidityAddress, abi, signer);
try {
const transactionResult = await contract.dissociate();
return transactionResult.hash;
} catch (error) {
console.warn(error.message ? error.message : error);
return null;
}
};
Upvotes: 10