HCS‑17 API Reference
Complete, literal reference for the HCS‑17 module in @hashgraphonline/standards-sdk. For conceptual guidance and flows, see the HCS‑17 SDK guide and standard.
Sources
- Module folder: GitHub
- types.ts: GitHub
- base-client.ts: GitHub
- sdk.ts: GitHub
- browser.ts: GitHub
- tx.ts: GitHub
Import PathsDirect link to Import Paths
// Barrel export
import {
HCS17Client,
HCS17BrowserClient,
HCS17TopicType,
generateHCS17Memo,
parseHCS17Memo,
buildHcs17CreateTopicTx,
buildHcs17MessageTx,
type StateHashMessage,
type AccountStateInput,
type CompositeStateInput,
type StateHashResult,
type CompositeStateHashResult,
type HCS17ClientConfig,
type SDKHCS17ClientConfig,
type BrowserHCS17ClientConfig,
} from '@hashgraphonline/standards-sdk';
// Direct path (optional)
import * as HCS17 from '@hashgraphonline/standards-sdk/hcs-17';
Topic MemoDirect link to Topic Memo
- Format:
hcs-17:<type>:<ttl>where<type>is numeric and<ttl>is a positive integer (seconds). - Enum:
HCS17TopicType.STATE = 0.
Helpers:
function generateHCS17Memo(ttl: number): string;
function parseHCS17Memo(memo: string): { type: HCS17TopicType; ttl: number } | undefined;
TypesDirect link to Types
type TopicState = { topicId: string; latestRunningHash: string };
interface AccountStateInput {
accountId: string;
publicKey: import('@hashgraph/sdk').PublicKey | string;
topics: TopicState[];
}
interface CompositeStateInput {
compositeAccountId: string;
compositePublicKeyFingerprint: string; // deterministic fingerprint of threshold key
memberStates: Array<{ accountId: string; stateHash: string }>;
compositeTopics: TopicState[];
}
interface StateHashMessage {
p: 'hcs-17';
op: 'state_hash';
state_hash: string;
topics: string[];
account_id: string;
timestamp?: string; // ISO8601
m?: string; // optional application memo
}
interface StateHashResult {
stateHash: string;
accountId: string;
timestamp: Date;
topicCount: number;
}
interface CompositeStateHashResult extends StateHashResult {
memberCount: number;
compositeTopicCount: number;
}
interface HCS17ClientConfig {
network: 'mainnet' | 'testnet';
logLevel?: 'debug' | 'info' | 'warn' | 'error';
silent?: boolean;
mirrorNodeUrl?: string; // override
logger?: any; // custom logger (ILogger compatible)
}
interface SDKHCS17ClientConfig extends HCS17ClientConfig {
operatorId: string;
operatorKey: string | import('@hashgraph/sdk').PrivateKey;
keyType?: 'ed25519' | 'ecdsa';
}
interface BrowserHCS17ClientConfig extends HCS17ClientConfig {
hwc?: import('@hashgraphonline/hashinal-wc').HashinalsWalletConnectSDK;
signer?: import('@hashgraph/hedera-wallet-connect').DAppSigner;
}
EnumDirect link to Enum
enum HCS17TopicType {
STATE = 0,
}
Message Schema (canonical)Direct link to Message Schema (canonical)
{
"p": "hcs-17",
"op": "state_hash",
"state_hash": "<hex>",
"topics": ["0.0.123", "0.0.456"],
"account_id": "0.0.999",
"timestamp": "2025-09-14T10:00:00.000Z",
"m": "optional"
}
Base Client (selected)Direct link to Base Client (selected)
The following methods are inherited by both Node and Browser clients.
// Constructed internally by concrete clients
// Validate an existing HCS‑17 topic by memo
validateHCS17Topic(topicId: string): Promise<{ valid: boolean; type?: HCS17TopicType; ttl?: number; error?: string }>;
// Mirror node helpers (validated parsing)
getRecentMessages(
topicId: string,
options?: { limit?: number; order?: 'asc' | 'desc' }
): Promise<Array<{ message: StateHashMessage; consensus_timestamp?: string; sequence_number: number; payer?: string }>>;
getLatestMessage(topicId: string): Promise<(StateHashMessage & { consensus_timestamp?: string; sequence_number: number }) | null>;
// Hashing utilities
calculateAccountStateHash(input: AccountStateInput): StateHashResult;
calculateCompositeStateHash(input: CompositeStateInput): CompositeStateHashResult;
calculateKeyFingerprint(keys: import('@hashgraph/sdk').PublicKey[], threshold: number): string;
verifyStateHash(input: AccountStateInput | CompositeStateInput, expectedHash: string): Promise<boolean>;
// Message helper
createStateHashMessage(stateHash: string, accountId: string, topicIds: string[], memo?: string): StateHashMessage;
Notes
- Account state hash sorts topics lexicographically by
topicIdand hashestopicId || runningHashvalues plus the public key (SHA‑384). - Composite state hash sorts members by
accountId, then composite topics bytopicId, and appends the threshold key fingerprint. verifyStateHashrecomputes with the same rules and compares toexpectedHash.
Node Client (HCS17Client)Direct link to Node Client (HCS17Client)
constructor(config: SDKHCS17ClientConfig)
getKeyType(): 'ed25519' | 'ecdsa'
createStateTopic(options?: {
ttl?: number; // default 86400
adminKey?: boolean | string | import('@hashgraph/sdk').PublicKey | import('@hashgraph/sdk').KeyList;
submitKey?: boolean | string | import('@hashgraph/sdk').PublicKey | import('@hashgraph/sdk').KeyList;
}): Promise<string>
submitMessage(topicId: string, message: StateHashMessage): Promise<import('@hashgraph/sdk').TransactionReceipt>
computeAndPublish(params: {
accountId: string;
accountPublicKey: string | import('@hashgraph/sdk').PublicKey;
topics: string[]; // topics to include in hash
publishTopicId: string; // destination topic for the message
memo?: string;
}): Promise<{ stateHash: string; receipt: import('@hashgraph/sdk').TransactionReceipt }>
Throws
Invalid HCS-17 message: …(onsubmitMessagewhen schema validation fails)Failed to create topic: topicId empty(unexpected Mirror Node/SDK response)
Example
const c = new HCS17Client({ network: 'testnet', operatorId, operatorKey });
const topicId = await c.createStateTopic({ ttl: 86400 });
const { stateHash } = await c.computeAndPublish({
accountId: '0.0.1234',
accountPublicKey: '302a30…',
topics: ['0.0.2001','0.0.2002'],
publishTopicId: topicId,
});
Browser Client (HCS17BrowserClient)Direct link to Browser Client (HCS17BrowserClient)
constructor(config: BrowserHCS17ClientConfig)
createStateTopic(options?: {
ttl?: number; // default 86400
adminKey?: boolean | string; // string = hex/der of key; depends on wallet support
submitKey?: boolean | string;
}): Promise<string>
submitMessage(topicId: string, message: StateHashMessage): Promise<{ transactionId?: string }>
computeAndPublish(params: {
accountId: string;
accountPublicKey: string | import('@hashgraph/sdk').PublicKey;
topics: string[];
publishTopicId: string;
memo?: string;
}): Promise<{ stateHash: string }>
Throws
No active wallet connection(no account bound)No active wallet signer(connector has no signer)Invalid HCS-17 message: …(onsubmitMessagewhen schema validation fails)
Example
const c = new HCS17BrowserClient({ network: 'testnet', signer });
const topicId = await c.createStateTopic({ ttl: 86400 });
const out = await c.computeAndPublish({
accountId: '0.0.1234',
accountPublicKey: '302a30…',
topics: ['0.0.2001','0.0.2002'],
publishTopicId: topicId,
});
Builders (tx.ts)Direct link to Builders (tx.ts)
function buildHcs17CreateTopicTx(params: {
ttl: number;
adminKey?: boolean | string | import('@hashgraph/sdk').PublicKey | import('@hashgraph/sdk').KeyList;
submitKey?: boolean | string | import('@hashgraph/sdk').PublicKey | import('@hashgraph/sdk').KeyList;
operatorPublicKey?: import('@hashgraph/sdk').PublicKey; // Node helper defaulting
}): import('@hashgraph/sdk').TopicCreateTransaction;
function buildHcs17MessageTx(params: {
topicId: string;
stateHash: string;
accountId: string;
topics: string[];
memo?: string;
transactionMemo?: string;
}): import('@hashgraph/sdk').TopicMessageSubmitTransaction;
Notes
- The message builder includes an ISO timestamp automatically.
- Use
transactionMemoto set the Hedera transaction memo (separate fromm).
Reading MessagesDirect link to Reading Messages
// Recent, validated messages (filtering non‑HCS‑17 entries)
const recent = await client.getRecentMessages('0.0.7777', { limit: 25, order: 'desc' });
// Latest only (or null)
const latest = await client.getLatestMessage('0.0.7777');
Validation RulesDirect link to Validation Rules
parseHCS17Memoaccepts onlyhcs-17:<number>:<positive integer>.- Message
pmust behcs-17andopmust bestate_hash. state_hashandaccount_idare required;topicsmust be an array of strings.
Error TypesDirect link to Error Types
class StateHashError extends Error {
readonly code: string; // implementation-defined
}
Note: The clients throw standard Error with codes in messages; StateHashError is available for users who prefer explicit typing in their apps.