Skip to main content
In Part 1 of the series, you saw how to mint, transfer, and burn an NFT using Hedera’a EVM and Hedera Token Service (HTS) System Smart Contracts. In this guide, you’ll learn the basics of how to configure / permission native Hedera Tokens via a Smart Contract. Specifically, you will learn how to:
  • 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

  1. Step 1: Add KYC key when creating HTS NFT Collection
  2. Step 2: Minting and Burning an NFT
  3. Step 3: Granting KYC
  4. Step 4: Revoking KYC
  5. Step 5: Updating the KYC Key
  6. Step 6: Deploy your HTS KYC enabled NFT Smart Contract
  7. Step 7: Minting an HTS NFT with KYC
  8. Step 8: Burning an HTS NFT with KYC
  9. Step 9: Run tests
  10. Token Association in the Tests
  11. Conclusion
  12. 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 createNonFungibleToken instead of createNonFungibleTokenWithCustomFees for this exercise.

Key Code Snippet:

contracts/MyHTSTokenKYC.sol
How It Works
  1. Define Token Details – Provide name and symbol.
  2. 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.
  3. Create the NFT – Call the HTS System Contract’s createNonFungibleToken function from within the contract. If successful, store the resulting HTS token address in tokenAddress.
We call 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 grantKYC to 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 KYCGranted to 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 revokeKYC to 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 KYCRevoked to go along with it.
contracts/MyHTSTokenKYC.sol

Step 5. Updating the KYC Key

Let’s update our contract by:
  • Adding a new function updateKYCKey to 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 KYCKeyUpdated to go along with it.
contracts/MyHTSTokenKYC.sol
After this key rotation, the contract’s key is no longer able to perform KYC operations. In the snippet above, we immediately demonstrate that KYC attempts signed by the contract itself will revert. Account 1 will now be able to grant/revoke KYC using the SDK. Here’s the complete contract code for 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
In this script, we first retrieve your account (the deployer) using Ethers.js. This account will own the deployed smart contract. Next, we use this account to deploy the contract by calling 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.
Deploy your contract by executing the script:
Copy the deployed address—you’ll need this in subsequent steps.
The output looks like this:

Step 7: Minting an HTS NFT with KYC

Create a mintNFTKYC.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
  1. Connects to Hedera testnet, gets the first signer, and attaches to your deployed MyHTSTokenKYC contract.
  2. Reads the underlying HTS ERC721 facade address (tokenAddress) from the contract.
  3. Associates the signer via token.associate()(EOA -> token contract)
  4. Grant KYC to the recipient
  5. Constructs <=100-byte UTF-8 metadata and calls mintNFT(recipient, metadata), then waits for the transaction receipt.
  6. Mints NFT to recipient
  7. Queries balanceOf(recipient) on the ERC721 facade and logs the current NFT count.
The code mints a new NFT to your account ( signer.address ). Then we verify the balance to see if we own an HTS NFT. Mint an NFT:
Expected output:

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
  1. Connects to Hedera testnet, gets the signer, attaches to MyHTSTokenKYC, and reads the ERC721 facade tokenAddress.
  2. Checks token ownership and existing approval; if needed, approves the MyHTSTokenKYC contract for the specific tokenId.
  3. Calls burnNFT(tokenId) on MyHTSTokenKYC and waits for the transaction receipt.
  4. Reads and logs the signer’s NFT balance from the ERC721 facade after the burn.
The script will burn the HTS NFT with the ID set to 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:
You should get an output similar to:
Congratulations! 🎉 You have successfully learned how to deploy an HTS NFT collection smart contract using Hardhat, OpenZeppelin, and Ethers. Feel free to reach out in Discord!

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.
Copy these files and then run the tests:
You can also run both the solidity and mocha tests altogether:

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
This is due to a nuance: In order to grant KYC to an account, it must have the token associated with it. This is the case even if the account has unlimited auto associations.

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.
Check out Part 3: How to Pause, Freeze, Wipe, and Delete NFTs to learn more about configuring Native Tokens with Smart Contracts.

Hts X Evm Part 3 How To Pause Freeze Wipe And Delete Nfts


Additional Resources

Check out our GitHub repo to find the full contract and Hardhat test scripts, along with the configuration files you need to deploy and test on Hedera!

Writer: Jake, Senior DevRel Engineer

Editor: Michiel, DevRel Engineer

Editor: Krystal, Senior DX Engineer

Editor: Kiran, Developer Advocate