- Create and configure an NFT.
- Grant and revoke a Know Your Customer (KYC) flag.
- Update the KYC key with an Admin (to rotate compliance keys, for example)
You can take a look at the complete code in the Hedera-Code-Snippets
repository
Prerequisites
- ECDSA account from the Hedera Portal.
- Basic understanding of Solidity.
Table of Contents
- Step 1: Add KYC key when creating HTS NFT Collection
- Step 2: Minting and Burning an NFT
- Step 3: Granting KYC
- Step 4: Revoking KYC
- Step 5: Updating the KYC Key
- Step 6: Deploy your HTS KYC enabled NFT Smart Contract
- Step 7: Minting an HTS NFT with KYC
- Step 8: Burning an HTS NFT with KYC
- Step 9: Run tests
- Token Association in the Tests
- Conclusion
- Additional Resources
Step 1. Add KYC key when creating HTS NFT Collection
The previous tutorial covered creating NFT collection. Everything remains largely the same except for the following changes:- We just need to add one additional line for managing the KYC key that is able to grant/remove KYC.
- We will be using
createNonFungibleTokeninstead ofcreateNonFungibleTokenWithCustomFeesfor this exercise.
Key Code Snippet:
contracts/MyHTSTokenKYC.sol
How It Works
- Define Token Details – Provide
nameandsymbol. - Set Keys – We generate three token keys:
- AdminKey: Grants permission to update token-level properties later.
- SupplyKey: Permits minting and burning of tokens.
- KYCKey: Allows the contract (acting as the KYC authority) to grant or revoke KYC on specific accounts.
- Create the NFT – Call the HTS System Contract’s
createNonFungibleTokenfunction from within the contract. If successful, store the resulting HTS token address intokenAddress.
createNFTCollection(...) and expect it to emit an NFTCollectionCreated event with a valid token address.
Step 2. Minting and Burning an NFT
The previous tutorial covered minting and burning NFTs. Nothing’s changed in the code as it’s the same as before.Step 3. Granting KYC
Let’s update our contract by:- Adding a new function
grantKYCto enable KYC for a specific account. If a token is configured to enforce KYC, that account must be “granted” KYC before it can receive or send the token. - We will also define a new event
KYCGrantedto go along with it.
Key Code Snippet:
contracts/MyHTSTokenKYC.sol
Without this step, the account won’t be able to receive or transact the NFT.
Step 4. Revoking KYC
Let’s update our contract by:- Adding a new function
revokeKYCto disable KYC for a specific account. After revocation, that account can no longer receive or transfer the token. - We will also define a new event
KYCRevokedto go along with it.
contracts/MyHTSTokenKYC.sol
Step 5. Updating the KYC Key
Let’s update our contract by:- Adding a new function
updateKYCKeyto change the KYC key on the token. This could be a “key rotation” to maintain compliance or to assign another entity control over KYC status. - We will also define a new event
KYCKeyUpdatedto go along with it.
contracts/MyHTSTokenKYC.sol
MyHTSTokenKYC.sol:
contracts/MyHTSTokenKYC.sol
Step 6: Deploy Your HTS KYC Enabled NFT Smart Contract
Create a deployment script (deployKYC.ts) in scripts directory:
scripts/deployKYC.ts
MyHTSTokenKYC.deploy().
NoteFor most HTS System Smart Contract calls, an HBAR value is not required to be sent in the contract call; the gas fee will cover it. However, for expensive transactions, like Create HTS NFT Collection, the gas fee is reduced, and the transaction cost is covered by the payable amount. This is to reduce the gas consumed by the contract call.
Copy the deployed address—you’ll need this in subsequent steps.
Step 7: Minting an HTS NFT with KYC
Create amintNFTKYC.ts script in your scripts directory to mint an NFT. Don’t forget to replace the <your-contract-address> with the address you’ve just copied.
scripts/mintNFTKYC.ts
How It Works
- Connects to Hedera testnet, gets the first signer, and attaches to your deployed MyHTSTokenKYC contract.
- Reads the underlying HTS ERC721 facade address (tokenAddress) from the contract.
- Associates the signer via
token.associate()(EOA -> token contract) - Grant KYC to the recipient
- Constructs <=100-byte UTF-8 metadata and calls mintNFT(recipient, metadata), then waits for the transaction receipt.
- Mints NFT to recipient
- Queries balanceOf(recipient) on the ERC721 facade and logs the current NFT count.
signer.address ). Then we verify the balance to see if we own an HTS NFT.
Mint an NFT:
Step 8: Burning an HTS NFT
Create a burn script (burnNFTKYC.ts ) in your scripts directory. Make sure to replace <your-contract-address> to the MyHTSToken contract address you got from deploying and replace <your-token-id> with the tokenId you want to burn(eg. “1”) :
scripts/burnNFTKYC.ts
How It Works
- Connects to Hedera testnet, gets the signer, attaches to MyHTSTokenKYC, and reads the ERC721 facade tokenAddress.
- Checks token ownership and existing approval; if needed, approves the MyHTSTokenKYC contract for the specific tokenId.
- Calls burnNFT(tokenId) on MyHTSTokenKYC and waits for the transaction receipt.
- Reads and logs the signer’s NFT balance from the ERC721 facade after the burn.
1, which is the HTS NFT you’ve just minted. To be sure the token has been deleted, let’s print the balance for our account to the terminal. The balance should show a balance of 0.
Burn the NFT:
Step 9: Run tests(Optional)
You can find both types of tests in the Hedera-Code-Snippets repository. You will find the following files:You can find both types of tests in the Hedera-Code-Snippets repository. You will find the following files:contracts/MyHTSTokenKYC.t.sol
- Ownership and access control: Ensures the constructor sets the correct owner and enforces onlyOwner for createNFTCollection and updateKYCKey (non-owners revert with OwnableUnauthorizedAccount). * Pre-creation guards: Confirms HTS-dependent functions (mint, burn, grantKYC, revokeKYC, updateKYCKey) revert with “HTS: not created” before the collection is created.
- HBAR handling: Verifies the contract can receive HBAR (HBARReceived event), blocks non-owner withdrawals, and allows the owner to withdraw all HBAR (HBARWithdrawn event) leaving the contract balance at zero.
test/MyHTSTokenKYC.ts
- Deployment and setup: Deploys the KYC wrapper, creates the HTS NFT collection (with KYC key), and retrieves the ERC721 facade address. * KYC enforcement before mint: Validates that minting reverts when KYC has not been granted to the recipient. * Association + KYC + mint: Associates the signer via token.associate(), grants KYC via the wrapper, then mints and extracts the tokenId from the wrapper’s NFTMinted event. * Burn flow: Approves the wrapper for the minted token if needed and burns it via the wrapper; confirms the operation by checking the signer’s ERC721 balance. * KYC key rotation and effect: Derives the signer’s compressed public key on-chain and updates the KYC key; verifies subsequent grantKYC calls fail since the wrapper no longer holds the KYC key.
Token Association in the Tests
Because we’re using a hybrid approach of EVM and the Native Hedera Token Service, you’ll see special logic to:- Associate the newly created token with the signer’s account.
- Grant KYC to the account
- Mint NFT to the account
Conclusion
Using a Solidity Smart Contract on Hedera, you can replicate many of the native HTS functionalities—granting and revoking KYC, updating token keys, minting and transferring NFTs—while retaining the benefit of contract-driven logic and on-chain state. This approach may be preferable if:- You want advanced business logic in a self-contained contract.
- You prefer standard Solidity patterns and tooling for your Web3 workflows.
- You plan to modularize or integrate your token behavior with other smart contracts.