UNPKG

@hashgraphonline/standards-sdk

Version:

The Hashgraph Online Standards SDK provides a complete implementation of the Hashgraph Consensus Standards (HCS), giving developers all the tools needed to build applications on Hedera.

408 lines (407 loc) • 11.9 kB
import { TopicCreateTransaction, AccountId, TopicMessageSubmitTransaction, TopicId, Hbar } from "@hashgraph/sdk"; import { HCS20BaseClient } from "./standards-sdk.es18.js"; import { PointsValidationError, TopicRegistrationError } from "./standards-sdk.es17.js"; class BrowserHCS20Client extends HCS20BaseClient { constructor(config) { super({ network: config.network, logger: config.logger, mirrorNodeUrl: config.mirrorNodeUrl, registryTopicId: config.registryTopicId, publicTopicId: config.publicTopicId }); this.hwc = config.hwc; this.feeAmount = config.feeAmount || 20; } /** * Get operator account ID */ getOperatorId() { const accountInfo = this.hwc.getAccountInfo(); if (!accountInfo?.accountId) { throw new Error("Wallet not connected"); } return accountInfo.accountId; } /** * Deploy new points */ async deployPoints(options) { const operatorId = this.getOperatorId(); const { progressCallback } = options; try { progressCallback?.({ stage: "creating-topic", percentage: 20 }); let topicId; if (options.usePrivateTopic) { const publicKey = await this.mirrorNode.getPublicKey(operatorId); const topicCreateTx = new TopicCreateTransaction().setTopicMemo(options.topicMemo || `HCS-20: ${options.name}`).setSubmitKey(publicKey).setAdminKey(publicKey).setAutoRenewAccountId(AccountId.fromString(operatorId)); const txResponse = await this.hwc.executeTransactionWithErrorHandling( topicCreateTx, false ); if (txResponse?.error) { throw new Error(txResponse.error); } const receipt = txResponse?.result; if (!receipt?.topicId) { throw new Error("Failed to create topic: topicId is null"); } topicId = receipt.topicId.toString(); this.logger.info(`Created private topic: ${topicId}`); } else { topicId = this.publicTopicId; } progressCallback?.({ stage: "submitting-deploy", percentage: 50, topicId }); const deployMessage = { p: "hcs-20", op: "deploy", name: options.name, tick: this.normalizeTick(options.tick), max: options.maxSupply, lim: options.limitPerMint, metadata: options.metadata, m: options.topicMemo }; const validation = this.validateMessage(deployMessage); if (!validation.valid) { throw new PointsValidationError( "Invalid deploy message", validation.errors ); } const deployResult = await this.submitPayload( topicId, deployMessage, options.usePrivateTopic ); const deployTxId = deployResult.transactionHash?.toString() || ""; progressCallback?.({ stage: "confirming", percentage: 80, topicId, deployTxId }); await new Promise((resolve) => setTimeout(resolve, 2e3)); progressCallback?.({ stage: "complete", percentage: 100, topicId, deployTxId }); return { name: options.name, tick: this.normalizeTick(options.tick), maxSupply: options.maxSupply, limitPerMint: options.limitPerMint, metadata: options.metadata, topicId, deployerAccountId: operatorId, currentSupply: "0", deploymentTimestamp: (/* @__PURE__ */ new Date()).toISOString(), isPrivate: options.usePrivateTopic || false }; } catch (error) { progressCallback?.({ stage: "complete", percentage: 100, error: error instanceof Error ? error.message : "Unknown error" }); throw error; } } /** * Mint points */ async mintPoints(options) { this.getOperatorId(); const { progressCallback } = options; try { progressCallback?.({ stage: "validating", percentage: 20 }); progressCallback?.({ stage: "submitting", percentage: 50 }); const mintMessage = { p: "hcs-20", op: "mint", tick: this.normalizeTick(options.tick), amt: options.amount, to: this.accountToString(options.to), m: options.memo }; const topicId = options.topicId || this.publicTopicId; const mintResult = await this.submitPayload( topicId, mintMessage, false ); const mintTxId = mintResult.transactionHash?.toString() || ""; progressCallback?.({ stage: "confirming", percentage: 80, mintTxId }); await new Promise((resolve) => setTimeout(resolve, 2e3)); progressCallback?.({ stage: "complete", percentage: 100, mintTxId }); return { id: mintTxId, operation: "mint", tick: this.normalizeTick(options.tick), amount: options.amount, to: this.accountToString(options.to), timestamp: (/* @__PURE__ */ new Date()).toISOString(), sequenceNumber: 0, topicId, transactionId: mintTxId, memo: options.memo }; } catch (error) { progressCallback?.({ stage: "complete", percentage: 100, error: error instanceof Error ? error.message : "Unknown error" }); throw error; } } /** * Transfer points */ async transferPoints(options) { this.getOperatorId(); const { progressCallback } = options; try { progressCallback?.({ stage: "validating-balance", percentage: 20 }); progressCallback?.({ stage: "submitting", percentage: 50 }); const transferMessage = { p: "hcs-20", op: "transfer", tick: this.normalizeTick(options.tick), amt: options.amount, from: this.accountToString(options.from), to: this.accountToString(options.to), m: options.memo }; const topicId = options.topicId || this.publicTopicId; const transferResult = await this.submitPayload( topicId, transferMessage, false ); const transferTxId = transferResult.transactionHash?.toString() || ""; progressCallback?.({ stage: "confirming", percentage: 80, transferTxId }); await new Promise((resolve) => setTimeout(resolve, 2e3)); progressCallback?.({ stage: "complete", percentage: 100, transferTxId }); return { id: transferTxId, operation: "transfer", tick: this.normalizeTick(options.tick), amount: options.amount, from: this.accountToString(options.from), to: this.accountToString(options.to), timestamp: (/* @__PURE__ */ new Date()).toISOString(), sequenceNumber: 0, topicId, transactionId: transferTxId, memo: options.memo }; } catch (error) { progressCallback?.({ stage: "complete", percentage: 100, error: error instanceof Error ? error.message : "Unknown error" }); throw error; } } /** * Burn points */ async burnPoints(options) { this.getOperatorId(); const { progressCallback } = options; try { progressCallback?.({ stage: "validating-balance", percentage: 20 }); progressCallback?.({ stage: "submitting", percentage: 50 }); const burnMessage = { p: "hcs-20", op: "burn", tick: this.normalizeTick(options.tick), amt: options.amount, from: this.accountToString(options.from), m: options.memo }; const topicId = options.topicId || this.publicTopicId; const burnResult = await this.submitPayload( topicId, burnMessage, false ); const burnTxId = burnResult.transactionHash?.toString() || ""; progressCallback?.({ stage: "confirming", percentage: 80, burnTxId }); await new Promise((resolve) => setTimeout(resolve, 2e3)); progressCallback?.({ stage: "complete", percentage: 100, burnTxId }); return { id: burnTxId, operation: "burn", tick: this.normalizeTick(options.tick), amount: options.amount, from: this.accountToString(options.from), timestamp: (/* @__PURE__ */ new Date()).toISOString(), sequenceNumber: 0, topicId, transactionId: burnTxId, memo: options.memo }; } catch (error) { progressCallback?.({ stage: "complete", percentage: 100, error: error instanceof Error ? error.message : "Unknown error" }); throw error; } } /** * Register a topic in the registry */ async registerTopic(options) { const { progressCallback } = options; try { progressCallback?.({ stage: "validating", percentage: 20 }); const registerMessage = { p: "hcs-20", op: "register", name: options.name, metadata: options.metadata, private: options.isPrivate, t_id: this.topicToString(options.topicId), m: options.memo }; const validation = this.validateMessage(registerMessage); if (!validation.valid) { throw new PointsValidationError( "Invalid register message", validation.errors ); } progressCallback?.({ stage: "submitting", percentage: 50 }); const registerResult = await this.submitPayload( this.registryTopicId, registerMessage, false ); const registerTxId = registerResult.transactionHash?.toString() || ""; progressCallback?.({ stage: "confirming", percentage: 80, registerTxId }); await new Promise((resolve) => setTimeout(resolve, 2e3)); progressCallback?.({ stage: "complete", percentage: 100, registerTxId }); } catch (error) { progressCallback?.({ stage: "complete", percentage: 100, error: error instanceof Error ? error.message : "Unknown error" }); throw new TopicRegistrationError( error instanceof Error ? error.message : "Unknown error", this.topicToString(options.topicId) ); } } /** * Submit payload to topic using HWC */ async submitPayload(topicId, payload, requiresFee) { this.logger.debug(`Submitting payload to topic ${topicId}`); let message; if (typeof payload === "string") { message = payload; } else { message = JSON.stringify(payload); } const transaction = new TopicMessageSubmitTransaction().setTopicId(TopicId.fromString(topicId)).setMessage(message); if (requiresFee) { this.logger.info( "Topic requires fee payment, setting max transaction fee" ); transaction.setMaxTransactionFee(new Hbar(this.feeAmount)); } const transactionResponse = await this.hwc.executeTransactionWithErrorHandling( transaction, false ); if (transactionResponse?.error) { this.logger.error( `Failed to submit payload: ${transactionResponse.error}` ); throw new Error(`Failed to submit payload: ${transactionResponse.error}`); } if (!transactionResponse?.result) { this.logger.error( "Failed to submit message: receipt is null or undefined" ); throw new Error("Failed to submit message: receipt is null or undefined"); } this.logger.debug("Payload submitted successfully via HWC"); return transactionResponse.result; } } export { BrowserHCS20Client }; //# sourceMappingURL=standards-sdk.es19.js.map