hts-system-contract

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hedera Token Service (HTS) System Contract

Hedera Token Service (HTS) 系统合约

HTS precompile at
0x167
enables Solidity contracts to create and manage Hedera-native tokens with built-in compliance controls (KYC, freeze, pause) and custom fees.
位于
0x167
的 HTS 预编译合约支持 Solidity 合约创建和管理 Hedera 原生代币,内置合规控制(KYC、冻结、暂停)和自定义手续费功能。

Quick Reference

快速参考

Imports:
solidity
import {HederaTokenService} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/HederaTokenService.sol";
import {KeyHelper} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/KeyHelper.sol";
import {ExpiryHelper} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/ExpiryHelper.sol";
import {HederaResponseCodes} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/HederaResponseCodes.sol";
Safe variants (auto-revert on failure):
SafeHTS.sol
,
SafeViewHTS.sol
导入:
solidity
import {HederaTokenService} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/HederaTokenService.sol";
import {KeyHelper} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/KeyHelper.sol";
import {ExpiryHelper} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/ExpiryHelper.sol";
import {HederaResponseCodes} from "@hashgraph/smart-contracts/contracts/system-contracts/hedera-token-service/HederaResponseCodes.sol";
安全变体(失败时自动回滚):
SafeHTS.sol
、
SafeViewHTS.sol

Critical: HBAR Payment Required

重要提示:需要支付 HBAR

Token creation requires explicit HBAR value payment (not just gas):
solidity
// ❌ WRONG - fails with INSUFFICIENT_TX_FEE
(int rc, address token) = createNonFungibleToken(token);

// ✅ CORRECT
(int rc, address token) = createNonFungibleToken{value: msg.value}(token);
Call from TypeScript:
typescript
await contract.createToken(name, symbol, {
  gasLimit: 350_000,
  value: ethers.parseEther("15"), // ~$1-2 USD of HBAR
});
创建代币需要显式支付 HBAR 金额(不仅仅是 gas 费):
solidity
// ❌ WRONG - fails with INSUFFICIENT_TX_FEE
(int rc, address token) = createNonFungibleToken(token);

// ✅ CORRECT
(int rc, address token) = createNonFungibleToken{value: msg.value}(token);
TypeScript 调用示例:
typescript
await contract.createToken(name, symbol, {
  gasLimit: 350_000,
  value: ethers.parseEther("15"), // ~$1-2 USD of HBAR
});

Token Key System

代币密钥体系

Seven key types control token operations (bit positions for
keyType
field):
KeyBitValueControls
ADMIN01Update token, keys, deletion
KYC12Grant/revoke KYC
FREEZE24Freeze/unfreeze accounts
WIPE38Wipe balances
SUPPLY416Mint/burn
FEE532Update fees
PAUSE664Pause all operations
Use
KeyHelper
for key construction:
solidity
keys[0] = getSingleKey(KeyType.SUPPLY, KeyValueType.CONTRACT_ID, address(this));
See references/keys.md for key value types and JSON tuple format.
七种密钥类型控制代币操作(
keyType
字段的位位置):
密钥类型位值控制范围
ADMIN01更新代币、密钥、删除代币
KYC12授予/撤销 KYC
FREEZE24冻结/解冻账户
WIPE38擦除余额
SUPPLY416铸造/销毁
FEE532更新手续费
PAUSE664暂停所有操作
使用
KeyHelper
构建密钥:
solidity
keys[0] = getSingleKey(KeyType.SUPPLY, KeyValueType.CONTRACT_ID, address(this));
有关密钥值类型和 JSON 元组格式,请参阅 references/keys.md。

Association Model

关联模型

Accounts must associate with tokens before receiving them:
solidity
int rc = associateToken(accountAddress, tokenAddress);
require(
    rc == HederaResponseCodes.SUCCESS ||
    rc == HederaResponseCodes.TOKEN_ALREADY_ASSOCIATED_TO_ACCOUNT,
    "Association failed"
);
账户在接收代币前必须先与代币建立关联:
solidity
int rc = associateToken(accountAddress, tokenAddress);
require(
    rc == HederaResponseCodes.SUCCESS ||
    rc == HederaResponseCodes.TOKEN_ALREADY_ASSOCIATED_TO_ACCOUNT,
    "Association failed"
);

Common Patterns

常用模式

Fungible Token Creation

同质化代币创建

solidity
function createToken() external payable {
    IHederaTokenService.HederaToken memory token;
    token.name = "My Token";
    token.symbol = "MTK";
    token.treasury = address(this);
    token.expiry = createAutoRenewExpiry(address(this), 7776000); // 90 days

    (int rc, address created) = createFungibleToken{value: msg.value}(
        token, 1000000, 18  // initialSupply, decimals
    );
    require(rc == HederaResponseCodes.SUCCESS, "Create failed");
}
solidity
function createToken() external payable {
    IHederaTokenService.HederaToken memory token;
    token.name = "My Token";
    token.symbol = "MTK";
    token.treasury = address(this);
    token.expiry = createAutoRenewExpiry(address(this), 7776000); // 90 days

    (int rc, address created) = createFungibleToken{value: msg.value}(
        token, 1000000, 18  // initialSupply, decimals
    );
    require(rc == HederaResponseCodes.SUCCESS, "Create failed");
}

Mintable NFT Collection

可铸造 NFT 集合

solidity
function createNFT() external payable {
    IHederaTokenService.HederaToken memory token;
    token.name = "My NFT";
    token.symbol = "MNFT";
    token.treasury = address(this);
    token.tokenSupplyType = true;  // FINITE
    token.maxSupply = 10000;

    IHederaTokenService.TokenKey[] memory keys = new IHederaTokenService.TokenKey[](1);
    keys[0] = getSingleKey(KeyType.SUPPLY, KeyValueType.CONTRACT_ID, address(this));
    token.tokenKeys = keys;
    token.expiry = createAutoRenewExpiry(address(this), 7776000);

    (int rc, address created) = createNonFungibleToken{value: msg.value}(token);
    require(rc == HederaResponseCodes.SUCCESS, "Create failed");
}

function mintNFT(bytes memory metadata) external {
    bytes[] memory metas = new bytes[](1);
    metas[0] = metadata;
    (int rc, , int64[] memory serials) = mintToken(tokenAddress, 0, metas);
    require(rc == HederaResponseCodes.SUCCESS, "Mint failed");
}
solidity
function createNFT() external payable {
    IHederaTokenService.HederaToken memory token;
    token.name = "My NFT";
    token.symbol = "MNFT";
    token.treasury = address(this);
    token.tokenSupplyType = true;  // FINITE
    token.maxSupply = 10000;

    IHederaTokenService.TokenKey[] memory keys = new IHederaTokenService.TokenKey[](1);
    keys[0] = getSingleKey(KeyType.SUPPLY, KeyValueType.CONTRACT_ID, address(this));
    token.tokenKeys = keys;
    token.expiry = createAutoRenewExpiry(address(this), 7776000);

    (int rc, address created) = createNonFungibleToken{value: msg.value}(token);
    require(rc == HederaResponseCodes.SUCCESS, "Create failed");
}

function mintNFT(bytes memory metadata) external {
    bytes[] memory metas = new bytes[](1);
    metas[0] = metadata;
    (int rc, , int64[] memory serials) = mintToken(tokenAddress, 0, metas);
    require(rc == HederaResponseCodes.SUCCESS, "Mint failed");
}

KYC-Enabled Token

启用 KYC 的代币

Treasury must self-grant KYC after creation:
solidity
// After token creation with KYC key
int kycRc = grantTokenKyc(tokenAddress, address(this));
require(kycRc == HederaResponseCodes.SUCCESS, "Self-KYC failed");
金库地址必须在代币创建后为自身授予 KYC 权限:
solidity
// After token creation with KYC key
int kycRc = grantTokenKyc(tokenAddress, address(this));
require(kycRc == HederaResponseCodes.SUCCESS, "Self-KYC failed");

Response Code Handling

响应码处理

Always check response codes. SUCCESS = 22.
solidity
require(responseCode == HederaResponseCodes.SUCCESS, "Operation failed");
Common codes: See references/response-codes.md
始终检查响应码。SUCCESS = 22。
solidity
require(responseCode == HederaResponseCodes.SUCCESS, "Operation failed");
常用响应码:请参阅 references/response-codes.md

Additional References

更多参考资料

  • API Reference: references/api.md - All function signatures
  • Custom Fees: references/fees.md - Fixed, fractional, royalty fees
  • Compliance Controls: references/compliance.md - KYC, freeze, pause details
  • Struct Definitions: references/structs.md - HederaToken, Expiry, etc.
  • Troubleshooting: references/troubleshooting.md - Common errors and fixes
  • API 参考:references/api.md - 所有函数签名
  • 自定义手续费:references/fees.md - 固定手续费、分级手续费、版税手续费
  • 合规控制:references/compliance.md - KYC、冻结、暂停详情
  • 结构体定义:references/structs.md - HederaToken、Expiry 等
  • 故障排查:references/troubleshooting.md - 常见错误及修复方法