diff --git a/src/agent/index.ts b/src/agent/index.ts index 6ebc6bd..0b97c5e 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -76,6 +76,12 @@ import { multisig_reject_proposal, multisig_approve_proposal, multisig_execute_proposal, + parseTransaction, + sendTransactionWithPriorityFee, + getAssetsByOwner, + getHeliusWebhook, + create_HeliusWebhook, + deleteHeliusWebhook, } from "../tools"; import { Config, @@ -90,6 +96,8 @@ import { OrderParams, FlashTradeParams, FlashCloseTradeParams, + HeliusWebhookIdResponse, + HeliusWebhookResponse, } from "../types"; /** @@ -654,4 +662,36 @@ export class SolanaAgentKit { ): Promise { return multisig_execute_proposal(this, transactionIndex); } + async CreateWebhook( + accountAddresses: string[], + webhookURL: string, + ): Promise { + return create_HeliusWebhook(this, accountAddresses, webhookURL); + } + async getWebhook(id: string): Promise { + return getHeliusWebhook(this, id); + } + async deleteWebhook(webhookID: string): Promise { + return deleteHeliusWebhook(this, webhookID); + } + async heliusParseTransactions(transactionId: string): Promise { + return parseTransaction(this, transactionId); + } + async getAllAssetsbyOwner(owner: PublicKey, limit: number): Promise { + return getAssetsByOwner(this, owner, limit); + } + async sendTranctionWithPriority( + priorityLevel: string, + amount: number, + to: PublicKey, + splmintAddress?: PublicKey, + ): Promise<{ transactionId: string; fee: number }> { + return sendTransactionWithPriorityFee( + this, + priorityLevel, + amount, + to, + splmintAddress, + ); + } } diff --git a/src/langchain/helius/create_webhook.ts b/src/langchain/helius/create_webhook.ts new file mode 100644 index 0000000..05dd6d5 --- /dev/null +++ b/src/langchain/helius/create_webhook.ts @@ -0,0 +1,65 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; + +export class SolanaHeliusWebhookTool extends Tool { + name = "create_helius_webhook"; + description = `Creates a Helius Webhook that listens to specified account addresses. + Inputs (input is a JSON string): + accountAddresses: string[] | string, + e.g. ["BVdNLvyG2DNiWAXBE9qAmc4MTQXymd5Bzfo9xrQSUzVP","Eo2ciguhMLmcTWXELuEQPdu7DWZt67LHXb2rdHZUbot7"] + or "BVdNLvyG2DNiWAXBE9qAmc4MTQXymd5Bzfo9xrQSUzVP,Eo2ciguhMLmcTWXELuEQPdu7DWZt67LHXb2rdHZUbot7" + webhookURL: string, e.g. "https://TestServer.test.repl.co/webhooks"`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + protected async _call(input: string): Promise { + try { + const parsedInput = JSON.parse(input); + let accountAddresses: string[] = []; + + if (!parsedInput.accountAddresses) { + throw new Error('Missing "accountAddresses" property in input JSON.'); + } + if (Array.isArray(parsedInput.accountAddresses)) { + accountAddresses = parsedInput.accountAddresses.map((addr: string) => + addr.trim(), + ); + } else if (typeof parsedInput.accountAddresses === "string") { + accountAddresses = parsedInput.accountAddresses + .split(",") + .map((addr: string) => addr.trim()); + } else { + throw new Error( + 'Invalid type for "accountAddresses". Expected array or comma-separated string.', + ); + } + + const webhookURL = parsedInput.webhookURL; + if (!webhookURL) { + throw new Error( + 'Invalid input. Expected a "webhookURL" property in the JSON.', + ); + } + const result = await this.solanaKit.CreateWebhook( + accountAddresses, + webhookURL, + ); + + // Return success in JSON + return JSON.stringify({ + status: "success", + message: "Helius Webhook created successfully", + webhookURL: result.webhookURL, + webhookID: result.webhookID, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} diff --git a/src/langchain/helius/delete_webhook.ts b/src/langchain/helius/delete_webhook.ts new file mode 100644 index 0000000..dd7d952 --- /dev/null +++ b/src/langchain/helius/delete_webhook.ts @@ -0,0 +1,39 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; + +export class SolanaDeleteHeliusWebhookTool extends Tool { + name = "delete_helius_webhook"; + description = `Deletes a Helius Webhook by its ID. + Inputs (input is a JSON string): + webhookID: string, e.g. "1ed4244d-a591-4854-ac31-cc28d40b8255"`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + protected async _call(input: string): Promise { + try { + const parsedInput = JSON.parse(input); + + const webhookID = parsedInput.webhookID; + if (!webhookID || typeof webhookID !== "string") { + throw new Error( + 'Invalid input. Expected a "webhookID" property in the JSON.', + ); + } + const result = await this.solanaKit.deleteWebhook(webhookID); + + return JSON.stringify({ + status: "success", + message: "Helius Webhook deleted successfully", + data: result, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} diff --git a/src/langchain/helius/get_all_assets.ts b/src/langchain/helius/get_all_assets.ts new file mode 100644 index 0000000..eb06c46 --- /dev/null +++ b/src/langchain/helius/get_all_assets.ts @@ -0,0 +1,38 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; +import { PublicKey } from "@solana/web3.js"; + +export class SolanaGetAllAssetsByOwner extends Tool { + name = "solana_get_all_assets_by_owner"; + description = `Get all assets owned by a specific wallet address. + Inputs: + - owner: string, the wallet address of the owner, e.g., "4Be9CvxqHW6BYiRAxW9Q3xu1ycTMWaL5z8NX4HR3ha7t" (required) + - limit: number, the maximum number of assets to retrieve (optional)`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + protected async _call(input: string): Promise { + try { + const { owner, limit } = JSON.parse(input); + const ownerPubkey = new PublicKey(owner); + + const assets = await this.solanaKit.getAllAssetsbyOwner( + ownerPubkey, + limit, + ); + return JSON.stringify({ + status: "success", + message: "Assets retrieved successfully", + assets: assets, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} diff --git a/src/langchain/helius/get_webhook.ts b/src/langchain/helius/get_webhook.ts new file mode 100644 index 0000000..410580f --- /dev/null +++ b/src/langchain/helius/get_webhook.ts @@ -0,0 +1,43 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; + +export class SolanaGetHeliusWebhookTool extends Tool { + name = "get_helius_webhook"; + description = `Retrieves a Helius Webhook by its ID. + Inputs (input is a JSON string): + webhookID: string, e.g. "1ed4244d-a591-4854-ac31-cc28d40b8255"`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + protected async _call(input: string): Promise { + try { + const parsedInput = JSON.parse(input); + + const webhookID = parsedInput.webhookID; + if (!webhookID || typeof webhookID !== "string") { + throw new Error( + 'Invalid input. Expected a "webhookID" property in the JSON.', + ); + } + + const result = await this.solanaKit.getWebhook(webhookID); + return JSON.stringify({ + status: "success", + message: "Helius Webhook retrieved successfully", + wallet: result.wallet, + webhookURL: result.webhookURL, + transactionTypes: result.transactionTypes, + accountAddresses: result.accountAddresses, + webhookType: result.webhookType, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} diff --git a/src/langchain/helius/index.ts b/src/langchain/helius/index.ts new file mode 100644 index 0000000..652b20e --- /dev/null +++ b/src/langchain/helius/index.ts @@ -0,0 +1,6 @@ +export * from "./create_webhook"; +export * from "./delete_webhook"; +export * from "./get_all_assets"; +export * from "./get_webhook"; +export * from "./parse_transaction"; +export * from "./send_transaction_priority"; diff --git a/src/langchain/helius/parse_transaction.ts b/src/langchain/helius/parse_transaction.ts new file mode 100644 index 0000000..33d318c --- /dev/null +++ b/src/langchain/helius/parse_transaction.ts @@ -0,0 +1,32 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; + +export class SolanaParseTransactionHeliusTool extends Tool { + name = "solana_parse_transaction_helius"; + description = `Parse a Solana transaction using Helius API. + Inputs: + - transactionId: string, the ID of the transaction to parse, e.g., "5h3k...9d2k" (required).`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + protected async _call(input: string): Promise { + try { + const transactionId = input.trim(); + const parsedTransaction = + await this.solanaKit.heliusParseTransactions(transactionId); + return JSON.stringify({ + status: "success", + message: "transaction parsed successfully", + transaction: parsedTransaction, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "NOt able to Parse transaction", + }); + } + } +} diff --git a/src/langchain/helius/send_transaction_priority.ts b/src/langchain/helius/send_transaction_priority.ts new file mode 100644 index 0000000..ee492e5 --- /dev/null +++ b/src/langchain/helius/send_transaction_priority.ts @@ -0,0 +1,63 @@ +import { Tool } from "langchain/tools"; +import { SolanaAgentKit } from "../../agent"; +import { PublicKey } from "@solana/web3.js"; + +export class SolanaSendTransactionWithPriorityFee extends Tool { + name = "solana_send_transaction_with_priority_fee"; + description = `Sends a Solana transaction with a user-defined priority fee. + **Inputs (JSON-encoded string)**: + - priorityLevel: string — the priority level ("NONE", "Min", "Low", "Medium", "High", "VeryHigh", or "UnsafeMax") + - amount: number — the amount of SOL to send + - to: string — the recipient's wallet address (public key in base58);`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + protected async _call(input: string): Promise { + try { + const { priorityLevel, amount, to, splmintAddress } = JSON.parse(input); + + const validPriorityLevels = [ + "NONE", + "Min", + "Low", + "Medium", + "High", + "VeryHigh", + "UnsafeMax", + ]; + if (!validPriorityLevels.includes(priorityLevel)) { + throw new Error( + `Invalid priority level. Must be one of: ${validPriorityLevels.join(", ")}. Received: ${priorityLevel}`, + ); + } + + if (!amount || !to) { + throw new Error( + `Missing required fields. Received: priorityLevel=${priorityLevel}, amount=${amount}, to=${to}`, + ); + } + + const toPubkey = new PublicKey(to); + const priorityFeeTx = await this.solanaKit.sendTranctionWithPriority( + priorityLevel, + amount, + toPubkey, + splmintAddress, + ); + + return JSON.stringify({ + status: "success", + message: "Transaction sent successfully", + priorityFeeTx, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 707a5d2..524b3d0 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -24,6 +24,7 @@ export * from "./tiplink"; export * from "./sns"; export * from "./lightprotocol"; export * from "./squads"; +export * from "./helius"; import { SolanaAgentKit } from "../agent"; import { @@ -91,6 +92,12 @@ import { SolanaApproveProposal2by2Multisig, SolanaExecuteProposal2by2Multisig, SolanaRejectProposal2by2Multisig, + SolanaSendTransactionWithPriorityFee, + SolanaHeliusWebhookTool, + SolanaGetHeliusWebhookTool, + SolanaDeleteHeliusWebhookTool, + SolanaParseTransactionHeliusTool, + SolanaGetAllAssetsByOwner, } from "./index"; export function createSolanaTools(solanaKit: SolanaAgentKit) { @@ -159,5 +166,11 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) { new SolanaExecuteProposal2by2Multisig(solanaKit), new SolanaDepositTo2by2Multisig(solanaKit), new SolanaTransferFrom2by2Multisig(solanaKit), + new SolanaSendTransactionWithPriorityFee(solanaKit), + new SolanaHeliusWebhookTool(solanaKit), + new SolanaGetHeliusWebhookTool(solanaKit), + new SolanaDeleteHeliusWebhookTool(solanaKit), + new SolanaParseTransactionHeliusTool(solanaKit), + new SolanaGetAllAssetsByOwner(solanaKit), ]; } diff --git a/src/tools/helius/get_assets_by_owner.ts b/src/tools/helius/get_assets_by_owner.ts new file mode 100644 index 0000000..05d225c --- /dev/null +++ b/src/tools/helius/get_assets_by_owner.ts @@ -0,0 +1,57 @@ +import { SolanaAgentKit } from "../../index"; +import { PublicKey } from "@solana/web3.js"; + +/** + * Fetch assets by owner using the Helius Digital Asset Standard (DAS) API + * @param agent SolanaAgentKit instance + * @param ownerPublicKey Owner's Solana wallet PublicKey + * @param limit Number of assets to retrieve per request + * @returns Assets owned by the specified address + */ +export async function getAssetsByOwner( + agent: SolanaAgentKit, + ownerPublicKey: PublicKey, + limit: number, +): Promise { + try { + const apiKey = agent.config.HELIUS_API_KEY; + if (!apiKey) { + throw new Error("HELIUS_API_KEY not found in environment variables"); + } + + const url = `https://mainnet.helius-rpc.com/?api-key=${apiKey}`; + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "get-assets", + method: "getAssetsByOwner", + params: { + ownerAddress: ownerPublicKey.toString(), + page: 3, + limit: limit, + displayOptions: { + showFungible: true, + }, + }, + }), + }); + + if (!response.ok) { + throw new Error( + `Failed to fetch: ${response.status} - ${response.statusText}`, + ); + } + + const data = await response.json(); + + return data.result.items; + } catch (error: any) { + console.error("Error retrieving assets: ", error.message); + throw new Error(`Assets retrieval failed: ${error.message}`); + } +} diff --git a/src/tools/helius/helius_transaction_parsing.ts b/src/tools/helius/helius_transaction_parsing.ts new file mode 100644 index 0000000..54a39a6 --- /dev/null +++ b/src/tools/helius/helius_transaction_parsing.ts @@ -0,0 +1,44 @@ +import { SolanaAgentKit } from "../../index"; + +/** + * Parse a Solana transaction using the Helius Enhanced Transactions API + * @param agent SolanaAgentKit instance + * @param transactionId The transaction ID to parse + * @returns Parsed transaction data + */ +export async function parseTransaction( + agent: SolanaAgentKit, + transactionId: string, +): Promise { + try { + const apiKey = agent.config.HELIUS_API_KEY; + if (!apiKey) { + throw new Error("HELIUS_API_KEY not found in environment variables"); + } + + const url = `https://api.helius.xyz/v0/transactions/?api-key=${apiKey}`; + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + transactions: [transactionId], + }), + }); + + if (!response.ok) { + throw new Error( + `Failed to fetch: ${response.status} - ${response.statusText}`, + ); + } + + const data = await response.json(); + + return data; + } catch (error: any) { + console.error("Error parsing transaction: ", error.message); + throw new Error(`Transaction parsing failed: ${error.message}`); + } +} diff --git a/src/tools/helius/helius_webhooks.ts b/src/tools/helius/helius_webhooks.ts new file mode 100644 index 0000000..48a16e3 --- /dev/null +++ b/src/tools/helius/helius_webhooks.ts @@ -0,0 +1,132 @@ +import { SolanaAgentKit } from "../../index"; +import { HeliusWebhookResponse, HeliusWebhookIdResponse } from "../../index"; + +export async function create_HeliusWebhook( + agent: SolanaAgentKit, + accountAddresses: string[], + webhookURL: string, +): Promise { + try { + const response = await fetch( + `https://api.helius.xyz/v0/webhooks?api-key=${agent.config.HELIUS_API_KEY}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + webhookURL, + transactionTypes: ["Any"], + accountAddresses, + webhookType: "enhanced", + txnStatus: "all", + }), + }, + ); + + const data = await response.json(); + return { + webhookURL: data.webhookURL, + webhookID: data.webhookID, + }; + } catch (error: any) { + throw new Error(`Failed to create Webhook: ${error.message}`); + } +} + +/** + * Retrieves a Helius Webhook by ID, returning only the specified fields. + * + * @param agent - An instance of SolanaAgentKit (with .config.HELIUS_API_KEY) + * @param webhookID - The unique ID of the webhook to retrieve + * + * @returns A HeliusWebhook object containing { wallet, webhookURL, transactionTypes, accountAddresses, webhookType } + */ +export async function getHeliusWebhook( + agent: SolanaAgentKit, + webhookID: string, +): Promise { + try { + const apiKey = agent.config.HELIUS_API_KEY; + if (!apiKey) { + throw new Error("HELIUS_API_KEY is missing in agent.config"); + } + + const response = await fetch( + `https://api.helius.xyz/v0/webhooks/${webhookID}?api-key=${apiKey}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }, + ); + + if (!response.ok) { + throw new Error( + `Failed to fetch webhook with ID ${webhookID}. ` + + `Status Code: ${response.status}`, + ); + } + + const data = await response.json(); + + return { + wallet: data.wallet, + webhookURL: data.webhookURL, + transactionTypes: data.transactionTypes, + accountAddresses: data.accountAddresses, + webhookType: data.webhookType, + }; + } catch (error: any) { + throw new Error(`Failed to get webhook by ID: ${error.message}`); + } +} + +/** + * Deletes a Helius Webhook by its ID. + * + * @param agent - An instance of SolanaAgentKit (with .config.HELIUS_API_KEY) + * @param webhookID - The unique ID of the webhook to delete + * + * @returns The response body from the Helius API (which may contain status or other info) + */ +export async function deleteHeliusWebhook( + agent: SolanaAgentKit, + webhookID: string, +): Promise { + try { + const apiKey = agent.config.HELIUS_API_KEY; + if (!apiKey) { + throw new Error("Missing Helius API key in agent.config.HELIUS_API_KEY"); + } + + const url = `https://api.helius.xyz/v0/webhooks/${webhookID}?api-key=${apiKey}`; + const response = await fetch(url, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error( + `Failed to delete webhook: ${response.status} ${response.statusText}`, + ); + } + if (response.status === 204) { + return { message: "Webhook deleted successfully (no content returned)" }; + } + const contentLength = response.headers.get("Content-Length"); + if (contentLength === "0" || !contentLength) { + return { message: "Webhook deleted successfully (empty body)" }; + } + + // Otherwise, parse as JSON + const data = await response.json(); + return data; + } catch (error: any) { + console.error("Error deleting Helius Webhook:", error.message); + throw new Error(`Failed to delete Helius Webhook: ${error.message}`); + } +} diff --git a/src/tools/helius/index.ts b/src/tools/helius/index.ts new file mode 100644 index 0000000..cec732b --- /dev/null +++ b/src/tools/helius/index.ts @@ -0,0 +1,4 @@ +export * from "./get_assets_by_owner"; +export * from "./helius_transaction_parsing"; +export * from "./helius_webhooks"; +export * from "./send_transaction_with_priority"; diff --git a/src/tools/helius/send_transaction_with_priority.ts b/src/tools/helius/send_transaction_with_priority.ts new file mode 100644 index 0000000..3d49401 --- /dev/null +++ b/src/tools/helius/send_transaction_with_priority.ts @@ -0,0 +1,174 @@ +import { SolanaAgentKit, PriorityFeeResponse } from "../../index"; +import { + SystemProgram, + Transaction, + sendAndConfirmTransaction, + ComputeBudgetProgram, + PublicKey, + LAMPORTS_PER_SOL, +} from "@solana/web3.js"; +import { + getAssociatedTokenAddress, + createTransferInstruction, + getMint, + createAssociatedTokenAccountInstruction, +} from "@solana/spl-token"; +import bs58 from "bs58"; + +/** + * Sends a transaction with an estimated priority fee using the provided SolanaAgentKit. + * + * @param agent An instance of SolanaAgentKit containing connection, wallet, etc. + * @param priorityLevel The priority level (e.g., "Min", "Low", "Medium", "High", "VeryHigh", or "UnsafeMax"). + * @param amount The amount of SOL to send (in SOL, not lamports). + * @param to The recipient's PublicKey. + * @returns The transaction signature (string) once confirmed along with the fee used. + */ +export async function sendTransactionWithPriorityFee( + agent: SolanaAgentKit, + priorityLevel: string, + amount: number, + to: PublicKey, + splmintAddress?: PublicKey, +): Promise<{ transactionId: string; fee: number }> { + try { + if (!splmintAddress) { + const transaction = new Transaction(); + const { blockhash, lastValidBlockHeight } = + await agent.connection.getLatestBlockhash(); + transaction.recentBlockhash = blockhash; + transaction.lastValidBlockHeight = lastValidBlockHeight; + transaction.feePayer = agent.wallet_address; + + const transferIx = SystemProgram.transfer({ + fromPubkey: agent.wallet_address, + toPubkey: to, + lamports: amount * LAMPORTS_PER_SOL, + }); + + transaction.add(transferIx); + transaction.sign(agent.wallet); + + const response = await fetch( + `https://mainnet.helius-rpc.com/?api-key=${agent.config.HELIUS_API_KEY}`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "1", + method: "getPriorityFeeEstimate", + params: [ + { + transaction: bs58.encode(transaction.serialize()), + options: { priorityLevel: priorityLevel }, + }, + ], + } as PriorityFeeResponse), + }, + ); + + const data = await response.json(); + if (data.error) { + throw new Error("Error fetching priority fee:"); + } + const feeEstimate: number = data.result.priorityFeeEstimate; + + // Set the priority fee if applicable + const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: feeEstimate, + }); + transaction.add(computePriceIx); + + // Send the transaction and confirm + const txSignature = await sendAndConfirmTransaction( + agent.connection, + transaction, + [agent.wallet], + ); + + return { + transactionId: txSignature, + fee: feeEstimate, + }; + } else { + const fromAta = await getAssociatedTokenAddress( + splmintAddress, + agent.wallet_address, + ); + const toAta = await getAssociatedTokenAddress(splmintAddress, to); + + const mintInfo = await getMint(agent.connection, splmintAddress); + const adjustedAmount = amount * Math.pow(10, mintInfo.decimals); + + const transaction = new Transaction(); + const { blockhash, lastValidBlockHeight } = + await agent.connection.getLatestBlockhash(); + transaction.recentBlockhash = blockhash; + transaction.lastValidBlockHeight = lastValidBlockHeight; + transaction.feePayer = agent.wallet_address; + + const response = await fetch( + `https://mainnet.helius-rpc.com/?api-key=${agent.config.HELIUS_API_KEY}`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "1", + method: "getPriorityFeeEstimate", + params: [ + { + transaction: bs58.encode(transaction.serialize()), + options: { priorityLevel: priorityLevel }, + }, + ], + } as PriorityFeeResponse), + }, + ); + + const data = await response.json(); + if (data.error) { + throw new Error("Error fetching priority fee:"); + } + const feeEstimate: number = data.result.priorityFeeEstimate; + + transaction.add( + ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: feeEstimate, + }), + ); + + transaction.add( + createAssociatedTokenAccountInstruction( + agent.wallet_address, + toAta, + to, + splmintAddress, + ), + ); + + transaction.add( + createTransferInstruction( + fromAta, + toAta, + agent.wallet_address, + adjustedAmount, + ), + ); + + const txSignature = await sendAndConfirmTransaction( + agent.connection, + transaction, + [agent.wallet], + ); + + return { + transactionId: txSignature, + fee: feeEstimate, + }; + } + } catch (error: any) { + throw new Error(`Failed to process transaction: ${error.message}`); + } +} diff --git a/src/tools/index.ts b/src/tools/index.ts index 6a546e9..c63e4bc 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -23,3 +23,5 @@ export * from "./3land"; export * from "./tiplink"; export * from "./lightprotocol"; export * from "./squads"; +export * from "./squads_multisig"; +export * from "./helius"; diff --git a/src/types/index.ts b/src/types/index.ts index 01ac152..2c0a54c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -7,6 +7,7 @@ export interface Config { JUPITER_REFERRAL_ACCOUNT?: string; JUPITER_FEE_BPS?: number; FLASH_PRIVILEGE?: string; + HELIUS_API_KEY?: string; } export interface Creator { @@ -237,3 +238,25 @@ export interface FlashCloseTradeParams { token: string; side: "long" | "short"; } + +export interface HeliusWebhookResponse { + webhookURL: string; + webhookID: string; +} +export interface HeliusWebhookIdResponse { + wallet: string; + webhookURL: string; + transactionTypes: string[]; + accountAddresses: string[]; + webhookType: string; +} + +export interface PriorityFeeResponse { + jsonrpc: string; + id: string; + method: string; + params: Array<{ + transaction: string; + options: { priorityLevel: string }; + }>; +} diff --git a/test/index.ts b/test/index.ts index 00f9976..c666d33 100644 --- a/test/index.ts +++ b/test/index.ts @@ -55,6 +55,7 @@ async function initializeAgent() { process.env.RPC_URL!, { OPENAI_API_KEY: process.env.OPENAI_API_KEY!, + HELIUS_API_KEY: process.env.HELIUS_API_KEY!, }, );