hedera-token-service について
hedera-token-serviceは、`@hiero-ledger/sdk`を使うHedera Token Service向けJavaScript SDKのスキルです。ファンジブルトークンとNFT、取引、クエリ、キー、コンプライアンス制御を扱います。
主な機能
- 01ファンジブルトークンとNFTの作成
- 02トークンのミント、バーン、転送
- 03アカウントとトークンの関連付け
- 04KYC、凍結、ワイプ、一時停止制御
- 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 ネイティブのトークンエンジンです。スマートコントラクトを書かずに、代替性トークン(fungible token)や NFT を作成・管理できます。HTS を通じて作成されたトークンは、組み込みのコンプライアンス制御(KYC、フリーズ、ワイプ、一時停止)とカスタム手数料スケジュールを備えた、ファーストクラスのネットワークエンティティです。
セットアップ
すべてのインポートは @hiero-ledger/sdk から行います。セットアップのパターンは 2 つあります。
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);
署名者パターンでは、freezeWith(client) / execute(client) の代わりに、freezeWithSigner(wallet)、signWithSigner(wallet)、executeWithSigner(wallet)、getReceiptWithSigner(wallet) を使用します。
トランザクションのライフサイクル
すべてのトランザクションは次の流れに従います: configure -> freeze -> sign -> execute -> receipt。
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);
オペレーターキーのみが必要な場合は、明示的な freeze/sign を省略できます — execute(client) が処理します。
const response = await new SomeTransaction()
.setSomeField(value)
.execute(client);
const receipt = await response.getReceipt(client);
トークンの作成
代替性トークン(Fungible Token)
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 が必要です。NFT には小数桁がなく、初期供給量もありません — 作成後に個別のシリアルをミントします。
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 アカウントは、トークンを受け取る前にそのトークンに関連付け(associate)する必要があります(アカウントで 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
エアドロップ
エアドロップはトークンを複数の受信者に配布します。受信者が自動関連付けできない場合、エアドロップは保留中(pending)になり、請求(claim)する必要があります。
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 は 3 種類の手数料をサポートしています。詳細は 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 承認を受ける必要があります。 -
ミント/バーンには供給キー: 後でミントまたはバーンを行うには、作成時に供給キーが設定されている必要があります。
-
トレジャリーの自動関連付け: トレジャリーアカウントはトークンに自動的に関連付けられます。
-
マルチシグ前のフリーズ: 複数の当事者が署名する必要がある場合、まず
freezeWith(client)を呼び出し、その後.sign(key)呼び出しをチェーンします。
参照ファイル
references/api-reference.md— すべての HTS トランザクションおよびクエリクラスとそのメソッドの完全なリストreferences/custom-fees.md— 固定手数料、割合手数料、ロイヤルティ手数料の詳細ガイド