Complete token management plugin for the Hiero CLI following the plugin architecture.
This plugin follows the plugin architecture principles:
- Stateless: Plugin is functionally stateless
- Dependency Injection: Services are injected into command handlers
- Manifest-Driven: Capabilities declared via manifest with output specifications
- Namespace Isolation: Own state namespace (
token-tokens) - Type Safety: Full TypeScript support
- Structured Output: All command handlers return
CommandResultwith standardized output
src/plugins/token/
βββ manifest.ts # Plugin manifest with command definitions and output specs
βββ schema.ts # Token data schema with Zod validation
βββ commands/
β βββ create-ft/
β β βββ handler.ts # Fungible token creation handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ create-nft/
β β βββ handler.ts # Non-fungible token creation handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ create-ft-from-file/
β β βββ handler.ts # Fungible token from file handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ burn-ft/
β βββ burn-nft/
β β βββ handler.ts # Fungible token burn handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ mint-ft/
β β βββ handler.ts # Fungible token minting handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ mint-nft/
β β βββ handler.ts # Non-fungible token minting handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ update-metadata-nft/
β β βββ handler.ts # NFT metadata update handler (metadata key)
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ airdrop-ft/
β β βββ handler.ts # Fungible token airdrop handler (multi-recipient)
β β βββ input.ts # Input schema with REPEATABLE --to/--amount
β β βββ output.ts # Output schema and template
β β βββ types.ts # Command-specific type definitions
β β βββ index.ts # Command exports
β βββ transfer-ft/
β β βββ handler.ts # Fungible token transfer handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ transfer-nft/
β β βββ handler.ts # NFT transfer handler
β β βββ input.ts # Input validation schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ airdrop-nft/
β β βββ handler.ts # NFT airdrop handler (multi-recipient)
β β βββ input.ts # Input schema with REPEATABLE --to/--serials
β β βββ output.ts # Output schema and template
β β βββ types.ts # Command-specific type definitions
β β βββ index.ts # Command exports
β βββ cancel-airdrop/
β β βββ handler.ts # Cancel pending airdrop handler (FT and NFT)
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ types.ts # Command-specific type definitions
β β βββ index.ts # Command exports
β βββ associate/
β β βββ handler.ts # Token association handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ dissociate/
β β βββ handler.ts # Token dissociation handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ types.ts # Command-specific type definitions
β β βββ index.ts # Command exports
β βββ allowance-ft/
β β βββ handler.ts # Fungible token allowance handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ types.ts # Internal types
β β βββ index.ts # Command exports
β βββ delete/
β β βββ handler.ts # Token delete handler (network or local state)
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ update/
β β βββ handler.ts # Unified token update handler (FT and NFT)
β β βββ input.ts # Input schema with nullable role-key fields
β β βββ output.ts # Output schema and template
β β βββ types.ts # TokenUpdateNormalizedParams and result types
β β βββ index.ts # Command exports
β βββ allowance-nft/
β β βββ handler.ts # NFT allowance approval handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ types.ts # Command-specific type definitions
β β βββ index.ts # Command exports
β βββ delete-allowance-nft/
β β βββ handler.ts # NFT allowance deletion handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ types.ts # Command-specific type definitions
β β βββ index.ts # Command exports
β βββ list/
β β βββ handler.ts # Token list handler
β β βββ input.ts # Input schema
β β βββ output.ts # Output schema and template
β β βββ index.ts # Command exports
β βββ view/
β βββ handler.ts # Token view handler
β βββ input.ts # Input schema
β βββ output.ts # Output schema and template
β βββ index.ts # Command exports
βββ hooks/
β βββ batch-create-ft/
β β βββ handler.ts # TokenCreateFtBatchStateHook - persists FT state after batch execution
β β βββ types.ts # CreateFtNormalisedParamsSchema for batch item validation
β β βββ index.ts # Hook exports
β βββ batch-create-nft/
β β βββ handler.ts # TokenCreateNftBatchStateHook - persists NFT state after batch execution
β β βββ types.ts # CreateNftNormalisedParamsSchema for batch item validation
β β βββ index.ts # Hook exports
β βββ batch-create-ft-from-file/
β β βββ handler.ts # TokenCreateFtFromFileBatchStateHook - persists FT-from-file state after batch execution
β β βββ types.ts # CreateFtFromFileNormalisedParamsSchema for batch item validation
β β βββ index.ts # Hook exports
β βββ batch-create-nft-from-file/
β β βββ handler.ts # TokenCreateNftFromFileBatchStateHook - persists NFT-from-file state after batch execution
β β βββ types.ts # CreateNftFromFileNormalisedParamsSchema for batch item validation
β β βββ index.ts # Hook exports
β βββ batch-associate/
β β βββ handler.ts # TokenAssociateBatchStateHook - persists association results after batch execution
β β βββ types.ts # AssociateNormalisedParamsSchema for batch item validation
β β βββ index.ts # Hook exports
β βββ token-update-state/
β β βββ handler.ts # TokenUpdateStateHook - persists updated token data after batch execution
β β βββ types.ts # TokenUpdateNormalisedParamsSchema for batch item validation
β β βββ index.ts # Hook exports
β βββ token-dissociate-state/
β βββ handler.ts # TokenDissociateStateHook - removes association from state after batch execution
β βββ types.ts # DissociateNormalizedParamsSchema for batch item validation
βββ utils/
β βββ token-build-output.ts # NFT output builder utilities
β βββ token-amount-helpers.ts # Token amount processing helpers
β βββ token-data-builders.ts # Token data builders for create-from-file and update commands
β βββ token-associations.ts # Token association processing
β βββ [other utility files...]
βββ zustand-state-helper.ts # State management helper
βββ resolver-helper.ts # Token and account resolver utilities
βββ __tests__/ # Comprehensive test suite
β βββ unit/
β β βββ adr007-compliance.test.ts # Output structure compliance tests
β β βββ batch-create-ft.test.ts
β β βββ batch-create-nft.test.ts
β β βββ batch-create-ft-from-file.test.ts
β β βββ batch-create-nft-from-file.test.ts
β β βββ [other test files...]
β βββ integration/
β βββ [integration test files...]
βββ index.ts # Plugin exports
All commands return CommandResult with structured output data in the result field. Errors are thrown as typed CliError instances and handled uniformly by the core framework.
Each command defines a Zod schema for output validation and a Handlebars template for human-readable formatting.
Create a new fungible token with specified properties.
# Using account alias
hcli token create-ft \
--token-name "My Token" \
--symbol "MTK" \
--treasury alice \
--decimals 2 \
--initial-supply 1000 \
--supply-type FINITE \
--max-supply 10000 \
--admin-key admin-public-key \
--name mytoken-alias
# Using treasury-id:treasury-key pair
hcli token create-ft \
--token-name "My Token" \
--symbol "MTK" \
--treasury 0.0.123456:302e020100300506032b657004220420... \
--decimals 2 \
--initial-supply 1000 \
--supply-type INFINITE \
--name mytoken-aliasAuto-renew and expiration (optional):
--auto-renew-period/-R: Auto-renew interval. A plain integer is seconds (e.g.500). You may use a suffix:s(seconds),m(minutes),h(hours),d(days), e.g.500s,50m,2h,1d. Requires--auto-renew-account; if the period is set without an account, validation fails.--auto-renew-account/-r: Account that pays for auto-renewal (same accepted formats as--treasury: alias,accountId:privateKey, key reference, etc.).--expiration-time/-x: Fixed expiration as an ISO 8601 datetime (e.g.2030-12-31T23:59:59.000Z). If both auto-renew period and account are set, expiration is ignored and a warning is logged (auto-renew takes precedence).
Command output includes optional autoRenewPeriodSeconds, autoRenewAccountId, and expirationTime (ISO string when a fixed expiration was applied).
# Auto-renew every 30 days, paid by a dedicated account
hcli token create-ft \
--token-name "My Token" \
--symbol "MTK" \
--auto-renew-period 30d \
--auto-renew-account 0.0.789012:302e020100300506032b657004220420...Batch support: Pass --batch <batch-name> to add token creation to a batch instead of executing immediately. See the Batch Support section.
Create a new non-fungible token (NFT) collection with specified properties.
# Using account alias
hcli token create-nft \
--token-name "My NFT Collection" \
--symbol "MNFT" \
--treasury alice \
--supply-type FINITE \
--max-supply 1000 \
--admin-key alice \
--supply-key alice \
--freeze-key alice \
--wipe-key alice \
--name my-nft-collection
# With additional optional keys and settings
hcli token create-nft \
--token-name "My Collection" \
--symbol "MC" \
--treasury 0.0.123456:302e020100300506032b657004220420... \
--supply-type INFINITE \
--admin-key alice \
--supply-key alice \
--kyc-key alice \
--pause-key alice \
--fee-schedule-key alice \
--metadata-key alice \
--auto-renew-period 7776000 \
--auto-renew-account-id 0.0.123456 \
--freeze-default false \
--name my-collectionParameters:
--token-name/-T: Token name - Required--symbol/-s: Token symbol/ticker - Required--treasury: Treasury account for the NFT collection - Optional (defaults to operator)- Account alias:
alice - Account with key:
0.0.123456:private-key
- Account alias:
--supply-type: Supply type - Optional (defaults toINFINITE)INFINITE- Unlimited supplyFINITE- Fixed maximum supply (requires--max-supply)
--max-supply: Maximum number of NFTs in collection (required for FINITE) - Optional--admin-key: Admin key for administrative operations - Optional--supply-key: Supply key for minting NFTs - Optional--freeze-key: Freeze key to freeze token transfers for accounts - Optional--wipe-key: Wipe key to wipe token balances - Optional--kyc-key: KYC key to grant/revoke KYC status - Optional--pause-key: Pause key to pause all token transfers - Optional--fee-schedule-key: Fee schedule key to modify custom fees - Optional--metadata-key: Metadata key to update token metadata - Optional--freeze-default: Default freeze status for new associations (requires--freeze-key) - Optional (defaults to false)--auto-renew-period: Token auto-renewal period in seconds (e.g., 7776000 for 90 days) - Optional--auto-renew-account-id: Account ID that pays for token auto-renewal fees - Optional--expiration-time: Token expiration time in ISO 8601 format (e.g., 2027-01-01T00:00:00Z) - Optional--name: Token alias to register - Optional--key-manager: Key manager type - Optional (defaults to config setting)localorlocal_encrypted
--memo: Optional memo for the token (max 100 characters) - Optional--batch: Add to batch instead of executing immediately - Optional
Output:
{
"tokenId": "0.0.123456",
"name": "My NFT Collection",
"symbol": "MNFT",
"treasuryId": "0.0.111",
"supplyType": "FINITE",
"transactionId": "0.0.123@1700000000.123456789",
"adminPublicKey": "302e020100300506032b657004220420...",
"supplyPublicKey": "302e020100300506032b657004220420...",
"freezePublicKey": "302e020100300506032b657004220420...",
"wipePublicKey": "302e020100300506032b657004220420...",
"kycPublicKey": "302e020100300506032b657004220420...",
"pausePublicKey": "302e020100300506032b657004220420...",
"feeSchedulePublicKey": "302e020100300506032b657004220420...",
"metadataPublicKey": "302e020100300506032b657004220420...",
"network": "testnet"
}Notes:
- NFTs are non-fungible, meaning each NFT is unique and tracked by serial number
- No decimals field applies to NFTs
- Use
mint-nftcommand to mint individual NFTs to the collection - Token name is automatically registered as an alias after successful creation
- Freeze default requires freeze key to be set
Batch support: Pass --batch <batch-name> to add NFT collection creation to a batch instead of executing immediately. See the Batch Support section.
Burn fungible tokens from the token's Treasury account to decrease total supply. Requires the supply key.
# Using token alias
hcli token burn-ft \
--token mytoken-alias \
--amount 1000 \
--supply-key 0.0.123456:302e020100300506032b657004220420...
# Using token ID with base units (t suffix)
hcli token burn-ft \
--token 0.0.123456 \
--amount 5000t \
--supply-key 0.0.123456:302e020100300506032b657004220420...
# Using an account alias for supply key
hcli token burn-ft \
--token 0.0.123456 \
--amount 500 \
--supply-key supply-account-aliasParameters:
--token/-T: Token identifier (alias or token ID) - Required--amount/-a: Amount to burn - Required- Display units (default):
100(will be multiplied by token decimals) - Base units:
100t(raw amount without decimals)
- Display units (default):
--supply-key/-s: Supply key for signing - Optional (if omitted, resolved from key manager by matching the token's on-chain key)- Account alias:
supply-account-alias - Account with key:
0.0.123456:private-key
- Account alias:
--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Note: The burn amount cannot exceed the token's current total supply. Tokens can only be burned from the treasury account.
Batch support: Pass --batch <batch-name> to add to a batch. See the Batch Support section.
Burn NFT serial numbers to decrease total supply. NFTs must be held by the treasury account.
# Burn a single serial
hcli token burn-nft \
--token my-nft-collection \
--serials 1 \
--supply-key 0.0.123456:302e020100300506032b657004220420...
# Burn multiple serials at once
hcli token burn-nft \
--token 0.0.123456 \
--serials 1,2,3 \
--supply-key 0.0.123456:302e020100300506032b657004220420...
# Using an account alias for supply key
hcli token burn-nft \
--token 0.0.123456 \
--serials 5,10 \
--supply-key supply-account-aliasParameters:
--token/-T: Token identifier (alias or token ID) - Required--serials/-s: Comma-separated serial numbers to burn (max 10) - Required--supply-key/-S: Supply key for signing - Optional (if omitted, resolved from key manager by matching the token's on-chain key)- Account alias:
supply-account-alias - Account with key:
0.0.123456:private-key
- Account alias:
--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Note: NFTs must be held by the treasury account. Burning NFTs not in treasury will fail with an SDK error.
Batch support: Pass --batch <batch-name> to add to a batch. See the Batch Support section.
Mint additional fungible tokens to increase supply. Tokens are minted to the token's treasury account.
# Using token alias
hcli token mint-ft \
--token mytoken-alias \
--amount 1000 \
--supply-key 0.0.123456:302e020100300506032b657004220420...
# Using token ID with account alias for supply key
hcli token mint-ft \
--token 0.0.123456 \
--amount 500t \
--supply-key supply-account-alias
# Using base units (t suffix)
hcli token mint-ft \
--token 0.0.123456 \
--amount 5000t \
--supply-key 0.0.123456:302e020100300506032b657004220420...Parameters:
--token/-T: Token identifier (alias or token ID) - Required--amount/-a: Amount to mint - Required- Display units (default):
100(will be multiplied by token decimals) - Base units:
100t(raw amount without decimals)
- Display units (default):
--supply-key/-s: Supply key credential(s) for signing - Optional if every required on-chain supply public key already has matching material in the key manager (otherwise pass explicit credential(s))- Repeatable: pass
--supply-keymultiple times when the tokenβs on-chain supply key is a KeyList or threshold key and you need more than one distinct signer - Account alias:
supply-account-alias - Account with key:
0.0.123456:private-key
- Repeatable: pass
--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Note: The token must have a supply key configured. Minted tokens are added to the token's treasury account.
Mint a new non-fungible token (NFT) to an NFT collection. Each mint operation creates a single NFT with unique metadata and serial number.
# Using token alias
hcli token mint-nft \
--token my-nft-collection \
--metadata "My NFT Metadata" \
--supply-key 0.0.123456:302e020100300506032b657004220420...
# Using token ID with account alias for supply key
hcli token mint-nft \
--token 0.0.123456 \
--metadata "Unique NFT #1" \
--supply-key supply-account-alias
# Using account-id:private-key pair for supply key
hcli token mint-nft \
--token 0.0.123456 \
--metadata "Test NFT" \
--supply-key 0.0.123456:302e020100300506032b657004220420...Parameters:
--token/-T: Token identifier (alias or token ID) - Required- Must be an NFT collection (type:
NON_FUNGIBLE_TOKEN)
- Must be an NFT collection (type:
--metadata/-m: NFT metadata string - Required- Maximum size: 100 bytes
- UTF-8 encoded string
--supply-key/-s: Supply key credential(s) for signing - Optional if every required on-chain supply public key already has matching material in the key manager (otherwise pass explicit credential(s))- Repeatable: pass
--supply-keymultiple times when the tokenβs on-chain supply key is a KeyList or threshold key and you need more than one distinct signer - Account alias:
supply-account-alias - Account with key:
0.0.123456:private-key
- Repeatable: pass
--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Output:
The command returns the minted NFT's serial number, which uniquely identifies the NFT within the collection:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"serialNumber": "1",
"network": "testnet"
}Notes:
- The token must be an NFT collection (created with
create-nftcommand) - The token must have a supply key configured
- When using
--supply-key, provide enough credentials to satisfy the on-chain supply key policy (including M-of-N threshold keys) - Metadata cannot exceed 100 bytes (Hedera limit)
- For tokens with finite supply, the command validates that minting won't exceed
maxSupply - Minted NFT is assigned to the token's treasury account
- Each mint operation creates exactly one NFT with a unique serial number
Example Workflow:
# 1. Create NFT collection
hcli token create-nft \
--token-name "My Collection" \
--symbol "MC" \
--treasury alice \
--supply-type FINITE \
--max-supply 100 \
--admin-key alice \
--supply-key alice \
--name my-collection
# 2. Mint NFT to collection
hcli token mint-nft \
--token my-collection \
--metadata "First NFT in collection" \
--supply-key alice
# 3. View minted NFT
hcli token view --token my-collection --serial 1Update on-chain metadata for one or more NFTs in a collection by serial number. The token must have a metadata key set at creation time; that key must sign the transaction (see Hedera: Update NFT metadata).
# Single serial
hcli token update-metadata-nft \
--token my-nft-collection \
--serials 1 \
--metadata "ipfs://QmNew..."
# Multiple serials (comma-separated, max 10 per transaction)
hcli token update-metadata-nft \
--token 0.0.123456 \
--serials 1,2,3 \
--metadata "updated-uri"
# Explicit metadata key (optional if KMS resolves the on-chain metadata key)
hcli token update-metadata-nft \
--token my-nft-collection \
--serials 1 \
--metadata "new metadata" \
--metadata-key 0.0.123456:302e020100300506032b657004220420...Parameters:
--token/-T: Token identifier (alias or token ID) - Required- Must be an NFT collection
--serials/-s: Comma-separated serial numbers to update (max 10) - Required--metadata/-m: New metadata string - Required (max 100 bytes UTF-8)--metadata-key/-M: Metadata key credential(s) - Optional (if omitted, resolved from the key manager to match the tokenβs on-chain metadata key). Repeatable for KeyList / threshold keys--key-manager/-k: Key manager type - Optional (defaults to config setting)
Output:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"serialNumbers": [1, 2, 3],
"network": "testnet"
}Notes:
- If the token has no metadata key, the command fails with a clear validation error.
- Batch support: Pass
--batch <batch-name>to add the update to a batch (same pattern asmint-nft).
Approve a spender to transfer NFTs on behalf of the owner. This command creates an AccountAllowanceApproveTransaction that grants permission to a spender account to transfer specific or all NFT serials from the owner's account.
# Approve specific serial numbers
hcli token allowance-nft \
--token mynft-alias \
--spender bob \
--owner alice \
--serials 1,2,3
# Approve all serials in the collection
hcli token allowance-nft \
--token mynft-alias \
--spender bob \
--owner alice \
--all-serials
# Owner defaults to operator
hcli token allowance-nft \
--token mynft-alias \
--spender 0.0.222222 \
--serials 1,5,10
# Using account-id:private-key pair for owner
hcli token allowance-nft \
--token 0.0.123456 \
--spender bob \
--owner 0.0.111111:302e020100300506032b657004220420... \
--all-serialsParameters:
--token/-T: NFT token identifier (alias or token ID) - Required- Must be an NFT collection (type:
NON_FUNGIBLE_UNIQUE)
- Must be an NFT collection (type:
--spender/-s: Spender account (ID, EVM address, or alias) - Required- Account that will be granted permission to transfer NFTs
--owner/-o: Owner account - Optional (defaults to operator)- Accepts any key format
- Account ID only:
0.0.111111 - Account with key:
0.0.111111:private-key - Account alias:
alice
--serials: Specific NFT serial numbers to approve (comma-separated, e.g.,1,2,3) - Optional- Mutually exclusive with
--all-serials
- Mutually exclusive with
--all-serials: Approve all serials in the collection - Optional- Mutually exclusive with
--serials - One of
--serialsor--all-serialsmust be specified
- Mutually exclusive with
--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Output:
The command returns the transaction details and approval confirmation:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"ownerAccountId": "0.0.111111",
"spenderAccountId": "0.0.222222",
"serials": [1, 2, 3],
"allSerials": false,
"network": "testnet"
}When using --all-serials:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"ownerAccountId": "0.0.111111",
"spenderAccountId": "0.0.222222",
"serials": null,
"allSerials": true,
"network": "testnet"
}Delete NFT allowances. Supports two modes:
- Specific serials (
--serials): UsesAccountAllowanceDeleteTransactionto remove allowance for specific serial numbers from ALL spenders. No--spenderneeded. - All-serials blanket revoke (
--all-serials): UsesAccountAllowanceApproveTransaction.deleteTokenNftAllowanceAllSerialsto revoke a blanket all-serials approval for a specific spender. Requires--spender.
# Delete allowance for specific serials (removes for ALL spenders)
hcli token delete-allowance-nft \
--token mynft-alias \
--owner alice \
--serials 1,2,3
# Revoke all-serials blanket approval for a specific spender
hcli token delete-allowance-nft \
--token mynft-alias \
--owner alice \
--spender bob \
--all-serials
# Owner defaults to operator
hcli token delete-allowance-nft \
--token mynft-alias \
--serials 1,5,10
# Using account-id:private-key pair for owner
hcli token delete-allowance-nft \
--token 0.0.123456 \
--owner 0.0.111111:302e020100300506032b657004220420... \
--serials 1,2,3Parameters:
--token/-T: NFT token identifier (alias or token ID) - Required- Must be an NFT collection (type:
NON_FUNGIBLE_UNIQUE)
- Must be an NFT collection (type:
--owner/-o: Owner account - Optional (defaults to operator)- Accepts any key format
- Account ID only:
0.0.111111 - Account with key:
0.0.111111:private-key - Account alias:
alice
--serials: Specific NFT serial numbers to delete allowance for (comma-separated, e.g.,1,2,3) - Optional- Removes allowance for ALL spenders on these serials
- Mutually exclusive with
--all-serials - Cannot be used with
--spender
--all-serials: Revoke all-serials blanket approval - Optional- Mutually exclusive with
--serials - Requires
--spender - One of
--serialsor--all-serialsmust be specified
- Mutually exclusive with
--spender/-s: Spender account (ID, EVM address, or alias) - Conditional- Required with
--all-serials, not used with--serials
- Required with
--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Output (specific serials):
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"ownerAccountId": "0.0.111111",
"spenderAccountId": null,
"serials": [1, 2, 3],
"allSerials": false,
"network": "testnet"
}When using --all-serials:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"ownerAccountId": "0.0.111111",
"spenderAccountId": "0.0.222222",
"serials": null,
"allSerials": true,
"network": "testnet"
}Associate a fungible or non-fungible token with an account to enable transfers. Use token associate for both FT and NFT tokens.
# Using account alias
hcli token associate \
--token mytoken-alias \
--account alice
# Using account-id:account-key pair
hcli token associate \
--token 0.0.123456 \
--account 0.0.789012:302e020100300506032b657004220420...
# Add to batch
hcli token associate --token mytoken-alias --account alice --batch my-batchRemove a token association from an account. The account must have a zero balance of the token before dissociating. Works for both fungible tokens (FT) and non-fungible tokens (NFT).
# Using account alias
hcli token dissociate \
--token mytoken-alias \
--account alice
# Using account-id:account-key pair
hcli token dissociate \
--token 0.0.123456 \
--account 0.0.789012:302e020100300506032b657004220420...
# Add to batch
hcli token dissociate --token mytoken-alias --account alice --batch my-batchParameters:
--token/-T: Token identifier (alias or token ID) - Required--account/-a: Account to dissociate from the token. Accepts any key format: account alias,accountId:privateKey, or key reference - Required--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Output:
{
"transactionId": "0.0.123@1700000000.123456789",
"accountId": "0.0.789012",
"tokenId": "0.0.123456",
"network": "testnet"
}Notes:
- The account must hold a zero balance of the token before dissociation (Hedera requirement)
- The command validates that the token is currently associated with the account before attempting dissociation
- After successful dissociation, the association is removed from local state
- Batch support: pass
--batch <batch-name>to queue the transaction for batch execution
Airdrop fungible tokens from one account to one or more recipients in a single transaction. If a recipient lacks auto-association slots or has "receiver signature required" set, the transfer becomes a pending airdrop (not a failure) that the recipient must claim separately.
# Airdrop to a single recipient
hcli token airdrop-ft \
--token mytoken-alias \
--to alice \
--amount 100
# Airdrop to multiple recipients (index-mapped: to[0]βamount[0])
hcli token airdrop-ft \
--token 0.0.123456 \
--to 0.0.100001 --amount 100 \
--to 0.0.100002 --amount 200 \
--to 0.0.100003 --amount 50
# Using raw base units with "t" suffix
hcli token airdrop-ft \
--token mytoken-alias \
--to alice --amount 1000t \
--to bob --amount 500t \
--from 0.0.111111:302e020100300506032b657004220420...
# Add to a batch
hcli token airdrop-ft \
--token mytoken-alias \
--to alice --amount 100 \
--batch my-airdrop-batchParameters:
--token/-T: Fungible token identifier (alias or token ID) - Required--to/-t: Recipient account (alias, account-id, or EVM address) β pass multiple times for multiple recipients - Required--amount/-a: Amount to airdrop β index-mapped to--to. Default: display units (decimals applied). Appendtfor raw base units β pass multiple times to match--to- Required--from/-f: Sender account (alias or account-id:private-key pair) - Optional (defaults to operator)--key-manager/-k: Key manager type - Optional (defaults to config setting)localorlocal_encrypted
Notes:
- The number of
--toflags must equal the number of--amountflags (validated at input) - Maximum 9 recipients per transaction (Hedera limit: 10 balance adjustments including sender debit)
- Batch support: pass
--batch <batch-name>to queue the transaction for batch execution
Implementation: src/plugins/token/commands/airdrop-ft/handler.ts
Transfer a fungible token from one account to another.
# Using account name for source
hcli token transfer-ft \
--token mytoken-alias \
--from alice \
--to bob \
--amount 100
# Using account-id:private-key pair for source
hcli token transfer-ft \
--token 0.0.123456 \
--from 0.0.111111:302e020100300506032b657004220420... \
--to 0.0.222222 \
--amount 100tAirdrop specific NFT serial numbers from one account to one or more recipients in a single transaction. If a recipient lacks auto-association slots, the transfer becomes a pending airdrop (not a failure) that the recipient must claim separately.
# Airdrop a single serial to one recipient
hcli token airdrop-nft \
--token mynft-alias \
--to alice \
--serials 1
# Airdrop multiple serials to one recipient
hcli token airdrop-nft \
--token mynft-alias \
--to alice \
--serials 1,2,3
# Airdrop to multiple recipients (index-mapped: to[0]βserials[0])
hcli token airdrop-nft \
--token 0.0.123456 \
--to 0.0.100001 --serials 1,2 \
--to 0.0.100002 --serials 3,4 \
--from 0.0.111111:302e020100300506032b657004220420...
# Add to a batch
hcli token airdrop-nft \
--token mynft-alias \
--to alice --serials 1 \
--to bob --serials 2 \
--batch my-airdrop-batchParameters:
--token/-T: NFT token identifier (alias or token ID) - Required--to/-t: Recipient account(s) (ID, EVM address, or alias) β pass multiple times for multiple recipients - Required--serials/-s: Serial numbers per recipient (comma-separated). Index-mapped to--toβ pass multiple times to match--to- Required--from/-f: Sender account (alias or account-id:private-key pair) - Optional (defaults to operator)--key-manager/-k: Key manager type - Optional (defaults to config setting)localorlocal_encrypted
Notes:
- The number of
--toflags must equal the number of--serialsflags (validated at input) - Serial numbers must be unique across all recipients (no duplicates allowed)
- Maximum 20 NFT serial transfers per transaction (Hedera limit)
- Batch support: pass
--batch <batch-name>to queue the transaction for batch execution
Implementation: src/plugins/token/commands/airdrop-nft/handler.ts
Claim one or more pending airdrops (FT and/or NFT) for a receiver account. Up to 10 airdrops can be claimed in a single transaction.
Use pending-airdrops first to list pending airdrops and their indices.
# List pending airdrops to see indices
hcli token pending-airdrops --account myaccount
# Output:
# 1. MyToken (MTK) [0.0.123] β Amount: 1000
# 2. CoolNFT (CNFT) [0.0.456] β Serial: #5
# Claim a single airdrop by index
hcli token claim-airdrop --account myaccount --index 1
# Claim multiple airdrops (FT and NFT in one transaction)
hcli token claim-airdrop --account myaccount --index 1 --index 2
# Using explicit signing account
hcli token claim-airdrop --account myaccount --index 1 --from my-key
# Batch mode
hcli token claim-airdrop --account myaccount --index 1 --batch my-batchOptions:
--account(required): Receiver account ID or alias--index(required, repeatable): 1-based index frompending-airdropsoutput--from(optional): Signing account. Defaults to operator--key-manager(optional): Key manager type (localorlocal_encrypted)
Notes:
- Maximum 10 airdrops per transaction (Hedera SDK limit)
- Both FT and NFT airdrops can be claimed in a single transaction
- Indices are 1-based and correspond to the order shown by
pending-airdrops - Batch support: pass
--batch <batch-name>to queue the transaction for batch execution
Implementation: src/plugins/token/commands/claim-airdrop/handler.ts
Cancel a pending token airdrop (FT or NFT). The sender of the original airdrop must sign this transaction.
# Cancel a pending FT airdrop
hcli token cancel-airdrop \
--token 0.0.123456 \
--receiver 0.0.200000
# Cancel a pending NFT airdrop (requires --serial)
hcli token cancel-airdrop \
--token 0.0.123456 \
--receiver 0.0.200000 \
--serial 42
# Specify sender key explicitly (defaults to operator)
hcli token cancel-airdrop \
--token mytoken-alias \
--receiver alice \
--from 0.0.111111:302e020100300506032b657004220420...
# Add to a batch
hcli token cancel-airdrop \
--token 0.0.123456 \
--receiver 0.0.200000 \
--batch my-batch
# Schedule the transaction
hcli token cancel-airdrop \
--token 0.0.123456 \
--receiver 0.0.200000 \
--schedule my-scheduleOptions:
| Option | Short | Required | Description |
|---|---|---|---|
--token |
-T |
Yes | Token identifier (ID or alias) |
--receiver |
-r |
Yes | Receiver account (ID, EVM address, or alias) |
--serial |
-s |
No | NFT serial number. If provided, cancels an NFT airdrop |
--from |
-f |
No | Sender key. Accepts any key format. Defaults to operator |
--key-manager |
-k |
No | Key manager type (defaults to config setting) |
Notes:
- Omitting
--serialcancels a fungible token airdrop; providing it cancels an NFT airdrop - Batch and schedule support: pass
--batch <name>or--schedule <name>
Implementation: src/plugins/token/commands/cancel-airdrop/handler.ts
Reject a token from account balance, returning it to the treasury. For NFT tokens, specify serial numbers with --serial. Custom fees are waived.
# Reject a fungible token
hcli token reject-airdrop \
--owner my-wallet \
--token 0.0.5867883
# Reject a single NFT serial
hcli token reject-airdrop \
--owner my-wallet \
--token 0.0.5867884 \
--serial 5
# Reject multiple NFT serials
hcli token reject-airdrop \
--owner my-wallet \
--token 0.0.5867884 \
--serial 1,2,3
# With explicit signing key
hcli token reject-airdrop \
--owner my-wallet \
--token 0.0.5867883 \
--from 0.0.5678:302e020100300506032b657004220420...
# Batch mode
hcli token reject-airdrop \
--owner my-wallet \
--token 0.0.5867883 \
--batch my-batchParameters:
--owner/-o: Owner account ID or alias - Required--token/-t: Token ID to reject (e.g.0.0.5867883) - Required--serial/-s: NFT serial number(s). Required for NFT tokens. Comma-separated:1,2,3- Optional--from/-f: Signing account credential (alias or account-id:private-key pair) - Optional (defaults to owner account)--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Notes:
- Maximum 10 NFT serials per transaction (Hedera limit)
--serialis required for NFT tokens and must not be provided for fungible tokens- Batch support: pass
--batch <batch-name>to queue the transaction for batch execution
Implementation: src/plugins/token/commands/reject-airdrop/handler.ts
Transfer one or more NFTs from one account to another.
# Using account alias for source
hcli token transfer-nft \
--token mynft-alias \
--from alice \
--to bob \
--serials 1,2,3
# Using account-id:private-key pair for source
hcli token transfer-nft \
--token 0.0.123456 \
--from 0.0.111111:302e020100300506032b657004220420... \
--to 0.0.222222 \
--serials 5
# Omitting --from uses operator account
hcli token transfer-nft \
--token mynft-alias \
--to bob \
--serials 1,2,3Parameters:
--token/-T: NFT token identifier (alias or token ID) - Required--to/-t: Destination account (alias, account-id, or EVM address) - Required--from/-f: Source account (alias or account-id:private-key pair) - Optional (defaults to operator)--serials/-s: NFT serial numbers to transfer (comma-separated, max 10) - Required--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Note: Maximum 10 serial numbers per transaction (Hedera limit). The command verifies NFT ownership before transfer.
Approve (or revoke) a spender allowance for fungible tokens on behalf of the owner. Set amount to 0 to revoke an existing allowance.
# Approve allowance using aliases
hcli token allowance-ft \
--token mytoken-alias \
--owner alice \
--spender bob \
--amount 500
# Approve using token ID and account-id:key pairs
hcli token allowance-ft \
--token 0.0.123456 \
--owner 0.0.111111:302e020100300506032b657004220420... \
--spender 0.0.222222 \
--amount 1000t
# Revoke allowance (set amount to 0)
hcli token allowance-ft \
--token mytoken-alias \
--owner alice \
--spender bob \
--amount 0Parameters:
--token/-T: Token identifier (alias or token ID) - Required--owner/-o: Owner account. Accepts any key format (alias,accountId:privateKey, key reference) - Required--spender/-s: Spender account (ID or alias) - Required--amount/-a: Allowance amount - Required- Display units (default):
100(will be multiplied by token decimals) - Base units:
100t(raw amount without decimals) 0to revoke the allowance
- Display units (default):
--key-manager/-k: Key manager type (optional, defaults to config setting)localorlocal_encrypted
Batch support: Pass --batch <batch-name> to add to a batch instead of executing immediately.
Output:
{
"tokenId": "0.0.123456",
"ownerAccountId": "0.0.111111",
"spenderAccountId": "0.0.222222",
"amount": "100000",
"transactionId": "0.0.111111@1700000000.123456789",
"network": "testnet"
}Note: Amount in the output is always in base units (raw). The token must have been associated with the spender account before the allowance can be used.
Delete a token from the Hedera network and remove it from local state. The token must have an admin key to be deleted from the network.
# Delete by token alias (network delete)
hcli token delete --token mytoken-alias
# Delete by token ID (network delete)
hcli token delete --token 0.0.123456
# Provide admin key explicitly
hcli token delete --token 0.0.123456 --admin-key <key-ref>
# Threshold / KeyList admin key: pass multiple `--admin-key` values
hcli token delete --token 0.0.123456 --admin-key alice --admin-key bob
# Remove from local state only (no network transaction)
hcli token delete --token mytoken-alias --state-onlyParameters:
--token/-T: Token identifier: either a token alias or token-id - Required--admin-key: Admin key credential(s) for signing - Optional (auto-resolved from the key manager from on-chain public keys when not passed). Repeatable for KeyList / threshold admin keys--key-manager: Key manager type, defaults to config setting - Optional--state-only: Remove token from local state only, without a network transaction - Optional
--state-only and --admin-key are mutually exclusive. Any aliases associated with the token on the current network will also be removed.
Freeze an account for a token. A frozen account cannot send or receive the token until unfrozen. Works for both fungible tokens (FT) and non-fungible tokens (NFT). Requires the token freeze key to sign. The token must have a freeze key set at creation time.
# Freeze account by token ID and account ID
hcli token freeze --token 0.0.123456 --account 0.0.5678 --freeze-key <key-ref>
# Freeze account using token alias
hcli token freeze --token mytoken-alias --account 0.0.5678 --freeze-key <key-ref>
# Freeze account using EVM address
hcli token freeze --token 0.0.123456 --account 0xaabbcc... --freeze-key <key-ref>
# Freeze account using account alias
hcli token freeze --token 0.0.123456 --account alice --freeze-key <key-ref>Parameters:
--token/-T: Token identifier: either a token alias or token-id - Required--account/-a: Account to freeze: account-id (0.0.X), account alias, or EVM address (0x...) - Required--freeze-key/-f: Freeze key of the token. Accepts any key format: key reference,{ed25519|ecdsa}:private:{key}, or{accountId}:{privateKey}pair - Optional (if omitted, resolved from key manager by matching the token's on-chain key)--key-manager/-k: Key manager type, defaults to config setting - Optional
If the token does not have a freeze key, the command fails with a clear error: Token has no freeze key. The operation is idempotent β freezing an already-frozen account succeeds without error.
Re-enables the specified account to send and receive the token. Works for both fungible tokens (FT) and non-fungible tokens (NFT). Requires the token freeze key to sign. The token must have a freeze key set at creation time.
# Unfreeze account by token ID and account ID
hcli token unfreeze --token 0.0.123456 --account 0.0.5678 --freeze-key <key-ref>
# Unfreeze account using token alias
hcli token unfreeze --token mytoken-alias --account 0.0.5678 --freeze-key <key-ref>
# Unfreeze account using EVM address
hcli token unfreeze --token 0.0.123456 --account 0xaabbcc... --freeze-key <key-ref>
# Unfreeze account using account alias
hcli token unfreeze --token 0.0.123456 --account alice --freeze-key <key-ref>Parameters:
--token/-T: Token identifier: either a token alias or token-id - Required--account/-a: Account to unfreeze: account-id (0.0.X), account alias, or EVM address (0x...) - Required--freeze-key/-f: Freeze key of the token. Accepts any key format: key reference,{ed25519|ecdsa}:private:{key}, or{accountId}:{privateKey}pair - Optional (if omitted, resolved from key manager by matching the token's on-chain key)--key-manager/-k: Key manager type, defaults to config setting - Optional
If the token does not have a freeze key, the command fails with a clear error: Token has no freeze key. The operation is idempotent β unfreezing an already-unfrozen account succeeds without error.
Prevents the token from being involved in any kind of transaction across all accounts. Requires the token pause key to sign. The token must have a pause key set at creation time.
# Pause token by token ID
hcli token pause --token 0.0.123456 --pause-key <key-ref>
# Pause token using token alias
hcli token pause --token mytoken-alias --pause-key <key-ref>Parameters:
--token/-T: Token identifier: either a token alias or token-id - Required--pause-key/-p: Pause key of the token. Accepts any key format: key reference,{ed25519|ecdsa}:private:{key}, or{accountId}:{privateKey}pair - Optional (if omitted, resolved from key manager by matching the token's on-chain key)--key-manager/-k: Key manager type, defaults to config setting - Optional
If the token does not have a pause key, the command fails with a clear error: Token has no pause key.
Re-enables the token to be involved in transactions across all accounts. Requires the token pause key to sign.
# Unpause token by token ID
hcli token unpause --token 0.0.123456 --pause-key <key-ref>
# Unpause token using token alias
hcli token unpause --token mytoken-alias --pause-key <key-ref>Parameters:
--token/-T: Token identifier: either a token alias or token-id - Required--pause-key/-p: Pause key of the token. Accepts any key format: key reference,{ed25519|ecdsa}:private:{key}, or{accountId}:{privateKey}pair - Optional (if omitted, resolved from key manager by matching the token's on-chain key)--key-manager/-k: Key manager type, defaults to config setting - Optional
If the token does not have a pause key, the command fails with a clear error: Token has no pause key.
Grants KYC flag to the specified account for the token. Requires the token KYC key to sign. Works for both fungible tokens (FT) and non-fungible tokens (NFT). The token must have a KYC key set at creation time.
# Grant KYC by token ID and account ID
hcli token grant-kyc --token 0.0.123456 --account 0.0.5678
# Grant KYC using token alias and account alias
hcli token grant-kyc --token mytoken-alias --account alice
# Grant KYC with explicit KYC key
hcli token grant-kyc --token 0.0.123456 --account 0.0.5678 --kyc-key <key-ref>Parameters:
--token/-T: Token identifier: either a token alias or token-id - Required--account/-a: Account to grant KYC: account-id (0.0.X), account alias, or EVM address (0x...) - Required--kyc-key/-y: KYC key of the token. Accepts any key format: key reference,{ed25519|ecdsa}:private:{key}, or{accountId}:{privateKey}pair - Optional (if omitted, resolved from key manager by matching the token's on-chain key)--key-manager/-k: Key manager type, defaults to config setting - Optional
If the token does not have a KYC key, the command fails with a clear error: Token has no KYC key.
Revokes KYC flag from the specified account for the token. Requires the token KYC key to sign. Works for both fungible tokens (FT) and non-fungible tokens (NFT).
# Revoke KYC by token ID and account ID
hcli token revoke-kyc --token 0.0.123456 --account 0.0.5678
# Revoke KYC using token alias and account alias
hcli token revoke-kyc --token mytoken-alias --account alice
# Revoke KYC with explicit KYC key
hcli token revoke-kyc --token 0.0.123456 --account 0.0.5678 --kyc-key <key-ref>Parameters:
--token/-T: Token identifier: either a token alias or token-id - Required--account/-a: Account to revoke KYC: account-id (0.0.X), account alias, or EVM address (0x...) - Required--kyc-key/-y: KYC key of the token. Accepts any key format: key reference,{ed25519|ecdsa}:private:{key}, or{accountId}:{privateKey}pair - Optional (if omitted, resolved from key manager by matching the token's on-chain key)--key-manager/-k: Key manager type, defaults to config setting - Optional
If the token does not have a KYC key, the command fails with a clear error: Token has no KYC key.
Update properties of an existing token. Works for both fungible (FT) and non-fungible (NFT) tokens. The token must exist on the mirror node and must have an admin key for most changes (expiration time is the only field that can be updated without one, when it is the only change).
Role keys (--kyc-key, --freeze-key, etc.) accept new key credentials or the literal string "null" to permanently remove the key from the token.
# Rename a token
hcli token update --token mytoken-alias --token-name "New Name"
# Update the token symbol
hcli token update --token 0.0.123456 --symbol NEWSYM
# Change treasury account
hcli token update --token mytoken-alias --treasury new-treasury-alias
# Replace the KYC key
hcli token update --token mytoken-alias --kyc-key alice
# Permanently remove the KYC key
hcli token update --token mytoken-alias --kyc-key null
# Clear the memo
hcli token update --token mytoken-alias --memo null
# Update expiration time (no admin key required when this is the only change)
hcli token update --token mytoken-alias --expiration-time 2030-06-01T00:00:00.000Z
# Update multiple fields at once
hcli token update --token mytoken-alias \
--token-name "Renamed Token" \
--memo "Updated memo" \
--kyc-key null \
--freeze-key alice
# Add to a batch
hcli token update --token mytoken-alias --token-name "Batched Rename" --batch my-batchKey options:
| Option | Short | Description |
|---|---|---|
--token |
-T |
Token ID or alias β Required |
--token-name |
-b |
New token name |
--symbol |
-Y |
New token symbol |
--treasury |
-t |
New treasury account ID or alias |
--admin-keys |
-a |
Current admin key credential(s) for signing (auto-resolved if omitted) |
--new-admin-keys |
-n |
New admin key(s); pass null to clear |
--kyc-key |
-y |
New KYC key(s); pass null to permanently remove |
--freeze-key |
-f |
New freeze key(s); pass null to permanently remove |
--wipe-key |
-w |
New wipe key(s); pass null to permanently remove |
--supply-key |
-s |
New supply key(s); pass null to permanently remove |
--fee-schedule-key |
-e |
New fee schedule key(s); pass null to permanently remove |
--pause-key |
-p |
New pause key(s); pass null to permanently remove |
--metadata-key |
-D |
New metadata key(s); pass null to permanently remove |
--memo |
-M |
New memo; pass null to clear |
--auto-renew-account |
-r |
New auto-renew account |
--auto-renew-period |
-R |
New auto-renew period (seconds or with suffix: 30d, 90d) |
--expiration-time |
-x |
New expiration as ISO 8601 string |
--metadata |
-d |
Token metadata (UTF-8, max 100 bytes) |
--key-manager |
-k |
Key manager type (local or local_encrypted) |
Output:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.67890",
"network": "testnet",
"updatedFields": ["name", "kycKey (cleared)", "memo"]
}updatedFields lists every field that was changed. Cleared role keys carry a (cleared) suffix.
Batch support: Pass --batch <batch-name> to defer execution. After a successful batch run the token-update-state hook persists the updated token data to local state automatically.
List all tokens (FT and NFT) stored in state for all networks.
hcli token list
hcli token list --keys # Show token key informationView detailed information about fungible or non-fungible tokens from the Hedera Mirror Node.
# View token by alias
hcli token view --token mytoken-alias
# View token by ID
hcli token view --token 0.0.123456
# View specific NFT serial
hcli token view --token mytoken-alias --serial 1Create a new fungible token from a JSON file definition with advanced features.
# Basic usage
hcli token create-ft-from-file --file token-definition.json
# With specific key manager
hcli token create-ft-from-file --file token-definition.json --key-manager local_encrypted
# Add to batch
hcli token create-ft-from-file --file token-definition.json --batch my-batchToken File Format:
initialSupply and maxSupply must be strings. Supported formats (same as other token commands):
- Display units:
"100"or"100.5"(multiplied by decimals) - Base units:
"100t"(raw amount, no decimals applied)
The token file supports aliases and raw keys with optional key type prefixes:
{
"name": "my-token",
"symbol": "MTK",
"decimals": 8,
"supplyType": "finite",
"initialSupply": "1000000",
"maxSupply": "10000000",
"treasuryKey": "<alias or accountId:privateKey>",
"adminKey": "<alias or accountId:privateKey>",
"supplyKey": "<alias or accountId:privateKey>",
"wipeKey": "<alias or accountId:privateKey>",
"kycKey": "<alias or accountId:privateKey>",
"freezeKey": "<alias or accountId:privateKey>",
"pauseKey": "<alias or accountId:privateKey>",
"feeScheduleKey": "<alias or accountId:privateKey>",
"metadataKey": "<alias or accountId:privateKey>",
"freezeDefault": false,
"autoRenewPeriod": 7776000,
"autoRenewAccountId": "<accountId>",
"expirationTime": "2027-01-01T00:00:00Z",
"memo": "Optional token memo",
"autoRenewPeriod": "86400",
"autoRenewAccount": "<alias or accountId:privateKey>",
"expirationTime": "2030-12-31T23:59:59.000Z",
"associations": ["<alias or accountId:privateKey>", "..."],
"customFees": [
{
"type": "fixed",
"amount": 100,
"unitType": "HBAR",
"collectorId": "<accountId>",
"exempt": false
}
]
}Optional lifecycle fields (same rules as token create-ft):
autoRenewPeriod: string or number; parsed to seconds (plain number = seconds; suffixess,m,h,dsupported). RequiresautoRenewAccountwhen set.autoRenewAccount: account that pays auto-renewal (same key formats as other keys).expirationTime: ISO 8601 string. Ignored with a warning if bothautoRenewPeriodandautoRenewAccountare set.
Supported formats for treasury and keys:
- Alias:
"my-account"- resolved via alias service - Account with key:
"0.0.123456:privateKey" - Account ID only:
"0.0.123456" - Public key:
"ed25519:public:hex-key"or"ecdsa:public:hex-key" - Private key:
"ed25519:private:hex-key"or"ecdsa:private:hex-key" - Key reference:
"kr_xxx"- managed by key manager
Note: Token name is automatically registered as an alias after successful creation. Duplicate names are not allowed.
Create a new non-fungible token from a JSON file definition with advanced features.
# Basic usage
hcli token create-nft-from-file --file nft-definition.json
# With specific key manager
hcli token create-nft-from-file --file nft-definition.json --key-manager local_encrypted
# Add to batch
hcli token create-nft-from-file --file nft-definition.json --batch my-batchToken File Format:
The NFT file supports aliases and raw keys with optional key type prefixes:
{
"name": "my-nft",
"symbol": "MNFT",
"supplyType": "finite",
"maxSupply": 1000,
"treasuryKey": "<alias or accountId:privateKey>",
"adminKey": "<alias or accountId:privateKey>",
"supplyKey": "<alias or accountId:privateKey>",
"wipeKey": "<alias or accountId:privateKey>",
"kycKey": "<alias or accountId:privateKey>",
"freezeKey": "<alias or accountId:privateKey>",
"pauseKey": "<alias or accountId:privateKey>",
"feeScheduleKey": "<alias or accountId:privateKey>",
"metadataKey": "<alias or accountId:privateKey>",
"freezeDefault": false,
"autoRenewPeriod": 7776000,
"autoRenewAccountId": "<accountId>",
"expirationTime": "2027-01-01T00:00:00Z",
"memo": "Optional NFT collection memo",
"associations": ["<alias or accountId:privateKey>", "..."]
}Supported formats for treasury and keys:
- Alias:
"my-account"- resolved via alias service - Account with key:
"0.0.123456:privateKey" - Account ID only:
"0.0.123456" - Public key:
"ed25519:public:hex-key"or"ecdsa:public:hex-key" - Private key:
"ed25519:private:hex-key"or"ecdsa:private:hex-key" - Key reference:
"kr_xxx"- managed by key manager
Key Differences from Fungible Token:
- No
decimalsorinitialSupplyfields (NFT-specific) maxSupplyrepresents the maximum number of NFT instances in the collection- NFTs are minted individually with metadata via
mint-nftcommand - No
customFeesfield (planned for future versions)
Note: NFT token name is automatically registered as an alias after successful creation. Duplicate names are not allowed. Token associations are created automatically for all specified accounts.
The plugin supports flexible parameter formats:
- Token: Token alias (name) or token ID (
0.0.123456) - Treasury: Account alias (name) or
treasury-id:treasury-keypair (e.g.,0.0.123456:302e0201...) - Account ID only:
0.0.123456(for destination accounts) - Account ID with key:
0.0.123456:private-key(for source accounts that need signing) - Account name:
alice(resolved via alias service) - Amount: Display units (default) or base units with
tsuffix (e.g.,100t)
All key parameters accept any of the following formats:
- Alias:
"my-account"- resolved via alias service - Account with private key:
"0.0.123456:privateKey" - Account ID only:
"0.0.123456" - Public key with type prefix:
"ed25519:public:hex-key"or"ecdsa:public:hex-key" - Private key with type prefix:
"ed25519:private:hex-key"or"ecdsa:private:hex-key" - Key reference:
"kr_xxx"- managed by key manager - EVM address:
"0x..."(where supported)
The following token commands support the --batch / -B flag via the batch plugin's batchify hook:
create-ftβTokenCreateFtBatchStateHookpersists FT state after batch executioncreate-nftβTokenCreateNftBatchStateHookpersists NFT state after batch executioncreate-ft-from-fileβTokenCreateFtFromFileBatchStateHookpersists FT-from-file statecreate-nft-from-fileβTokenCreateNftFromFileBatchStateHookpersists NFT-from-file stateassociateβTokenAssociateBatchStateHookpersists association resultsburn-ft,burn-nft,mint-ft,mint-nft,update-metadata-nft,transfer-ft,transfer-nft,allowance-nft,allowance-ft,delete-allowance-nftβ can be batched (no state hook; transactions execute atomically)dissociateβTokenDissociateStateHookremoves association from state after batch executionupdateβTokenUpdateStateHookpersists updated token data (name, symbol, treasury, role keys, memo) after batch executionburn-ft,burn-nft,mint-ft,mint-nft,transfer-ft,transfer-nft,allowance-nft,allowance-ft,delete-allowance-nftβ can be batched (no state hook; transactions execute atomically)
When you pass --batch <batch-name>:
- No immediate execution β The transaction is not submitted to the network. Instead, it is serialized and added to the specified batch.
- Deferred execution β Run
hcli batch execute --name <batch-name>to submit all batched transactions atomically. - State persistence β After successful batch execution, the corresponding batch-state hooks run for create/associate commands to persist token data, associations, and aliases.
Example workflow:
# 1. Create a batch
hcli batch create --name my-batch --key operator-alias
# 2. Add token operations to the batch
hcli token create-ft --token-name "Token A" --symbol "TA" --treasury alice --decimals 8 --initial-supply 1000 --supply-type FINITE --max-supply 10000 --admin-key alice --supply-key alice --name token-a --batch my-batch
hcli token create-ft-from-file --file token-definition.json --batch my-batch
hcli token associate --token token-a --account bob --batch my-batch
# 3. Execute the batch
hcli batch execute --name my-batchThe --batch option is automatically injected by the batchify hook. See the Batch Plugin README for full batch documentation.
The plugin uses the Core API services:
api.token- Token transaction creation and managementapi.txExecution- Transaction signing and executionapi.kms- Account credentials and key managementapi.alias- Account and token name resolutionapi.state- Namespaced state managementapi.network- Network informationapi.receipt- Transaction receipt retrieval (used by batch-state hooks)api.logger- Logging
All commands return structured output through the CommandResult interface:
interface CommandResult {
result: object;
}Output Structure:
- Output Schemas: Each command defines a Zod schema in
output.tsfor type-safe output validation - Human Templates: Handlebars templates provide human-readable output formatting
- Error Handling: All errors are returned in the result structure, ensuring consistent error handling
The result field contains a structured object conforming to the Zod schema defined in each command's output.ts file, ensuring type safety and consistent output structure.
Token data is stored in the token-tokens namespace with the following structure:
interface TokenData {
tokenId: string;
name: string;
symbol: string;
treasuryId: string;
tokenType: 'FUNGIBLE_COMMON' | 'NON_FUNGIBLE_UNIQUE';
decimals: number;
initialSupply: number;
supplyType: SupplyType;
maxSupply: number;
memo?: string;
adminPublicKey?: string;
supplyPublicKey?: string;
wipePublicKey?: string;
kycPublicKey?: string;
freezePublicKey?: string;
pausePublicKey?: string;
feeSchedulePublicKey?: string;
metadataPublicKey?: string;
keys: TokenKeys;
network: 'mainnet' | 'testnet' | 'previewnet' | 'localnet';
associations: TokenAssociation[];
customFees: CustomFee[];
}Field Descriptions:
tokenType: Discriminates fungible tokens (FUNGIBLE_COMMON) from NFT collections (NON_FUNGIBLE_UNIQUE)decimals: Number of decimal places for fungible tokens; zero for NFTsinitialSupply: Initial supply amount; zero for NFTsadminPublicKey: Public key with admin privileges for token operationssupplyPublicKey: Public key authorized to mint/burn tokenswipePublicKey: Public key authorized to wipe token balanceskycPublicKey: Public key authorized to grant/revoke KYC statusfreezePublicKey: Public key authorized to freeze token transferspausePublicKey: Public key authorized to pause all token transfersfeeSchedulePublicKey: Public key authorized to update custom feesmetadataPublicKey: Public key authorized to update token metadata
NFT tokens use zero for decimals and initialSupply; minted NFTs are tracked by serial number on the ledger. The schema is validated using Zod (TokenDataSchema) and stored as JSON Schema in the plugin manifest for runtime validation.
The plugin includes comprehensive tests for output structure:
import { Status } from '../../../core/shared/constants';
// Example test verifying CommandResult structure
describe('Token Plugin Output Structure', () => {
test('fungible token create command returns CommandResult', async () => {
const result = await createToken(mockArgs);
// Assert structure
expect(result.result).toBeDefined();
// Assert output format
const output = result.result as CreateFungibleTokenOutput;
expect(output.tokenId).toBe('0.0.12345');
expect(output.name).toBe('TestToken');
});
});- Output Compliance:
adr007-compliance.test.ts- Tests all handlers return properCommandResult - Unit Tests: Individual command handler tests with mocks and fixtures β including
update.test.tsfor the unified update command - Batch Tests:
batch-create-ft.test.ts,batch-create-nft.test.ts,batch-create-ft-from-file.test.ts,batch-create-nft-from-file.test.ts,token-update-state-hook.test.ts- Tests batch-state hooks - Integration Tests: End-to-end token lifecycle tests
- Schema Tests: Validation of input/output schemas
All commands support multiple output formats:
Fungible Token Create:
β
Token created successfully: 0.0.12345
Name: MyToken (MTK)
Treasury: 0.0.111
Decimals: 2
Initial Supply: 1000000
Supply Type: INFINITE
Network: testnet
Transaction ID: 0.0.123@1700000000.123456789
Non-Fungible Token Create:
β
NFT created successfully: 0.0.123456
Name: My NFT Collection (MNFT)
Treasury: 0.0.111
Supply Type: FINITE
Network: testnet
Transaction ID: 0.0.123@1700000000.123456789
FT Mint:
β
FT mint successful!
Token ID: 0.0.123456
Amount minted: 10000
Transaction ID: 0.0.123@1700000000.123456789
NFT Mint:
β
NFT mint successful!
Token ID: 0.0.123456
Serial Number: 1
Transaction ID: 0.0.123@1700000000.123456789
Fungible Token Create:
{
"tokenId": "0.0.12345",
"name": "MyToken",
"symbol": "MTK",
"treasuryId": "0.0.111",
"decimals": 2,
"initialSupply": "1000000",
"supplyType": "INFINITE",
"transactionId": "0.0.123@1700000000.123456789",
"network": "testnet"
}Non-Fungible Token Create:
{
"tokenId": "0.0.123456",
"name": "My NFT Collection",
"symbol": "MNFT",
"treasuryId": "0.0.111",
"supplyType": "FINITE",
"transactionId": "0.0.123@1700000000.123456789",
"adminPublicKey": "302e020100300506032b657004220420...",
"supplyPublicKey": "302e020100300506032b657004220420...",
"freezePublicKey": "302e020100300506032b657004220420...",
"wipePublicKey": "302e020100300506032b657004220420...",
"kycPublicKey": "302e020100300506032b657004220420...",
"pausePublicKey": "302e020100300506032b657004220420...",
"feeSchedulePublicKey": "302e020100300506032b657004220420...",
"metadataPublicKey": "302e020100300506032b657004220420...",
"network": "testnet"
}FT Mint:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"amount": "10000",
"network": "testnet"
}NFT Mint:
{
"transactionId": "0.0.123@1700000000.123456789",
"tokenId": "0.0.123456",
"serialNumber": "1",
"network": "testnet"
}Output format is controlled by the CLI's --format option (default: human, or json for machine-readable output).