hedera-dev/hedera-skills

hts-system-contract

Hedera Token Service (HTS) smart contract development.

Voir la source
Document Skill original

Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.

Hedera Token Service (HTS) System Contract

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.

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

Critical: HBAR Payment Required

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
});

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.

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"
);

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");
}

Mintable NFT Collection

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

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");

Response Code Handling

Always check response codes. SUCCESS = 22.

solidity
require(responseCode == HederaResponseCodes.SUCCESS, "Operation failed");

Common codes: See references/response-codes.md

Additional References

du même dépôt

Autres Skills

Tous les Skills
hedera-dev
Communauté

agent-kit-plugin

This skill should be used when the user asks to "create a hedera plugin", "build a hedera agent kit plugin", "extend hedera agent kit", "create custom hedera tools", "add hedera functionality", "write a hedera tool", "implement hedera tool", or needs guidance on Hedera Agent Kit plugin architecture, tool definitions, mutation tools, query tools, or parameter schemas using Zod.

installations
2
GitHub Stars
28
Mis à jour
3 sept.
hedera-dev
Communauté

axelar-gmp

Axelar General Message Passing (GMP) on Hedera. Use when sending or receiving cross-chain contract calls via Axelar Gateway (callContract, payNativeGasForContractCall), building AxelarExecutable receivers, wiring Hedera↔EVM destinations, or separating bridge transport from destination handlers (orchestrated / scheduled flows).

installations
2
GitHub Stars
28
Mis à jour
3 sept.
hedera-dev
Communauté

ccip

Chainlink CCIP Cross-Chain Tokens on Hedera. Use when bridging burn-and-mint CCT between Hedera and EVM, registering TokenAdminRegistry / pools, calling ccipSend with chain selectors, or wiring HTS-backed wrappers (HtsBurnMintERC20) vs vanilla BurnMintERC20. Not for Chainlink Data Feeds / price oracles.

installations
2
GitHub Stars
28
Mis à jour
3 sept.
hedera-dev
Communauté

chainlink-data-feeds

Chainlink Data Feeds on Hedera. Use when reading AggregatorV3 price feeds on Hedera (testnet 296 / mainnet 295), calling latestRoundData, checking round completeness and staleness, or normalizing feed decimals. Not for Chainlink CCIP (cross-chain tokens).

installations
2
GitHub Stars
28
Mis à jour
3 sept.