0x167 lets a Solidity contract create native HTS tokens. The resulting token is a real HTS token: same association rules, same mirror node REST responses, same HashScan view as an SDK-created one. You can operate on it through the HTS interface or through ERC-20 / ERC-721 redirects.
At a glance
Why use this instead of a plain ERC-20?
Two practical reasons. The first is compliance features. HTS tokens get native support for KYC keys, freeze, pause, wipe, supply caps, and royalty fees, and the network enforces them. If you build the same controls into an ERC-20 contract, you write them yourself and pay gas every time they fire. The second is pricing. HTS operations are priced in USD and paid in HBAR by the network. ERC-20 operations are priced in EVM gas, which scales with whatever you put in your contract. If you don’t need any of that, a plain ERC-20 is simpler and works fine. The choice is per-token; nothing stops you from using both in one app.Required imports
The helper library isHederaTokenService.sol, published with its companion contracts in the @hiero-ledger/hiero-contracts npm package. Install it in your project:
Keep the package layout.
HederaTokenService.sol imports ../common/HederaResponseCodes.sol, so copying the files into one flat folder breaks the build.
Example: fungible token
Example: non-fungible token
Paying for it
Token creation costs HBAR. The caller has to forward enoughmsg.value to cover the TokenCreate transaction fee, which buys the token its initial auto-renew period (90 days, the defaultAutoRenewPeriod of 7,776,000 seconds in HederaTokenService.sol). The current base fee is around $1 USD worth of HBAR for both fungible and non-fungible tokens.
Three important things to know about how Hedera handles the money:
msg.valuemust cover the create price, in tinybars.HederaTokenService.createFungibleTokenandcreateNonFungibleTokenforwardmsg.valueto the HTS system contract. It requires at least the HAPITokenCreateprice plus a 20% surcharge, minus the fixed gas portion it already charged. Inside the EVM,msg.valueis in tinybars (8 decimals), so don’t scale it by10**10.- Gas is charged on consumption. Per HIP-1249, Hedera refunds 100% of unused gas, and the per-transaction limit is 15M (HIP-185). Set a generous gas limit; you only pay for what you actually use.
- Excess
msg.valueis not refunded. Anything you forward beyond what the system contract consumes for theTokenCreatefee stays in the calling contract’s balance. There is no automatic refund to the EOA.
msg.sender after the create call.
TokenCreate with custom fees at $2.00, so with the 20% surcharge forward about $2.40 worth of tinybars (for example 24 * 10**9 tinycents) instead of the $1.50 above.
Calling
createFungible from a client through the JSON-RPC relay (ethers, viem, a wallet) is different: there, value is in 18-decimal weibars, so pass the tinybar amount times 10**10 (in ethers, parseEther("2") sends 2 HBAR). The network converts it to tinybars before the contract sees it. See HBAR decimal places.Token keys
TheHederaToken.tokenKeys array decides who can do what to the token. Each entry is a (keyType, keyValue) pair:
Build each entry with
KeyHelper.getSingleKey(KeyType.X, KeyValueType.Y, address). Common KeyValueType values: CONTRACT_ID (the contract signs implicitly), INHERIT_ACCOUNT_KEY (use the caller’s key), ED25519 / SECP256K1 (provide a raw public key).
token-service/KeyHelper.sol has no METADATA key type, so getSingleKey can’t build the metadata key from HIP-657.
See also
HTS System Contract Overview
Full function reference for the HTS precompile, including transfer, mint, burn, freeze, pause, and KYC operations.