UNPKG

@hashgraphonline/conversational-agent

Version:

Hashgraph Online conversational AI agent implementing HCS-10 communication, HCS-2 registries, and content inscription on Hedera

107 lines (106 loc) 4.33 kB
import { StructuredTool } from "@langchain/core/tools"; import { z } from "zod"; import { Logger } from "@hashgraphonline/standards-sdk"; class AirdropToolWrapper extends StructuredTool { constructor(originalTool, agentKit) { super(); this.name = "hedera-hts-airdrop-token"; this.description = "Airdrops fungible tokens to multiple recipients. Automatically converts human-readable amounts to smallest units based on token decimals."; this.schema = z.object({ tokenId: z.string().describe('The ID of the fungible token to airdrop (e.g., "0.0.yyyy").'), recipients: z.array( z.object({ accountId: z.string().describe('Recipient account ID (e.g., "0.0.xxxx").'), amount: z.union([z.number(), z.string()]).describe( 'Amount in human-readable format (e.g., "10" for 10 tokens).' ) }) ).min(1).describe("Array of recipient objects, each with accountId and amount."), memo: z.string().optional().describe("Optional. Memo for the transaction.") }); this.originalTool = originalTool; this.agentKit = agentKit; this.logger = new Logger({ module: "AirdropToolWrapper" }); } async _call(input) { try { this.logger.info( `Processing airdrop request for token ${input.tokenId} with ${input.recipients.length} recipients` ); const tokenInfo = await this.getTokenInfo(input.tokenId); const decimals = tokenInfo.decimals || 0; this.logger.info(`Token ${input.tokenId} has ${decimals} decimal places`); const convertedRecipients = input.recipients.map((recipient) => { const humanAmount = typeof recipient.amount === "string" ? parseFloat(recipient.amount) : recipient.amount; const smallestUnitAmount = this.convertToSmallestUnits( humanAmount, decimals ); this.logger.info( `Converting amount for ${recipient.accountId}: ${humanAmount} tokens → ${smallestUnitAmount} smallest units` ); return { ...recipient, amount: smallestUnitAmount.toString() }; }); const convertedInput = { ...input, recipients: convertedRecipients }; this.logger.info(`Calling original airdrop tool with converted amounts`); return await this.originalTool._call(convertedInput); } catch (error) { this.logger.error("Error in airdrop tool wrapper:", error); throw error; } } convertToSmallestUnits(amount, decimals) { return Math.floor(amount * Math.pow(10, decimals)); } async getTokenInfo(tokenId) { return await this.queryTokenInfo(tokenId); } async queryTokenInfo(tokenId) { try { this.logger.info("Querying token info using mirror node"); const mirrorNode = this.agentKit.mirrorNode; if (!mirrorNode) { this.logger.info( "MirrorNode not found in agentKit, attempting to access via fetch" ); const network = this.agentKit.network || "testnet"; const mirrorNodeUrl = network === "mainnet" ? "https://mainnet.mirrornode.hedera.com" : "https://testnet.mirrornode.hedera.com"; const response = await fetch( `${mirrorNodeUrl}/api/v1/tokens/${tokenId}` ); if (response.ok) { const tokenData = await response.json(); const decimals = parseInt(String(tokenData.decimals || "0")); this.logger.info( `Token ${tokenId} found with ${decimals} decimals via API` ); return { ...tokenData, decimals }; } } else { const tokenData = await mirrorNode.getTokenInfo(tokenId); if (tokenData && typeof tokenData.decimals !== "undefined") { const decimals = parseInt(tokenData.decimals.toString()) || 0; this.logger.info(`Token ${tokenId} found with ${decimals} decimals`); return { ...tokenData, decimals }; } } throw new Error(`Token data not found or missing decimals field`); } catch (error) { this.logger.warn(`Failed to query token info for ${tokenId}:`, error); this.logger.info( "Falling back to assumed 0 decimal places (smallest units)" ); return { decimals: 0 }; } } } export { AirdropToolWrapper }; //# sourceMappingURL=index19.js.map