Skip to main content

HCS-21 Browser Client (HCS21BrowserClient)

HCS21BrowserClient wraps the Hashinals WalletConnect SDK so browser apps can build the entire HCS-21 stack—registry-of-registries topics, adapter category indexes, version pointers, and declarations—without exposing operator keys. Every helper mirrors the Node.js HCS21Client, but each transaction is signed through the connected wallet.

SetupDirect link to Setup

import { HashinalsWalletConnectSDK } from '@hashgraphonline/hashinal-wc';
import {
HCS21BrowserClient,
HCS21TopicType,
Logger,
} from '@hashgraphonline/standards-sdk';

const hwc = new HashinalsWalletConnectSDK({
projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID!,
});

const browserClient = new HCS21BrowserClient({
network: 'testnet',
hwc,
});

const logger = new Logger({ module: 'hcs-21-browser', level: 'info' });

Create layered registry topicsDirect link to Create layered registry topics

Assume you've already inscribed registry metadata via client.inscribeMetadata and stored the resulting pointer; the browser client can reuse it:

const registryTopicId = await browserClient.createRegistryTopic({
ttl: 3600,
indexed: 0,
type: HCS21TopicType.ADAPTER_REGISTRY,
metaTopicId: registryMetadata.pointer, // optional HCS-1 registry manifest
});

const discoveryTopicId = await browserClient.createRegistryDiscoveryTopic({
ttl: 86400,
memoOverride: 'hcs-21:0:86400:1', // optional explicit memo
});

const categoryTopicId = await browserClient.createAdapterCategoryTopic({
ttl: 86400,
metaTopicId: registryMetadata.pointer,
});

const versionPointerTopicId =
await browserClient.createAdapterVersionPointerTopic({
ttl: 3600,
memoOverride: 'hcs-2:1:3600',
});

createRegistryTopic and createAdapterCategoryTopic emit standard hcs-21:<indexed>:<ttl>:<type>:<meta> memos. The browser client automatically freezes/signs the topic creation transactions with the wallet account.

Register discovery and category entriesDirect link to Register discovery and category entries

await browserClient.registerCategoryTopic({
discoveryTopicId,
categoryTopicId,
metadata: registryMetadata.pointer,
memo: 'adapter-registry:price-feeds',
});

await browserClient.publishCategoryEntry({
categoryTopicId,
adapterId: 'npm/@hol-org/adapter-binance', // slug only; version lives in the pointer topic
versionTopicId: versionPointerTopicId,
});

await browserClient.publishVersionPointer({
versionTopicId,
declarationTopicId: registryTopicId,
memo: 'adapter:npm/@hol-org/adapter-binance',
});

The helper methods emit hcs-2 register messages with the correct memo format. Use publishVersionPointer whenever you rotate an adapter declaration topic; the discovery entry remains stable.

Publish an Adapter DeclarationDirect link to Publish an Adapter Declaration

const publishResult = await browserClient.publishDeclaration({
topicId: registryTopicId,
declaration: {
op: 'register',
adapterId: 'pypi/community/pga-tour-adapter@0.4.0',
entity: 'dataset',
adapterPackage: {
registry: 'pypi',
name: 'pga-tour-adapter',
version: '0.4.0',
integrity: 'sha384-demo-digest',
},
manifest: 'ipfs://bafy...adapter-manifest',
manifestSequence: 15, // optional when HCS-1
config: {
account: '0.0.700001',
threshold: '2/3',
ctopic: '0.0.700101',
ttopic: '0.0.700102',
stopic: '0.0.700103',
},
stateModel: 'hcs-21.dataset-consensus@1',
},
});

console.log('Submitted declaration', publishResult.transactionId);

publishDeclaration returns the Hedera transaction ID plus the sequence number assigned to the message, making it easy to reconcile with mirror-node logs.

Resolve pointers & fetch declarationsDirect link to Resolve pointers & fetch declarations

const { declarationTopicId } = await browserClient.resolveVersionPointer(
versionPointerTopicId,
);

const latest = await browserClient.fetchDeclarations(declarationTopicId, {
limit: 10,
order: 'desc',
});

latest.forEach(payload => {
logger.info('hcs-21 declaration', {
sequence: payload.sequenceNumber,
payer: payload.payer,
adapter: payload.declaration.adapter_id,
});
});

fetchDeclarations uses the wallet’s Hedera Mirror endpoint, filters out non–hcs-21 payloads, and returns the same envelope structure as the server SDK. You can now run the entire layered registry workflow—from topic creation through declaration streaming—directly in a wallet-connected front‑end.