diff --git a/src/agent/index.ts b/src/agent/index.ts index e57f13d..5886fb4 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -623,6 +623,13 @@ export class SolanaAgentKit { ); return `Transaction: ${tx}`; } + async sendTranctionWithPriority( + priorityLevel: string, + amount: number, + to: PublicKey, + ): Promise { + return sendTransactionWithPriorityFee(this, priorityLevel, amount, to); + } async createSquadsMultisig(creator: PublicKey): Promise { return create_squads_multisig(this, creator); diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 524b3d0..1bf9113 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -100,6 +100,51 @@ import { SolanaGetAllAssetsByOwner, } from "./index"; +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 } = JSON.parse(input); + + if (!priorityLevel || !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, + ); + + 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", + }); + } + } +} + export function createSolanaTools(solanaKit: SolanaAgentKit) { return [ new SolanaBalanceTool(solanaKit), diff --git a/src/tools/get_assets_by_owner.ts b/src/tools/get_assets_by_owner.ts index 1f5d917..45f3dbe 100644 --- a/src/tools/get_assets_by_owner.ts +++ b/src/tools/get_assets_by_owner.ts @@ -1,7 +1,5 @@ import { SolanaAgentKit } from "../index"; import { PublicKey } from "@solana/web3.js"; -import * as dotenv from "dotenv"; -dotenv.config(); /** * Fetch assets by owner using the Helius Digital Asset Standard (DAS) API diff --git a/src/tools/helius_transaction_parsing.ts b/src/tools/helius_transaction_parsing.ts index 8ab5176..1f24ee3 100644 --- a/src/tools/helius_transaction_parsing.ts +++ b/src/tools/helius_transaction_parsing.ts @@ -1,6 +1,4 @@ import { SolanaAgentKit } from "../index"; -import * as dotenv from "dotenv"; -dotenv.config(); /** * Parse a Solana transaction using the Helius Enhanced Transactions API diff --git a/src/tools/send_transaction_with_priority.ts b/src/tools/send_transaction_with_priority.ts new file mode 100644 index 0000000..66417f1 --- /dev/null +++ b/src/tools/send_transaction_with_priority.ts @@ -0,0 +1,119 @@ +import { SolanaAgentKit } from "../agent"; +import { + SystemProgram, + Transaction, + sendAndConfirmTransaction, + ComputeBudgetProgram, + PublicKey, + LAMPORTS_PER_SOL, +} from "@solana/web3.js"; +import bs58 from "bs58"; +import { PriorityFeeTransaction } from "../types"; + +/** + * Fetches an estimated priority fee (in microLamports) from Helius. + * + * @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 transaction The (unsigned or partially-signed) Transaction you want to estimate fees for. + * @returns The numeric priority fee estimate in microLamports. + */ +export async function getPriorityFeeEstimate( + agent: SolanaAgentKit, + priorityLevel: string, + transaction: Transaction, +): Promise { + const apiKey = agent.config.HELIUS_API_KEY; + if (!apiKey) { + throw new Error( + "HELIUS_API_KEY not found in agent.config or environment variables", + ); + } + + const url = `https://api.helius.xyz/v0/transactions/?api-key=${apiKey}`; + + const payload = { + jsonrpc: "2.0", + id: "1", + method: "getPriorityFeeEstimate", + params: [ + { + transaction: bs58.encode(transaction.serialize()), + options: { priorityLevel }, + }, + ], + }; + const response = await fetch(url, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }); + + if (!response.ok) { + throw new Error(`Helius request failed with status ${response.status}`); + } + + const data = await response.json(); + if (!data.result || data.result.priorityFeeEstimate === undefined) { + throw new Error(`Invalid response from Helius: ${JSON.stringify(data)}`); + } + + return data.result.priorityFeeEstimate; +} + +/** + * Sends a transaction with an optional priority fee using the provided SolanaAgentKit. + * + * @param agent An instance of SolanaAgentKit containing connection, wallet, etc. + * @param priorityLevel The priority level ("NONE", "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. + */ + +export async function sendTransactionWithPriorityFee( + agent: SolanaAgentKit, + priorityLevel: string, + amount: number, + to: PublicKey, +): Promise { + const transaction = new Transaction(); + + const transferIx = SystemProgram.transfer({ + fromPubkey: agent.wallet_address, + toPubkey: to, + lamports: amount * LAMPORTS_PER_SOL, + }); + transaction.add(transferIx); + + let feeEstimate = 0; + if (priorityLevel !== "NONE") { + feeEstimate = await getPriorityFeeEstimate( + agent, + priorityLevel, + transaction, + ); + if (feeEstimate > 0) { + const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: feeEstimate, + }); + transaction.add(computePriceIx); + } + } + + transaction.recentBlockhash = ( + await agent.connection.getLatestBlockhash() + ).blockhash; + transaction.sign(agent.wallet); + + const txSignature = await sendAndConfirmTransaction( + agent.connection, + transaction, + [agent.wallet], + ); + + return { + transactionId: txSignature, + fee: feeEstimate, + }; +} diff --git a/src/types/index.ts b/src/types/index.ts index 2c0a54c..2d733b7 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -238,25 +238,3 @@ 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 }; - }>; -}