Hedera Token Service: Fungible Tokens, Stablecoins, and Governance
In the previous article I covered Hedera NFTs. Today we go deeper into fungible tokens – the backbone of DeFi, loyalty programmes, governance systems, and stablecoins.
The Hedera Token Service (HTS) handles all of this natively at the protocol level. No ERC-20 contract. No gas spikes. No MEV.
What Can You Build?
- Utility tokens – in-app currency, credits, access passes
- Governance tokens – weighted voting for DAOs
- Stablecoins – pegged to USD, EUR, or any asset
- Reward tokens – loyalty points, cashback
- Wrapped assets – bridged versions of other chain tokens
Creating a Fungible Token
import {
Client,
AccountId,
PrivateKey,
TokenCreateTransaction,
TokenType,
TokenSupplyType,
Hbar,
} from "@hashgraph/sdk";
const client = Client.forTestnet();
client.setOperator(
AccountId.fromString(process.env.OPERATOR_ID),
PrivateKey.fromStringECDSA(process.env.OPERATOR_KEY),
);
const createToken = await new TokenCreateTransaction()
.setTokenName("MrBns Reward Token")
.setTokenSymbol("MRT")
.setTokenType(TokenType.FungibleCommon) // fungible (ERC-20 equivalent)
.setDecimals(8) // like HBAR / Bitcoin
.setInitialSupply(1_000_000_00000000) // 1,000,000 tokens (8 decimals)
.setSupplyType(TokenSupplyType.Infinite) // or Finite with setMaxSupply
.setTreasuryAccountId(AccountId.fromString(process.env.OPERATOR_ID))
.setSupplyKey(PrivateKey.fromStringECDSA(process.env.OPERATOR_KEY))
.setAdminKey(PrivateKey.fromStringECDSA(process.env.OPERATOR_KEY))
.setFreezeKey(PrivateKey.fromStringECDSA(process.env.OPERATOR_KEY)) // optional
.setWipeKey(PrivateKey.fromStringECDSA(process.env.OPERATOR_KEY)) // optional
.execute(client);
const receipt = await createToken.getReceipt(client);
const tokenId = receipt.tokenId;
console.log(`Token created: ${tokenId}`);
Token Keys Explained
HTS gives you granular key-based access control – a huge advantage over ERC-20 contracts:
| Key | Purpose |
|---|---|
adminKey | Update token properties, delete token |
supplyKey | Mint or burn tokens |
freezeKey | Freeze/unfreeze an account’s token balance |
wipeKey | Wipe (zero out) a frozen account’s balance |
kycKey | Mark accounts as KYC-verified |
pauseKey | Pause all transfers globally |
feeScheduleKey | Update custom fee schedules |
For a decentralised DAO governance token, you would typically set no admin or freeze keys after deployment to prove immutability.
Minting Additional Supply
import { TokenMintTransaction } from "@hashgraph/sdk";
const mint = await new TokenMintTransaction()
.setTokenId(tokenId)
.setAmount(500_00000000) // mint 500 more tokens
.execute(client);
console.log(`New total supply: ${(await mint.getReceipt(client)).totalSupply}`);
Burning Tokens (Deflationary Mechanics)
import { TokenBurnTransaction } from "@hashgraph/sdk";
await new TokenBurnTransaction()
.setTokenId(tokenId)
.setAmount(100_00000000) // burn 100 tokens
.execute(client);
Burning tokens reduces total supply permanently – useful for buy-back-and-burn mechanics.
Distributing Tokens (Airdrop)
import { TransferTransaction } from "@hashgraph/sdk";
const airdrop = new TransferTransaction();
const recipients = [
{ id: "0.0.111111", amount: 100_00000000 },
{ id: "0.0.222222", amount: 200_00000000 },
{ id: "0.0.333333", amount: 50_00000000 },
];
// debit treasury
const total = recipients.reduce((s, r) => s + r.amount, 0);
airdrop.addTokenTransfer(tokenId, operatorId, -total);
// credit recipients (they must have associated first)
for (const r of recipients) {
airdrop.addTokenTransfer(tokenId, AccountId.fromString(r.id), r.amount);
}
await airdrop.execute(client);
console.log("Airdrop complete");
All transfers in a single TransferTransaction are atomic – either all succeed or all fail. No partial airdrops.
Custom Fees: Built-in Royalties
HTS supports custom fee schedules at the protocol level – no smart contract logic needed:
import { CustomFixedFee, CustomFractionalFee } from "@hashgraph/sdk";
// Fixed fee: 1 HBAR on every transfer
const fixedFee = new CustomFixedFee()
.setHbarAmount(new Hbar(1))
.setFeeCollectorAccountId(operatorId);
// Fractional fee: 2% of transfer amount to fee collector
const fractionalFee = new CustomFractionalFee()
.setNumerator(2)
.setDenominator(100)
.setFeeCollectorAccountId(operatorId);
const tokenWithFees = await new TokenCreateTransaction()
.setTokenName("MrBns Fee Token")
.setTokenSymbol("MFT")
.setTokenType(TokenType.FungibleCommon)
.setDecimals(2)
.setInitialSupply(1_000_000_00)
.setTreasuryAccountId(operatorId)
.setSupplyKey(operatorKey)
.setCustomFees([fixedFee, fractionalFee]) // ← attach fees at creation
.execute(client);
Every transfer of this token automatically routes fees to the collector – no contract, no hook, no gas estimation.
Querying Token Info via Mirror Node
The Hedera mirror node REST API lets you query token state without running a full node:
const res = await fetch(
`https://testnet.mirrornode.hedera.com/api/v1/tokens/${tokenId}`,
);
const info = await res.json();
console.log({
name: info.name,
symbol: info.symbol,
totalSupply: info.total_supply,
decimals: info.decimals,
});
For account balances:
const balRes = await fetch(
`https://testnet.mirrornode.hedera.com/api/v1/accounts/${accountId}/tokens`,
);
const { tokens } = await balRes.json();
const mrt = tokens.find((t) => t.token_id === tokenId.toString());
console.log(`Balance: ${mrt?.balance ?? 0}`);
Pause and Freeze: Compliance Controls
For regulated tokens (e-money, securities), HTS offers protocol-level compliance:
import { TokenPauseTransaction, TokenFreezeTransaction } from "@hashgraph/sdk";
// pause ALL transfers globally
await new TokenPauseTransaction().setTokenId(tokenId).execute(client);
// freeze a specific account (cannot send or receive)
await new TokenFreezeTransaction()
.setTokenId(tokenId)
.setAccountId(suspiciousAccount)
.execute(client);
These are irreversible on-chain actions (unless you have the matching unfreeze/unpause key). Perfect for AML/KYC compliance without extra infrastructure.
Summary
The Hedera Token Service is the most feature-rich native token system in the industry. As a Blockchain Full Stack Developer (MrBns / Mr Binary Sniper), I reach for HTS when clients need:
- Predictable sub-cent fees
- Protocol-level compliance controls (freeze, wipe, pause)
- Built-in royalty / fee schedules
- Atomic multi-party transfers
- Fast finality for user-facing applications
Whether you are building a loyalty programme, a DAO governance token, or a regulated digital asset, HTS removes the complexity and cost of smart contract development while giving you more control.
Next steps: explore Hedera Smart Contract Service (HSCS) for cases where you need custom EVM logic on top of the Hedera network.