Use this file to discover all available pages before exploring further.
The HTS system contract at 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.
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.
Token creation costs HBAR. The caller has to forward enough msg.value to cover the TokenCreate transaction fee, which buys the token its initial auto-renew period (~92 days). The current base fee is around $1 USD worth of HBAR for both fungible and non-fungible tokens.Two important things to know about how Hedera handles the money:
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.value is not refunded. Anything you forward beyond what the precompile consumes for the TokenCreate fee stays in the calling contract’s balance. There is no automatic refund to the EOA.
The practical pattern: compute the exact tinybars via the Exchange Rate system contract just before the call, or build a refund step into your contract that returns leftover HBAR to msg.sender after the precompile call.
// Compute the exact value just before the call, then forward only that amount.// 1.5 USD in tinycents = 1.5 * 10^8 tinycents. Gives a small safety margin// over the ~$1 base fee.uint256 tinybars = IExchangeRate(0x168).tinycentsToTinybars(15 * 10**7);uint256 wei_ = tinybars * 10**10; // tinybars (8 decimals) -> wei (18 decimals)TokenFactory(factory).createFungible{value: wei_}("MyToken", "MTK", 1_000_000, 2);
Token creation fails with INSUFFICIENT_PAYER_BALANCE if msg.value doesn’t cover the fee. If you can’t compute the exact amount, pass extra and refund the leftover from inside your contract. Don’t expect Hedera to do it for you.
The HederaToken.tokenKeys array decides who can do what to the token. Each entry is a (keyType, keyValue) pair:
Key
Authorizes
ADMIN
Updating token properties and rotating other keys
SUPPLY
Minting and burning
FREEZE
Freezing and unfreezing accounts
WIPE
Wiping tokens from accounts
KYC
Granting and revoking KYC status
PAUSE
Pausing all token operations
FEE_SCHEDULE
Updating the custom-fee schedule
METADATA
Updating NFT serial-number metadata (HIP-657)
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 / ECDSA (provide a raw public key).