In this advanced tutorial, you’ll learn how to interact with the Hedera Token Service (HTS) using System Contracts precompiles on a forked network. This guide covers creating HTS tokens, minting, transferring, and understanding the limitations of the forking emulation layer. This guide shows how to:Documentation Index
Fetch the complete documentation index at: https://hedera-0c6e0218-feat-hip-1313-high-volume-entity-creation.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
- Create HTS fungible tokens using System Contracts precompiles
- Mint and transfer HTS tokens on a forked network
- Repo: hashgraph/hedera-forking
- HTS System Contracts: hedera-smart-contracts
- Supported methods: README - Supported Methods
For a deeper understanding of how Hedera forking works and its limitations,
see Forking Hedera Network for Local
Testing.
You can take a look at the complete code in the advanced-hts-fork-test
repository.
Prerequisites
- Completed Part 1 of this tutorial series
- Familiarity with Hedera System Contracts - more specifically HTS System Contracts precompiles
Table of Contents
- Step 1: Project Setup
- Step 2: Create the HTS Contract and Deploy to Testnet
- Step 3: Write Tests for Supported HTS Methods
- Step 4: Run Tests on the Forked Network
Step 1: Project Setup
Initialize Project
Create a new directory and initialize the project:Install Dependencies
Create or update yourpackage.json with all required dependencies:
package.json
@hashgraph/smart-contracts which provides the HTS System Contracts interfaces and helper contracts.
Then install all dependencies:
Create Project Structure
Create the necessary directories:Configure TypeScript
Createtsconfig.json in your project root:
tsconfig.json
Configure Hardhat
Createhardhat.config.ts in your project root:
hardhat.config.ts
HEDERA_RPC_URL- Loaded from Hardhat configuration variablesHEDERA_PRIVATE_KEY- Loaded securely from configuration variableshederaTestnet- Network configuration for deploying to real testnethardhat.forking- Configuration for forking testnet locallyblockNumber- Pin to a block where your deployed contract existschainId: 296- Required for testnet (295 for mainnet)workerPort: 10001- Any free port for the worker that intercepts Hardhat calls@ts-ignore- Required becausechainIdandworkerPortare custom properties not in Hardhat’s type definitions- Optimizer is enabled for gas efficiency
Set Configuration Variables
Now thathardhat.config.ts exists, you can set the configuration variables. Hardhat allows you to securely store sensitive values using configuration variables:
https://testnet.hashio.io/api
Step 2: Create the HTS Contract and Deploy to Testnet
Create the HTS Interaction Contract
Create a new filecontracts/HTSTokenManager.sol:
contracts/HTSTokenManager.sol
createFungibleTokenPublic- Creates new HTS fungible tokensmintTokenPublic- Mints additional tokens (requires supply key)transferTokenPublic- Supported HTS transfer methodgetTokenInfoPublic/getFungibleTokenInfoPublic- Query token information
Compile the Contract
Create Deployment Script
Create a new filescripts/deploy.ts:
scripts/deploy.ts
Deploy to Testnet
Deploy your contract to Hedera testnet:Update Hardhat Config with Deployment Block
After deployment, update yourhardhat.config.ts with the block number:
Step 3: Write Tests for Supported HTS Methods
Create a new filetest/HTSTokenManager.test.ts:
Make sure to update the
DEPLOYED_CONTRACT and TOKEN_ADDRESS constants
below with the values from your deployment.test/HTSTokenManager.test.ts
- TypeScript types - Uses generated types from
typechain-typesfor type safety - Uses deployed contract - Tests bind to the already deployed
HTSTokenManagercontract usinggetContractAt - HTS token creation - Demonstrates creating fungible tokens using HTS System Contracts precompiles on the forked network
- Event parsing - Parses
CreatedToken,ResponseCode, andFungibleTokenInfoevents to verify HTS operations - Response code validation - Checks for HTS
SUCCESSresponse code (22) to confirm operations completed successfully - Self-contained tests - Each test creates its own token and operates on it, ensuring test isolation
- Local modifications - All token creations and queries happen only on the local fork
- No testnet changes - The real testnet is never modified by these tests
- Uses fixtures -
loadFixtureensures each test starts with a clean state - Funded accounts - Uses
hardhat_setBalanceto fund test accounts for gas fees and token creation costs
Step 4: Run Tests on the Forked Network
Run your tests against the forked Hedera testnet:Pin to a Specific Block
For reproducible tests, make sure theblockNumber in your hardhat.config.ts is set to a block where your contract exists. If you try to fork at a block before your contract was deployed, you’ll see an error because the contract doesn’t exist yet at that block.
Best Practices for HTS Fork Testing
- Always verify on real network - Fork testing is for development; always test on testnet/mainnet before production
- Use supported methods - Stick to the currently supported HTS methods
- Handle associations - Remember that token associations work differently in emulation
-
Check response codes - Always verify HTS response codes (
SUCCESS = 22) -
Fund test accounts - Use
hardhat_setBalanceto fund accounts for gas
Understanding Fork Testing with Deployed Contracts
Why Test Against Deployed Contracts?
- Real-world state - Test against actual balances, allowances, and state
- No deployment costs - Don’t spend gas deploying for every test run
- Impersonation - Act as any account (even the contract owner) without their private key
- Safe experimentation - Try anything without affecting the real network
How Impersonation Works
Hardhat’s impersonation feature allows you to act as any address without having its private key:HTSTokenManager is designed with the contract itself as the treasury and supply key holder. All functions are public with no access control, so anyone can call them. See Part 1 for an example where impersonation is required for onlyOwner functions.
Funding Accounts with hardhat_setBalance
Local test accounts on a forked network start with no balance. Fund them for gas and operations:
Further Learning & Next Steps
-
Forking Hedera Network for Local Testing
Deep dive into how Hedera forking works under the hood -
How to Fork Hedera with Foundry
Learn fork testing with Foundry framework -
hedera-forking Repository
Explore examples and documentation -
Hedera Smart Contracts Repository
Explore HTS System Contracts interfaces