From e3d1ff1d419696356ab6c10021d694b51a86f79c Mon Sep 17 00:00:00 2001 From: aryan Date: Tue, 19 Nov 2024 00:04:42 +0700 Subject: [PATCH] feat: priorty fee support --- src/agent/index.ts | 4 +- src/langchain/index.ts | 4 +- src/tools/deploy_token.ts | 83 ++++++++++++++++-------------------- src/utils/keypair.ts | 7 +++ src/utils/send_tx.ts | 89 +++++++++++++++++++++++++++++++++++++++ test/index.ts | 9 ++-- 6 files changed, 142 insertions(+), 54 deletions(-) create mode 100644 src/utils/keypair.ts create mode 100644 src/utils/send_tx.ts diff --git a/src/agent/index.ts b/src/agent/index.ts index 543e10c..88deccd 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -43,9 +43,9 @@ export class SolanaAgentKit { async deployToken( decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS, - initialSupply?: number + // initialSupply?: number ) { - return deploy_token(this, decimals, initialSupply); + return deploy_token(this, decimals); } async deployCollection(options: CollectionOptions) { diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 7a9c6ca..0e9f6fd 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -56,8 +56,8 @@ export class SolanaDeployTokenTool extends Tool { const validJson = input .replace(/([a-zA-Z0-9_]+):/g, '"$1":') // Add quotes around keys .trim(); - const { decimals = 9, initialSupply } = JSON.parse(validJson); - const result = await this.solanaKit.deployToken(decimals, initialSupply); + const { decimals = 9 } = JSON.parse(validJson); + const result = await this.solanaKit.deployToken(decimals); return `Token deployed successfully. Mint address: ${result.mint.toString()}`; } catch (error: any) { return `Error deploying token: ${error.message}`; diff --git a/src/tools/deploy_token.ts b/src/tools/deploy_token.ts index c3a40b1..65d537a 100644 --- a/src/tools/deploy_token.ts +++ b/src/tools/deploy_token.ts @@ -1,11 +1,12 @@ import { SolanaAgentKit } from "../index"; import { - createMint, - getOrCreateAssociatedTokenAccount, - mintTo, + createInitializeMint2Instruction, + MINT_SIZE, + getMinimumBalanceForRentExemptAccount, TOKEN_PROGRAM_ID, - Account, } from "@solana/spl-token"; +import { Keypair, SystemProgram, Transaction } from "@solana/web3.js"; +import { sendTx } from "../utils/send_tx"; /** * Deploy a new SPL token @@ -16,61 +17,49 @@ import { */ export async function deploy_token( agent: SolanaAgentKit, - decimals: number = 9, - initialSupply?: number + decimals: number = 9 + // initialSupply?: number ) { try { // Create new token mint - const mint = await createMint( - agent.connection, - agent.wallet, // Payer - agent.wallet_address, // Mint authority - agent.wallet_address, // Freeze authority (optional) + const lamports = await getMinimumBalanceForRentExemptAccount( + agent.connection + ); + + const mint = Keypair.generate(); + + console.log("Mint address: ", mint.publicKey.toString()); + console.log("Agent address: ", agent.wallet_address.toString()); + + let account_create_ix = SystemProgram.createAccount({ + fromPubkey: agent.wallet_address, + newAccountPubkey: mint.publicKey, + lamports, + space: MINT_SIZE, + programId: TOKEN_PROGRAM_ID, + }); + + let create_mint_ix = createInitializeMint2Instruction( + mint.publicKey, decimals, - undefined, // Optional keypair - { - commitment: "confirmed", - }, // Confirmation options + agent.wallet_address, + agent.wallet_address, TOKEN_PROGRAM_ID ); - console.log("Token deployed successfully. Mint address: ", mint.toString()); + let tx = new Transaction().add(account_create_ix, create_mint_ix); - // If initial supply is specified, mint tokens - let tokenAccount: Account | undefined = undefined; - if (initialSupply) { - // Create associated token account for the wallet - tokenAccount = await getOrCreateAssociatedTokenAccount( - agent.connection, - agent.wallet, - mint, - agent.wallet_address - ); + let hash = await sendTx(agent, tx, [mint]); - console.log( - "Token account created successfully. Address: ", - tokenAccount.address.toString() - ); + console.log("Transaction hash: ", hash); - // Mint the initial supply - await mintTo( - agent.connection, - agent.wallet, - mint, - tokenAccount.address, - agent.wallet_address, - initialSupply * Math.pow(10, decimals) - ); - - console.log( - "Tokens minted successfully. Total supply: ", - initialSupply * Math.pow(10, decimals) - ); - } + console.log( + "Token deployed successfully. Mint address: ", + mint.publicKey.toString() + ); return { - mint: mint, - tokenAccount: tokenAccount?.address, + mint: mint.publicKey, }; } catch (error: any) { console.log(error); diff --git a/src/utils/keypair.ts b/src/utils/keypair.ts new file mode 100644 index 0000000..4b2035c --- /dev/null +++ b/src/utils/keypair.ts @@ -0,0 +1,7 @@ +import { Keypair } from "@solana/web3.js"; +import bs58 from "bs58"; + +export const keypair = Keypair.generate(); + +console.log(keypair.publicKey.toString()); +console.log(bs58.encode(keypair.secretKey)); \ No newline at end of file diff --git a/src/utils/send_tx.ts b/src/utils/send_tx.ts new file mode 100644 index 0000000..d757ebe --- /dev/null +++ b/src/utils/send_tx.ts @@ -0,0 +1,89 @@ +import { SolanaAgentKit } from "../agent"; +import { Transaction, Keypair } from "@solana/web3.js"; +import { Connection, ComputeBudgetProgram } from "@solana/web3.js"; + +/** + * Get priority fees for the current block + * @param connection - Solana RPC connection + * @returns Priority fees statistics and instructions for different fee levels + */ +async function getPriorityFees(connection: Connection) { + try { + // Get recent prioritization fees + const priorityFees = await connection.getRecentPrioritizationFees(); + + if (!priorityFees.length) { + return { + min: 0, + median: 0, + max: 0, + }; + } + + // Sort fees by value + const sortedFees = priorityFees + .map((x) => x.prioritizationFee) + .sort((a, b) => a - b); + + // Calculate statistics + const min = sortedFees[0] ?? 0; + const max = sortedFees[sortedFees.length - 1] ?? 0; + const mid = Math.floor(sortedFees.length / 2); + const median = + sortedFees.length % 2 === 0 + ? ((sortedFees[mid - 1] ?? 0) + (sortedFees[mid] ?? 0)) / 2 + : sortedFees[mid] ?? 0; + + // Helper to create priority fee IX based on chosen strategy + const createPriorityFeeIx = (fee: number) => { + return ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: fee, + }); + }; + + return { + min, + median, + max, + // Return instructions for different fee levels + instructions: { + low: createPriorityFeeIx(min), + medium: createPriorityFeeIx(median), + high: createPriorityFeeIx(max), + }, + }; + } catch (error) { + console.error("Error getting priority fees:", error); + throw error; + } +} + +/** + * Send a transaction with priority fees + * @param agent - SolanaAgentKit instance + * @param tx - Transaction to send + * @returns Transaction ID + */ +export async function sendTx( + agent: SolanaAgentKit, + tx: Transaction, + otherKeypairs?: Keypair[] +) { + tx.recentBlockhash = (await agent.connection.getLatestBlockhash()).blockhash; + tx.feePayer = agent.wallet_address; + const fees = await getPriorityFees(agent.connection); + if (fees.instructions) { + tx.add(fees.instructions.medium!); + } + + tx.sign(agent.wallet, ...(otherKeypairs ?? [])); + let txid = await agent.connection.sendRawTransaction(tx.serialize()); + await agent.connection.confirmTransaction({ + signature: txid, + blockhash: (await agent.connection.getLatestBlockhash()).blockhash, + lastValidBlockHeight: ( + await agent.connection.getLatestBlockhash() + ).lastValidBlockHeight, + }); + return txid; +} diff --git a/test/index.ts b/test/index.ts index 566954a..7237497 100644 --- a/test/index.ts +++ b/test/index.ts @@ -8,13 +8,15 @@ import { createReactAgent } from "langchain/agents"; // Initialize SolanaAgentKit const solanaKit = new SolanaAgentKit( - "2bsq2EHutvSvZenGiFSqg4AKMBCP2gB1LnkRiavS4SHKZs4FnDSkGy9c2quiTBuSoKTn9AKV82P1E5D8mkiHJuEW" + "", + "https://mainnet.helius-rpc.com/?api-key=" ); +solanaKit.connection.getRecentPrioritizationFees + // Create Solana-specific tools const tools = createSolanaTools(solanaKit); - (async () => { // Define a Prompt Template for the Agent const prompt = await pull("hwchase17/react"); @@ -34,11 +36,12 @@ const tools = createSolanaTools(solanaKit); const agentExecutor = new AgentExecutor({ agent, tools, + maxIterations: 50, }); const result = await agentExecutor.invoke({ input: - "What is your wallet address?", + "Deploy a token with 6 decimals ", }); console.log(result);