关于 hedera-token-service
hedera-token-service 是介绍 Hedera Token Service 的 JavaScript SDK 技能,使用 `@hiero-ledger/sdk`。内容涵盖同质化代币与 NFT,以及代币交易、查询、密钥和合规控制。
主要功能
- 01创建同质化代币和 NFT
- 02铸造、销毁与转移代币
- 03将账户关联到代币
- 04执行 KYC、冻结、清除和暂停控制
- 05查询代币与 NFT 详情
- 06配置自定义费用计划
适用场景
- 01创建同质化代币或 NFT 系列
- 02管理代币发行与转账
- 03应用账户级合规控制
- 04查看代币供应量和 NFT 信息
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hedera-dev/ hedera-skills --skill hedera-token-service安装后在 Claude Code 中输入/hedera-token-service确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonspec.jsonreferences/api-reference.mdcustom-fees.md详细介绍
Hedera Token Service (HTS) — JavaScript SDK
HTS 是 Hedera 的原生代币引擎。无需编写智能合约,即可创建和管理同质化代币与 NFT。通过 HTS 创建的代币是网络中的一等实体,内置合规控制(KYC、冻结、清除、暂停)和自定义费用表。
设置
所有导入都来自 @hiero-ledger/sdk。有两种设置模式:
Client + setOperator(直接模式)
import { Client, AccountId, PrivateKey } from "@hiero-ledger/sdk";
const client = Client.forName(process.env.HEDERA_NETWORK)
.setOperator(
AccountId.fromString(process.env.OPERATOR_ID),
PrivateKey.fromStringECDSA(process.env.OPERATOR_KEY),
);
Wallet + LocalProvider(基于签名者)
import { Wallet, LocalProvider } from "@hiero-ledger/sdk";
const provider = new LocalProvider();
const wallet = new Wallet(process.env.OPERATOR_ID, process.env.OPERATOR_KEY, provider);
使用签名者模式时,请使用 freezeWithSigner(wallet)、signWithSigner(wallet)、executeWithSigner(wallet) 和 getReceiptWithSigner(wallet),而不是 freezeWith(client) / execute(client)。
交易生命周期
每笔交易都遵循以下流程:配置 -> 冻结 -> 签名 -> 执行 -> 收据。
const tx = await new SomeTransaction()
.setSomeField(value)
.freezeWith(client); // locks the transaction body
await tx.sign(privateKey); // add signatures (call multiple times for multi-sig)
const response = await tx.execute(client);
const receipt = await response.getReceipt(client);
只需要操作员密钥时,可以跳过显式冻结和签名——execute(client) 会处理这些步骤:
const response = await new SomeTransaction()
.setSomeField(value)
.execute(client);
const receipt = await response.getReceipt(client);
创建代币
同质化代币
import {
TokenCreateTransaction, TokenType, TokenSupplyType,
PrivateKey, Hbar,
} from "@hiero-ledger/sdk";
const supplyKey = PrivateKey.generateECDSA();
const { tokenId } = await (
await new TokenCreateTransaction()
.setTokenName("My Token")
.setTokenSymbol("MTK")
.setDecimals(2)
.setInitialSupply(10000)
.setTreasuryAccountId(operatorId)
.setAdminKey(operatorKey)
.setSupplyKey(supplyKey)
.execute(client)
).getReceipt(client);
NFT(非同质化代币)
NFT 需要使用 TokenType.NonFungibleUnique。它们没有小数位数,也没有初始供应量——创建后需逐个铸造序列号。
const { tokenId: nftId } = await (
await new TokenCreateTransaction()
.setTokenName("My NFT Collection")
.setTokenSymbol("MNFT")
.setTokenType(TokenType.NonFungibleUnique)
.setSupplyType(TokenSupplyType.Finite)
.setMaxSupply(1000)
.setTreasuryAccountId(treasuryId)
.setAdminKey(adminKey)
.setSupplyKey(supplyKey)
.execute(client)
).getReceipt(client);
铸造
import { TokenMintTransaction } from "@hiero-ledger/sdk";
// Fungible — specify amount
await new TokenMintTransaction()
.setTokenId(tokenId)
.setAmount(500)
.execute(client);
// NFT — specify metadata per serial
const { serials } = await (
await new TokenMintTransaction()
.setTokenId(nftId)
.addMetadata(Buffer.from("ipfs://QmFirst..."))
.addMetadata(Buffer.from("ipfs://QmSecond..."))
.execute(client)
).getReceipt(client);
// serials = [Long(1), Long(2)]
代币关联
Hedera 账户必须先与代币关联,才能接收该代币(除非账户通过 setMaxAutomaticTokenAssociations 启用了自动代币关联)。
import { TokenAssociateTransaction } from "@hiero-ledger/sdk";
await (
await (
await new TokenAssociateTransaction()
.setAccountId(recipientId)
.setTokenIds([tokenId])
.freezeWith(client)
).sign(recipientKey) // account owner must sign
).execute(client);
或者,在创建账户时设置 setMaxAutomaticTokenAssociations(-1),以允许无限自动关联。
转账
同质化代币和 NFT 都使用 TransferTransaction。金额带有正负号:负数表示扣款,正数表示入账。每种代币的金额总和必须为零。
import { TransferTransaction } from "@hiero-ledger/sdk";
// Fungible transfer
await new TransferTransaction()
.addTokenTransfer(tokenId, senderId, -100)
.addTokenTransfer(tokenId, receiverId, 100)
.execute(client);
// NFT transfer (tokenId, serial, sender, receiver)
await new TransferTransaction()
.addNftTransfer(nftId, 1, senderId, receiverId)
.execute(client);
// Mix Hbar + token transfers in one transaction
await new TransferTransaction()
.addHbarTransfer(senderId, new Hbar(-5))
.addHbarTransfer(receiverId, new Hbar(5))
.addTokenTransfer(tokenId, senderId, -50)
.addTokenTransfer(tokenId, receiverId, 50)
.execute(client);
密钥角色
每个密钥都是可选的。如果创建时省略某个密钥,相应功能将永久禁用。
| 密钥 | 用途 |
|---|---|
adminKey | 更新或删除代币;轮换其他密钥 |
supplyKey | 铸造和销毁 |
freezeKey | 冻结或解除冻结账户,禁止或允许其转账此代币 |
kycKey | 授予或撤销账户的 KYC 状态 |
wipeKey | 清除账户中的代币余额 |
pauseKey | 全局暂停或恢复所有代币操作 |
feeScheduleKey | 更新自定义费用表 |
metadataKey | 更新代币或 NFT 元数据 |
合规操作
// Grant KYC (required when token has kycKey)
await new TokenGrantKycTransaction()
.setTokenId(tokenId).setAccountId(accountId).execute(client);
// Freeze an account
await new TokenFreezeTransaction()
.setTokenId(tokenId).setAccountId(accountId).execute(client);
// Unfreeze
await new TokenUnfreezeTransaction()
.setTokenId(tokenId).setAccountId(accountId).execute(client);
// Wipe tokens from an account
await new TokenWipeTransaction()
.setTokenId(tokenId).setAccountId(accountId).setAmount(10).execute(client);
// Pause all transfers
await new TokenPauseTransaction().setTokenId(tokenId).execute(client);
// Unpause
await new TokenUnpauseTransaction().setTokenId(tokenId).execute(client);
销毁与删除
import { TokenBurnTransaction, TokenDeleteTransaction } from "@hiero-ledger/sdk";
// Burn fungible
await new TokenBurnTransaction()
.setTokenId(tokenId).setAmount(100).execute(client);
// Burn NFT serials
await new TokenBurnTransaction()
.setTokenId(nftId).setSerials([1, 2]).execute(client);
// Delete entire token (requires adminKey)
await new TokenDeleteTransaction()
.setTokenId(tokenId).execute(client);
查询代币信息
import { TokenInfoQuery, TokenNftInfoQuery, NftId } from "@hiero-ledger/sdk";
const info = await new TokenInfoQuery().setTokenId(tokenId).execute(client);
console.log(info.name, info.symbol, info.totalSupply.toString());
const nftInfo = await new TokenNftInfoQuery()
.setNftId(new NftId(nftId, 1))
.execute(client);
console.log(nftInfo.accountId.toString()); // current owner
空投
空投可向多个接收者分发代币。如果接收者无法自动关联,空投会变为待领取状态,必须由接收者领取。
import {
TokenAirdropTransaction, TokenClaimAirdropTransaction,
TokenCancelAirdropTransaction, TokenRejectTransaction, NftId,
} from "@hiero-ledger/sdk";
// Send airdrop
const record = await (
await (
await new TokenAirdropTransaction()
.addTokenTransfer(tokenId, treasuryId, -300)
.addTokenTransfer(tokenId, recipient1, 100)
.addTokenTransfer(tokenId, recipient2, 100)
.addTokenTransfer(tokenId, recipient3, 100)
.addNftTransfer(nftId, 1, treasuryId, recipient1)
.freezeWith(client)
.sign(treasuryKey)
).execute(client)
).getRecord(client);
// Check pending airdrops
const { newPendingAirdrops } = record;
// Recipient claims a pending airdrop
await (
await new TokenClaimAirdropTransaction()
.addPendingAirdropId(newPendingAirdrops[0].airdropId)
.freezeWith(client)
.sign(recipientKey)
).execute(client);
// Sender cancels a pending airdrop
await new TokenCancelAirdropTransaction()
.addPendingAirdropId(newPendingAirdrops[1].airdropId)
.execute(client);
// Recipient rejects tokens they already received
await (
await new TokenRejectTransaction()
.setOwnerId(recipientId)
.addTokenId(tokenId) // reject fungible
.addNftId(new NftId(nftId, 1)) // reject NFT
.freezeWith(client)
.sign(recipientKey)
).execute(client);
自定义费用
HTS 支持三种费用类型。完整详情请参阅 references/custom-fees.md。
import {
CustomFixedFee, CustomFractionalFee, CustomRoyaltyFee, Hbar,
} from "@hiero-ledger/sdk";
const fixedFee = new CustomFixedFee()
.setFeeCollectorAccountId(collectorId)
.setHbarAmount(new Hbar(1));
const fractionalFee = new CustomFractionalFee()
.setFeeCollectorAccountId(collectorId)
.setNumerator(1).setDenominator(100) // 1%
.setMin(1).setMax(1000);
const royaltyFee = new CustomRoyaltyFee()
.setFeeCollectorAccountId(collectorId)
.setNumerator(5).setDenominator(100) // 5%
.setFallbackFee(
new CustomFixedFee().setHbarAmount(new Hbar(2))
);
await new TokenCreateTransaction()
.setCustomFees([fixedFee, fractionalFee])
// ... other fields
.execute(client);
常见注意事项
-
转账前必须关联:接收者必须先与代币关联,或拥有自动关联名额。否则,转账会因
TOKEN_NOT_ASSOCIATED_TO_ACCOUNT而失败。 -
金额带有正负号:
addTokenTransfer使用带正负号的金额。发送方为负数,接收方为正数。两者总和必须为零。 -
NFT 没有小数位数或初始供应量:设置
TokenType.NonFungibleUnique,并逐个铸造序列号。 -
没有 adminKey 时,密钥不可更改:没有管理密钥,就无法更新或删除代币,也无法更改其他密钥。
-
KYC 门槛:如果代币设置了
kycKey,账户必须先获得 KYC 批准,才能使用该代币进行交易。 -
铸造或销毁需要 supply key:创建时必须设置 supply key,之后才能铸造或销毁。
-
Treasury 自动关联:Treasury 账户会自动与代币关联。
-
多方签名前先冻结:需要多方签名时,先调用
freezeWith(client),再链式调用.sign(key)。
参考文件
references/api-reference.md— 所有 HTS 交易与查询类及其方法的完整列表references/custom-fees.md— 固定费用、分段费用和版税费用的详细指南