@hashgraphonline/standards-agent-kit
Version:
A modular SDK for building on-chain autonomous agents using Hashgraph Online Standards, including HCS-10 for agent discovery and communication. https://hol.org
310 lines (287 loc) • 8.84 kB
text/typescript
import { BaseServiceBuilder } from 'hedera-agent-kit';
import type { HederaAgentKit } from 'hedera-agent-kit';
import {
HCS6Client,
SDKHCS6ClientConfig,
HCS6CreateRegistryOptions,
HCS6RegisterEntryOptions,
HCS6QueryRegistryOptions,
HCS6RegisterOptions,
HCS6CreateHashinalOptions,
HCS6TopicRegistrationResponse,
HCS6RegistryOperationResponse,
HCS6TopicRegistry,
HCS6CreateHashinalResponse,
NetworkType,
HederaMirrorNode,
TopicResponse,
} from '@hashgraphonline/standards-sdk';
import {
SignerProviderRegistry,
type NetworkString,
} from '../../signing/signer-provider';
import type {
HCS6TopicRegistrationResult,
HCS6RegistryOperationResult,
HCS6CreateHashinalResult,
} from '../../types/tx-results';
import { CodedError } from '../../utils/CodedError';
/**
* Builder for HCS-6 operations that delegates to HCS6Client
*/
export class HCS6Builder extends BaseServiceBuilder {
protected hcs6Client?: HCS6Client;
constructor(hederaKit: HederaAgentKit) {
super(hederaKit);
}
/**
* Get or create HCS-6 client
*/
protected async getHCS6Client(): Promise<HCS6Client> {
if (!this.hcs6Client) {
const operatorId = this.hederaKit.signer.getAccountId().toString();
const operatorPrivateKey = this.hederaKit.signer?.getOperatorPrivateKey()
? this.hederaKit.signer.getOperatorPrivateKey().toString()
: '';
const network = this.hederaKit.client.network;
const networkType: NetworkType = network.toString().includes('mainnet')
? 'mainnet'
: 'testnet';
const config: SDKHCS6ClientConfig = {
network: networkType,
operatorId: operatorId,
operatorKey: operatorPrivateKey,
};
this.hcs6Client = new HCS6Client(config);
}
return this.hcs6Client;
}
/**
* Create a new HCS-6 dynamic registry
* Note: This executes the transaction directly via HCS6Client
*/
async createRegistry(
options: HCS6CreateRegistryOptions = {}
): Promise<HCS6TopicRegistrationResult> {
const exec = SignerProviderRegistry.walletExecutor;
const preferWallet = SignerProviderRegistry.preferWalletOnly;
const network = (
this.hederaKit.client.network.toString().includes('mainnet')
? 'mainnet'
: 'testnet'
) as NetworkString;
if (exec) {
const start = SignerProviderRegistry.startHCSDelegate;
if (start) {
try {
const request: Record<string, unknown> = { options };
const { transactionBytes } = await start(
'hcs6.createRegistry',
request,
network
);
if (transactionBytes) {
return { success: true, transactionBytes };
}
} catch (err) {
if (preferWallet) {
throw new CodedError(
'wallet_submit_failed',
`wallet_submit_failed: ${
err instanceof Error ? err.message : String(err)
}`
);
}
}
}
if (preferWallet) {
throw new CodedError(
'wallet_unavailable',
'WalletExecutor not configured for hcs6.createRegistry'
);
}
}
const client = await this.getHCS6Client();
const sanitized = { ...options };
if ('adminKey' in sanitized) {
delete (sanitized as any).adminKey;
}
return await client.createRegistry(sanitized);
}
/**
* Register a new dynamic hashinal entry in an HCS-6 registry
*/
async registerEntry(
registryTopicId: string,
options: HCS6RegisterEntryOptions
): Promise<HCS6RegistryOperationResult> {
const exec = SignerProviderRegistry.walletExecutor;
const preferWallet = SignerProviderRegistry.preferWalletOnly;
const network = (
this.hederaKit.client.network.toString().includes('mainnet')
? 'mainnet'
: 'testnet'
) as NetworkString;
if (exec) {
const start = SignerProviderRegistry.startHCSDelegate;
if (start) {
try {
const request: Record<string, unknown> = { registryTopicId, options };
const { transactionBytes } = await start(
'hcs6.registerEntry',
request,
network
);
if (transactionBytes) {
return { success: true, transactionBytes };
}
} catch (err) {
if (preferWallet) {
throw new CodedError(
'wallet_submit_failed',
`wallet_submit_failed: ${
err instanceof Error ? err.message : String(err)
}`
);
}
}
}
if (preferWallet) {
throw new CodedError(
'wallet_unavailable',
'WalletExecutor not configured for hcs6.registerEntry'
);
}
}
const client = await this.getHCS6Client();
return await client.registerEntry(registryTopicId, options);
}
/**
* Query entries from an HCS-6 registry
*/
async getRegistry(
topicId: string,
options: HCS6QueryRegistryOptions = {}
): Promise<HCS6TopicRegistry> {
const client = await this.getHCS6Client();
return await client.getRegistry(topicId, options);
}
/**
* Create a complete dynamic hashinal with inscription and registry
*/
async createHashinal(
options: HCS6CreateHashinalOptions
): Promise<HCS6CreateHashinalResponse> {
const client = await this.getHCS6Client();
const metadata = {
name: options.metadata?.name || 'Dynamic Hashinal',
creator:
options.metadata?.creator ||
this.hederaKit.signer.getAccountId().toString(),
description: options.metadata?.description || 'Dynamic hashinal metadata',
type: options.metadata?.type || 'json',
...options.metadata,
} as Record<string, unknown>;
return await client.createHashinal({
...options,
metadata,
});
}
/**
* Register a dynamic hashinal with combined inscription and registry creation
* This is the main method for creating and updating dynamic hashinals
*/
async register(
options: HCS6RegisterOptions
): Promise<HCS6CreateHashinalResponse> {
const client = await this.getHCS6Client();
const metadata = {
name: options.metadata?.name || 'Dynamic Hashinal',
creator:
options.metadata?.creator ||
this.hederaKit.signer.getAccountId().toString(),
description:
options.metadata?.description || 'Dynamic hashinal registration',
type: options.metadata?.type || 'json',
...options.metadata,
} as Record<string, unknown>;
return await client.register({
...options,
metadata,
});
}
/**
* Submit a raw message to an HCS-6 topic
*/
async submitMessage(
topicId: string,
payload: any
): Promise<HCS6RegistryOperationResult> {
const exec = SignerProviderRegistry.walletExecutor;
const preferWallet = SignerProviderRegistry.preferWalletOnly;
const network = (
this.hederaKit.client.network.toString().includes('mainnet')
? 'mainnet'
: 'testnet'
) as NetworkString;
if (exec) {
const start = SignerProviderRegistry.startHCSDelegate;
if (start) {
try {
const request: Record<string, unknown> = { topicId, payload };
const { transactionBytes } = await start(
'hcs6.submitMessage',
request,
network
);
if (transactionBytes) {
return {
success: true,
transactionBytes,
} as unknown as HCS6RegistryOperationResult;
}
} catch (err) {
if (preferWallet) {
throw new CodedError(
'wallet_submit_failed',
`wallet_submit_failed: ${
err instanceof Error ? err.message : String(err)
}`
);
}
}
}
if (preferWallet) {
throw new CodedError(
'wallet_unavailable',
'WalletExecutor not configured for hcs6.submitMessage'
);
}
}
const client = await this.getHCS6Client();
return (await client.submitMessage(
topicId,
payload
)) as unknown as HCS6RegistryOperationResult;
}
/**
* Get topic info from mirror node
*/
async getTopicInfo(topicId: string): Promise<TopicResponse> {
const network = this.hederaKit.client.network;
const networkType: NetworkType = network.toString().includes('mainnet')
? 'mainnet'
: 'testnet';
const client = new HederaMirrorNode(networkType);
return await client.getTopicInfo(topicId);
}
/**
* Close the HCS-6 client
*/
async close(): Promise<void> {
if (this.hcs6Client) {
this.hcs6Client.close();
this.hcs6Client = undefined;
}
}
}