Non-EVM Standards
Hedera Token Service
Learn how Hedera Token Service (HTS) enables secure, scalable token issuance with native controls and low fees.
Hedera Token Service (HTS), the native token issuance and management protocol on Hedera's hashgraph-based blockchain, defines a Layer-1 framework for creating fungible and non-fungible tokens with built-in compliance controls like KYC, freeze, and wipe for regulatory adherence. For Real World Asset (RWA) protocols, this standard is especially valuable, as tokens can represent fractional claims on tokenized real estate, supply chain assets, carbon credits, or other off-chain collateral while maintaining a compliant, interoperable interface for associating, transferring, minting, and pausing without relying on smart contracts for core operations.
Before HTS, Hedera RWA projects used custom HVM (Hedera Virtual Machine) contracts, leading to fragmented compliance, inconsistent scalability, and higher costs. HTS resolved this by embedding native controls, KYC, freeze, and admin keys, directly into the consensus layer, leveraging Hedera's hashgraph for 10,000+ TPS and sub-second finality with ABFT security. For RWA builders, the standard provides a high-throughput abstraction layer supporting off-chain verification flows, such as oracle-fed KYC or atomic swaps for settlement, while enabling seamless composability with DeFi protocols like Dovu or HTS-integrated DEXs. As of late 2025, HTS powers $3B+ in tokenized value, including Envision Blockchain's Asset Tokenization Studio for modular RWAs.
A key design principle is consensus-level compliance, where tokens expose standardized SDK interfaces augmented by optional keys without exposing internal account logic. This is well suited to RWA tokens where transfers may depend on off-chain regulatory data or emergency wipes, yet integrators like wallets or aggregators still need reliable, auditable operations.
Use of HTS in RWA Contexts
HTS is the foundational standard for RWA tokens on Hedera because it abstracts the complexity of tokenizing and managing real-world assets into a native, consensus-embedded framework. While traditional DeFi tokens use HTS for unrestricted transfers, RWA tokens adapt the model to illiquid, regulated assets, tokenized private credit, commercial real estate, commodities, or bond portfolios, where on-chain tokens represent legally backed off-chain value held by custodians or SPVs, with KYC/freeze keys for securities laws like Reg D or MiCA.
Key Applications in RWA Development
Fractional Ownership and Liquidity Provision
Many RWAs are high-value and indivisible (for example, a ten-million-dollar property or a portfolio of supply chain assets). HTS allows developers to create fungible tokens with decimals for fractional shares, unlocking ownership and secondary-market liquidity under compliance rules.
- Implement token creation with total supply for fractions, linking metadata to off-chain deeds.
- Tokens can trade freely on DEXs within KYC bounds, offering liquidity for assets that would otherwise be locked for years.
- Example: A real estate token where wipe key restricts unauthorized holdings, with admin controls for concentration limits.
Yield Accrual and NAV Management
Admin and treasury keys automate revenue handling (e.g., yields from tokenized commodities), with scheduled transactions querying oracles (e.g., Chainlink) for real-time NAV updates. This supports auto-distribution without manual interventions, ideal for tokenized funds or credits.
Using trusted sources (Chainlink, RedStone) ensures accurate valuations, critical for compliance and for investor transfers. Regulators increasingly expect transparent audit trails, and HTS provides this without exposing internal key state.
Redemption and Settlement Mechanics
RWA redemptions are inherently asynchronous, as physical settlement layers (banks, custodians, transfer agents) cannot finalize instantly.
Patterns include:
- Burn via wipe key for queued releases.
- Freeze hooks for invalid transfers.
- Transaction memos for signed claims.
- Proof-of-reserve checks before fulfillment.
Composability Across the RWA Stack
HTS tokens plug directly into Hedera DeFi:
- Dovu accepts tokens as collateral within freeze restrictions.
- DEXs can provide deep secondary liquidity for permitted transfers.
- Aggregators route into HTS natively.
For regulated RWAs:
- Pair with KYC key for investor eligibility gating.
- Combine with wipe for modular compliance.
- Integrate identity proofs via admin roles.
This drastically reduces integration complexity, for example, a tokenized carbon credit can list across lending markets without custom adapters.
Developer Advantages in RWA Builds
- Regulatory Alignment: Native keys hide off-chain custodian processes while preserving accurate controls for MiFID II/MiCA-aligned disclosures.
- Extensibility: KYC/freeze allow injecting RWA-specific logic i.e., pricing oracles, geofencing, or IPFS-pinned compliance policies.
- Risk Isolation: Tokens remain fully consensus compliant, wipes do not impact wallet-held balances outside keys.
- Upgrade Path: Hedera governance enables protocol upgrades, preserving TVL and simplifying audits.
To visualize the end-to-end flow in an RWA token, the following sequence diagram captures the typical create - transfer - wipe cycle. It illustrates how users interact with the HTS ledger, how keys interact with admins and oracles, and how off-chain compliance updates flow back on-ledger through transactions or memos. This representation is especially important for understanding asynchronous transfers, delayed settlements, and key-driven compliance in RWA systems.
This diagram highlights how HTS acts as the connective tissue between on-ledger token operations and off-chain asset realities. Creations embed keys proportional to supply, admins capture real-world compliance as transfers execute, and wipe functions help manage revocations during disputes. For illiquid RWA portfolios, the model can be extended with explicit freeze rules between the ledger (L) and the custodian or SPV (C) to handle delayed settlement cycles.
Core Specification
An HTS token must implement the native consensus interface for its fungible/non-fungible structure, the controlled representation of a user’s proportional claim on the underlying asset. Optional keys enable advanced features like wipe, a valuable enhancement for RWA use cases where institutions manage access without needing full smart contracts.
In HTS, the token behaves like any ledger token (balance queries, total supply, transfers), while keys refer to designated signers for asset management. The specification enforces a clean separation between base tokens and key params, ensuring predictable operations and seamless integration across Hedera and RWA systems.
Key Definitions
- Token ID: The unique ledger identifier for the HTS token, e.g., a tokenized real estate share or carbon credit.
- Account: The holder's associated address, extensible for frozen states or memos.
- Total Supply: The aggregate token value managed by the token, equal to the sum of principal, wiped amounts, and adjustments for fees or losses.
- Control Keys: (e.g., Admin, KYC) Provide idealized, rule-agnostic behaviors for UI, analytics, and oracle integrations. They represent the regulatory relationship between base tokens and enforced logic.
- Transaction Functions: (e.g., transfer, wipe) Provide near-exact estimates of expected outcomes, reflecting keys, rounding, or NAV changes, without executing state updates. These enable accurate transaction planning.
- Rounding Rules: HTS mandates rounding in favor of the token:
- Round down when issuing units or deductions, preventing dilution.
- Round up when applying freezes or requirements, protecting existing participants. These rules ensure fair distribution and discourage precision-based attacks.
HTS defines core transaction types with 15+ parameters, organized by their roles in creation, management, and transfers. Every token is created via a single transaction, ensuring a single source of truth for behavior and movements. Below is the JavaScript-equivalent interface via @hashgraph/sdk, accompanied by developer notes covering edge cases, rounding behavior, and considerations specific to RWA tokens such as asynchronous keys and oracle-driven updates.
1const {
2 Client,
3 AccountId,
4 PrivateKey,
5 TokenCreateTransaction,
6 TokenAssociateTransaction,
7 TokenGrantKycTransaction,
8 TokenFreezeTransaction,
9 TokenWipeTransaction,
10 TokenTransferTransaction,
11} = require("@hashgraph/sdk");
12
13const client = Client.forTestnet(); // Or mainnet
14
15// Core Token Creation
16async function createHtsToken(adminPrivateKey, treasuryAccountId, supply) {
17 const adminKey = PrivateKey.fromString(adminPrivateKey);
18 client.setOperator(treasuryAccountId, adminKey);
19
20 const transaction = await new TokenCreateTransaction()
21 .setTokenName("RWA Real Estate")
22 .setTokenSymbol("RWA-RE")
23 .setDecimals(6)
24 .setInitialSupply(supply)
25 .setTreasuryAccountId(treasuryAccountId)
26 .setAdminKey(adminKey.publicKey)
27 .setKycKey(adminKey.publicKey)
28 .setFreezeKey(adminKey.publicKey)
29 .setWipeKey(adminKey.publicKey)
30 .setCustomFees([]) // Optional royalties
31 .setMemo("Tokenized Property Shares")
32 .freezeWith(client)
33 .sign(adminKey);
34
35 const txResponse = await transaction.execute(client);
36 const receipt = await txResponse.getReceipt(client);
37 return receipt.tokenId;
38}
39
40// Associate (Opt-in)
41async function associateToken(userPrivateKey, userAccountId, tokenId) {
42 const userKey = PrivateKey.fromString(userPrivateKey);
43 client.setOperator(userAccountId, userKey);
44
45 const transaction = await new TokenAssociateTransaction()
46 .setAccountId(userAccountId)
47 .setTokenIds([tokenId])
48 .freezeWith(client)
49 .sign(userKey);
50
51 const txResponse = await transaction.execute(client);
52 await txResponse.getReceipt(client);
53}
54
55// Grant KYC
56async function grantKyc(
57 adminPrivateKey,
58 treasuryAccountId,
59 tokenId,
60 userAccountId
61) {
62 const adminKey = PrivateKey.fromString(adminPrivateKey);
63 client.setOperator(treasuryAccountId, adminKey);
64
65 const transaction = await new TokenGrantKycTransaction()
66 .setAccountId(userAccountId)
67 .setTokenId(tokenId)
68 .freezeWith(client)
69 .sign(adminKey);
70
71 const txResponse = await transaction.execute(client);
72 await txResponse.getReceipt(client);
73}
74
75// Transfer
76async function transferToken(
77 senderPrivateKey,
78 senderAccountId,
79 receiverAccountId,
80 tokenId,
81 amount
82) {
83 const senderKey = PrivateKey.fromString(senderPrivateKey);
84 client.setOperator(senderAccountId, senderKey);
85
86 const transaction = await new TokenTransferTransaction()
87 .addTokenTransfer(tokenId, senderAccountId, -amount)
88 .addTokenTransfer(tokenId, receiverAccountId, amount)
89 .freezeWith(client)
90 .sign(senderKey);
91
92 const txResponse = await transaction.execute(client);
93 await txResponse.getReceipt(client);
94}
95
96// Wipe (Clawback/Burn)
97async function wipeToken(
98 adminPrivateKey,
99 treasuryAccountId,
100 tokenId,
101 userAccountId,
102 amount
103) {
104 const adminKey = PrivateKey.fromString(adminPrivateKey);
105 client.setOperator(treasuryAccountId, adminKey);
106
107 const transaction = await new TokenWipeTransaction()
108 .setAccountId(userAccountId)
109 .setTokenId(tokenId)
110 .setAmount(amount)
111 .freezeWith(client)
112 .sign(adminKey);
113
114 const txResponse = await transaction.execute(client);
115 await txResponse.getReceipt(client);
116}
117
118// Freeze
119async function freezeToken(
120 adminPrivateKey,
121 treasuryAccountId,
122 tokenId,
123 userAccountId
124) {
125 const adminKey = PrivateKey.fromString(adminPrivateKey);
126 client.setOperator(treasuryAccountId, adminKey);
127
128 const transaction = await new TokenFreezeTransaction()
129 .setAccountId(userAccountId)
130 .setTokenId(tokenId)
131 .freezeWith(client)
132 .sign(adminKey);
133
134 const txResponse = await transaction.execute(client);
135 await txResponse.getReceipt(client);
136}
Detailed Function Breakdown (with RWA Developer Notes)
Below is a transaction-by-transaction explanation of the HTS interface, including edge cases, rounding behavior, and RWA-specific implementation guidance for regulated assets, off-chain settlement, and key-driven validation.
createHtsToken()
Creates the base token with immutable params (supply, decimals) and keys. In RWA tokens, this pins the initial configuration for tokenized real estate, carbon wrappers, or supply chain notes.
- This value is partially immutable; keys can update via admin.
associateToken()
Establishes holder opt-in, requiring GrantKyc if KYC key set.
- RWA Integration: For compliance-based assets, prepend oracle check (Chainlink / oracles).
- Edge Case: Must handle non-associated receivers (revert) or frozen states.
grantKyc()
Enables transfers for account with KYC key.
- Formula: Consensus toggle post-validation.
- Usage: UI quoting, risk dashboards.
- RWA Note: Reflects pure regulatory enablement, does not account for settlement delays or custody fees.
transferToken()
Executes transfer between associated accounts, emitting ledger memo.
- Ensures no precision-based arbitrage on amounts.
- RWA Note: Useful for compliant trades in regulated markets.
wipeToken()
Revokes amount from holder with wipe key.
- Return 0 for “no amount.”
- RWA Note: Enforce redemptions, jurisdiction restrictions, or temporary pauses due to regulatory flags.
freezeToken()
Toggles frozen state for account with freeze key.
- Discrepancies vs grant reveal control impact.
- RWA Note: Useful for quote generation in dynamic vaults or those with custody fees.
Update Keys (Admin Txn)
Replaces keys (e.g., revoke wipe by new key).
- Requires prior admin check.
- Includes notes for AML evaluation.
- RWA Note:
- For illiquid assets (such as real estate and supply chain): pair with wipe asynchronous resolutions.
- Trigger oracle checks for sanctions/residency validation.
Reference Implementation
Hedera Foundation’s HTS offers a mature, security-audited foundation for building native tokens via SDKs. The protocol integrates with the hashgraph, providing a clean transaction surface for RWA-specific logic. Its design encourages minimal txns while still supporting custom key models, metadata memos, control layers, and oracle integration.
Key capabilities include:
- Inflation Attack Protection: The implementation prevents dilution by enforcing supply limits and key checks. Early creators cannot exploit low-supply corner cases to extract excess value.
- Rounding Compliance: All transfers use consensus arithmetic for precise, deterministic operations that adhere to HTS requirements of rounding in favor of the token. This eliminates subtle precision-drift exploits.
- Extensible Controls: Lifecycle txns such as wipe allow developers to embed RWA-specific functionality, NAV oracle checks, compliance gating, settlement status validation, or fee accounting, without modifying core logic.
- Flexible Structure: HTS builds on the ledger’s base, with optional HVM wrappers for regulated administration. This makes it straightforward to integrate custodial controls, upgrade pathways, or key-gated operations required in regulated RWA environments.
1const {
2 Client,
3 PrivateKey,
4 TokenCreateTransaction,
5 TokenAssociateTransaction,
6 TokenGrantKycTransaction,
7 TokenTransferTransaction,
8 TokenWipeTransaction,
9} = require("@hashgraph/sdk");
10
11const client = Client.forMainnet();
12
13async function createRwaToken() {
14 const adminPrivateKey = "302e..."; // Multi-sig recommended
15 const adminKey = PrivateKey.fromString(adminPrivateKey);
16 const treasuryAccountId = "0.0.12345";
17
18 client.setOperator(treasuryAccountId, adminKey);
19
20 const transaction = await new TokenCreateTransaction()
21 .setTokenName("RWA Property")
22 .setTokenSymbol("RWA-PROP")
23 .setDecimals(6)
24 .setInitialSupply(1000000)
25 .setTreasuryAccountId(treasuryAccountId)
26 .setAdminKey(adminKey.publicKey)
27 .setKycKey(adminKey.publicKey)
28 .setFreezeKey(adminKey.publicKey)
29 .setWipeKey(adminKey.publicKey)
30 .setMemo("Tokenized Real Estate Shares")
31 .freezeWith(client)
32 .sign(adminKey);
33
34 const txResponse = await transaction.execute(client);
35 const receipt = await txResponse.getReceipt(client);
36 return receipt.tokenId.toString();
37}
38
39// Associate Flow
40async function associateRwa(userPrivateKey, userAccountId, tokenId) {
41 const userKey = PrivateKey.fromString(userPrivateKey);
42 client.setOperator(userAccountId, userKey);
43
44 const transaction = await new TokenAssociateTransaction()
45 .setAccountId(userAccountId)
46 .setTokenIds([tokenId])
47 .freezeWith(client)
48 .sign(userKey);
49
50 const txResponse = await transaction.execute(client);
51 await txResponse.getReceipt(client);
52}
53
54// Transfer Flow
55async function transferRwa(
56 senderPrivateKey,
57 senderAccountId,
58 receiverAccountId,
59 tokenId,
60 amount
61) {
62 // Assume associated and KYC granted
63 const senderKey = PrivateKey.fromString(senderPrivateKey);
64 client.setOperator(senderAccountId, senderKey);
65
66 const transaction = await new TokenTransferTransaction()
67 .addTokenTransfer(tokenId, senderAccountId, -amount)
68 .addTokenTransfer(tokenId, receiverAccountId, amount)
69 .freezeWith(client)
70 .sign(senderKey);
71
72 const txResponse = await transaction.execute(client);
73 await txResponse.getReceipt(client);
74}
75
76// Wipe Flow
77async function wipeRwa(
78 adminPrivateKey,
79 treasuryAccountId,
80 tokenId,
81 userAccountId,
82 amount
83) {
84 const adminKey = PrivateKey.fromString(adminPrivateKey);
85 client.setOperator(treasuryAccountId, adminKey);
86
87 const transaction = await new TokenWipeTransaction()
88 .setAccountId(userAccountId)
89 .setTokenId(tokenId)
90 .setAmount(amount)
91 .freezeWith(client)
92 .sign(adminKey);
93
94 const txResponse = await transaction.execute(client);
95 await txResponse.getReceipt(client);
96}
- The creation pins keys at txn time. For RWA tokens, prefer multi-sig admins and link metadata to IPFS for provenance.
- Memos can be extended for custom fields in explorers.
Creation Flow (Admin-Facing)
Admin-level txns call ledger with keys.
1// As above in createRwaToken()
2// Post-creation: Query Token ID from receipt
- Use freezeWith for fee optimization.
- Override with oracle pre-checks (KYC, provenance) and revert early if verification fails.
- For illiquid or async-backed assets, combine creation with provisional supply and oracle finalization to avoid over-issuance.
Transfer Flow
Symmetric to creation, transfer requires associate then updates balances.
1// As in transferRwa()
2// Pre-transfer: Check KYC via getAccountInfo
3const accountInfo = await new AccountInfoQuery()
4 .setAccountId(senderAccountId)
5 .execute(client);
6if (
7 !accountInfo.tokenRelationships.has(tokenId) ||
8 !accountInfo.tokenRelationships.get(tokenId).kycGranted
9) {
10 throw new Error("KYC required");
11}
- Associate-first follows checks-effects-interactions and reduces reentrancy risk (though consensus-atomic).
- For queued transfers, implement scheduled txns to check status and push into a compliance queue.
- Add transfer limits via wipe post-hoc.
Wipe Flow
Default wipes are key-gated; RWA overrides query reasons.
1// As in wipeRwa()
2// Pre-wipe: Oracle query for justification
3// e.g., via Chainlink for compliance flag
- Wipe uses amount for precision.
- Consider a time-bound policy for revocations.
Adding Freeze (Example: Compliance Halt)
Freeze handling keeps execution consistent.
1async function applyFreeze(
2 adminPrivateKey,
3 treasuryAccountId,
4 tokenId,
5 userAccountId,
6 frozen
7) {
8 const adminKey = PrivateKey.fromString(adminPrivateKey);
9 client.setOperator(treasuryAccountId, adminKey);
10
11 const TransactionType = frozen
12 ? TokenFreezeTransaction
13 : TokenUnfreezeTransaction;
14 const transaction = await new TransactionType()
15 .setAccountId(userAccountId)
16 .setTokenId(tokenId)
17 .freezeWith(client)
18 .sign(adminKey);
19
20 const txResponse = await transaction.execute(client);
21 await txResponse.getReceipt(client);
22}
- Keep freeze accounting transparent: Use memos for events and track via Mirror Node API.
- For RWA products, freezes may address regulatory events, document in metadata.

