diff --git a/README.md b/README.md index 2dd01d8..8b7ae7d 100644 --- a/README.md +++ b/README.md @@ -104,9 +104,7 @@ import { PublicKey } from '@solana/web3.js'; const signature = await lendAsset( agent, - new PublicKey('asset-mint'), 100, // amount - "lulo-api-key" ); ``` diff --git a/src/agent/index.ts b/src/agent/index.ts index 483763d..0d7a4ef 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -10,6 +10,8 @@ import { trade, registerDomain, launchPumpFunToken, + lendAsset, + getTPS, } from "../tools"; import { CollectionOptions, PumpFunTokenOptions } from "../types"; import { DEFAULT_OPTIONS } from "../constants"; @@ -32,7 +34,7 @@ export class SolanaAgentKit { constructor( private_key: string, rpc_url = "https://api.mainnet-beta.solana.com", - openai_api_key: string + openai_api_key: string, ) { this.connection = new Connection(rpc_url); this.wallet = Keypair.fromSecretKey(bs58.decode(private_key)); @@ -46,7 +48,7 @@ export class SolanaAgentKit { } async deployToken( - decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS + decimals: number = DEFAULT_OPTIONS.TOKEN_DECIMALS, // initialSupply?: number ) { return deploy_token(this, decimals); @@ -63,7 +65,7 @@ export class SolanaAgentKit { async mintNFT( collectionMint: PublicKey, metadata: Parameters[2], - recipient?: PublicKey + recipient?: PublicKey, ) { return mintCollectionNFT(this, collectionMint, metadata, recipient); } @@ -80,17 +82,25 @@ export class SolanaAgentKit { outputMint: PublicKey, inputAmount: number, inputMint?: PublicKey, - slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS + slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS, ) { return trade(this, outputMint, inputAmount, inputMint, slippageBps); } + async lendAssets(amount: number) { + return lendAsset(this, amount); + } + + async getTPS() { + return getTPS(this); + } + async launchPumpFunToken( tokenName: string, tokenTicker: string, description: string, imageUrl: string, - options?: PumpFunTokenOptions + options?: PumpFunTokenOptions, ) { return launchPumpFunToken( this, @@ -98,7 +108,7 @@ export class SolanaAgentKit { tokenTicker, description, imageUrl, - options + options, ); } } diff --git a/src/constants/index.ts b/src/constants/index.ts index dfcc9f6..7c1d9c5 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -28,8 +28,3 @@ export const DEFAULT_OPTIONS = { * Jupiter API URL */ export const JUP_API = "https://quote-api.jup.ag/v6"; - -/** - * LULO (fka Flexlend) API URL - */ -export const LULO_API = "https://api.flexlend.fi"; diff --git a/src/langchain/index.ts b/src/langchain/index.ts index da063c1..2ba3b23 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -42,7 +42,7 @@ export class SolanaTransferTool extends Tool { name = "solana_transfer"; description = `Transfer tokens or SOL to another address ( also called as wallet address ). - Inputs ( input is a JSON string ): + Inputs ( input is a JSON string ): to: string, eg "8x2dR8Mpzuz2YqyZyZjUbYWKSWesBo5jMx2Q9Y86udVk" (required) amount: number, eg 1 (required) mint?: string, eg "So11111111111111111111111111111111111111112" or "SENDdRQtYMWaQrBroBrJ2Q53fgVuq95CV9UPGEvpCxa" (optional)`; @@ -409,9 +409,9 @@ export class SolanaPumpfunTokenLaunchTool extends Tool { description = `This tool can be used to launch a token on Pump.fun, do not use this tool for any other purpose, or for creating SPL tokens. - If the user asks you to chose the parameters, you should generate valid values. + If the user asks you to chose the parameters, you should generate valid values. For generating the image, you can use the solana_create_image tool. - + Inputs: tokenName: string, eg "PumpFun Token", tokenTicker: string, eg "PUMP", @@ -517,6 +517,57 @@ export class SolanaCreateImageTool extends Tool { } } +export class SolanaLendAssetTool extends Tool { + name = "solana_lend_asset"; + description = `Lend idle USDC for yield using Lulo. ( only USDC is supported ) + + Inputs (input is a json string): + amount: number, eg 1, 0.01 (required)`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + async _call(input: string): Promise { + try { + let amount = JSON.parse(input).amount || input; + + const tx = await this.solanaKit.lendAssets(amount); + + return JSON.stringify({ + status: "success", + message: "Asset lent successfully", + transaction: tx, + amount: amount, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} + +export class SolanaTPSCalculatorTool extends Tool { + name = "solana_get_tps"; + description = "Get the current TPS of the Solana network"; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + async _call(_input: string): Promise { + try { + const tps = await this.solanaKit.getTPS(); + return `Solana (mainnet-beta) current transactions per second: ${tps}`; + } catch (error: any) { + return `Error fetching TPS: ${error.message}`; + } + } +} + export function createSolanaTools(solanaKit: SolanaAgentKit) { return [ new SolanaBalanceTool(solanaKit), @@ -530,5 +581,7 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) { new SolanaGetWalletAddressTool(solanaKit), new SolanaPumpfunTokenLaunchTool(solanaKit), new SolanaCreateImageTool(solanaKit), + new SolanaLendAssetTool(solanaKit), + new SolanaTPSCalculatorTool(solanaKit), ]; } diff --git a/src/tools/create_image.ts b/src/tools/create_image.ts index e2c4bd4..7fbb2cf 100644 --- a/src/tools/create_image.ts +++ b/src/tools/create_image.ts @@ -13,7 +13,7 @@ export async function create_image( agent: SolanaAgentKit, prompt: string, size: "256x256" | "512x512" | "1024x1024" = "1024x1024", - n: number = 1 + n: number = 1, ) { try { if (!agent.openai_api_key) { @@ -21,7 +21,7 @@ export async function create_image( } const openai = new OpenAI({ - apiKey: agent.openai_api_key + apiKey: agent.openai_api_key, }); const response = await openai.images.generate({ @@ -31,9 +31,8 @@ export async function create_image( }); return { - images: response.data.map((img) => img.url), + images: response.data.map((img: any) => img.url), }; - } catch (error: any) { throw new Error(`Image generation failed: ${error.message}`); } diff --git a/src/tools/index.ts b/src/tools/index.ts index b559ab4..b9ca5ae 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -1,9 +1,11 @@ -export * from './request_faucet_funds'; -export * from './deploy_token'; -export * from './deploy_collection'; -export * from './get_balance'; -export * from './mint_nft'; -export * from './transfer'; -export * from './trade'; -export * from './register_domain'; -export * from './launch_pumpfun_token'; +export * from "./request_faucet_funds"; +export * from "./deploy_token"; +export * from "./deploy_collection"; +export * from "./get_balance"; +export * from "./mint_nft"; +export * from "./transfer"; +export * from "./trade"; +export * from "./register_domain"; +export * from "./launch_pumpfun_token"; +export * from "./lend"; +export * from "./get_tps"; diff --git a/src/tools/lend.ts b/src/tools/lend.ts index 5fd85b7..7889343 100644 --- a/src/tools/lend.ts +++ b/src/tools/lend.ts @@ -1,94 +1,60 @@ import { VersionedTransaction } from "@solana/web3.js"; -import { SolanaAgentKit } from "../index"; -import { LuloAccountDetailsResponse, LuloDepositAssetMint } from "../types"; -import { getPriorityFees } from "../utils/send_tx"; -import { LULO_API } from "../constants"; +import { LuloAccountDetailsResponse } from "../types"; +import { SolanaAgentKit } from "../agent"; /** * Lend tokens for yields using Lulo * @param agent SolanaAgentKit instance - * @param asset Mint address of the token to lend (as supported by Lulo) - * @param amount Amount to lend (in token decimals) - * @param LULO_API_KEY Valid API key for Lulo + * @param amount Amount of USDC to lend * @returns Transaction signature */ export async function lendAsset( agent: SolanaAgentKit, - asset: LuloDepositAssetMint, - amount: number, - LULO_API_KEY = "", + amount: number ): Promise { try { - if (!LULO_API_KEY) { - throw new Error("Missing Lulo API key"); - } - - const request = { - owner: agent.wallet.publicKey.toBase58(), - mintAddress: asset.toBase58(), - depositAmount: amount.toString(), - }; - - const priorityFees = await getPriorityFees(agent.connection); - const priority = `?priorityFee=${priorityFees.median}`; - const response = await fetch( - `${LULO_API}/generate/account/deposit${priority}`, + `https://blink.lulo.fi/actions?amount=${amount}&symbol=USDC`, { method: "POST", headers: { "Content-Type": "application/json", - "x-wallet-pubkey": agent.wallet.publicKey.toBase58(), - "x-api-key": LULO_API_KEY, }, - body: JSON.stringify(request), - }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + }), + } ); - const { - data: { transactionMeta }, - } = await response.json(); + const data = await response.json(); + // Deserialize the transaction const luloTxn = VersionedTransaction.deserialize( - Buffer.from(transactionMeta[0].transaction, "base64"), + Buffer.from(data.transaction, "base64") ); + // Get a recent blockhash and set it + const { blockhash } = await agent.connection.getLatestBlockhash(); + luloTxn.message.recentBlockhash = blockhash; + // Sign and send transaction luloTxn.sign([agent.wallet]); - const signature = await agent.connection.sendTransaction(luloTxn); + + const signature = await agent.connection.sendTransaction(luloTxn, { + preflightCommitment: "confirmed", + maxRetries: 3, + }); + + // Wait for confirmation using the latest strategy + const latestBlockhash = await agent.connection.getLatestBlockhash(); + await agent.connection.confirmTransaction({ + signature, + blockhash: latestBlockhash.blockhash, + lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, + }); return signature; } catch (error: any) { throw new Error(`Lending failed: ${error.message}`); } } - -/** - * Fetch lending details for agent - * @param agent SolanaAgentKit instance - * @param LULO_API_KEY Valid API key for Lulo - * @returns Lending account details - */ -export async function getLendingDetails( - agent: SolanaAgentKit, - LULO_API_KEY = "", -): Promise { - try { - if (!LULO_API_KEY) { - throw new Error("Missing Lulo API key"); - } - - const response = await fetch(`${LULO_API}/account`, { - headers: { - "x-wallet-pubkey": agent.wallet.publicKey.toBase58(), - "x-api-key": LULO_API_KEY, - }, - }); - - const { data } = await response.json(); - - return data as LuloAccountDetailsResponse; - } catch (error: any) { - throw new Error(`Failed to fetch lending details: ${error.message}`); - } -} diff --git a/src/types/index.ts b/src/types/index.ts index 10c2cfc..e5c591e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,5 +1,4 @@ import { PublicKey } from "@solana/web3.js"; -import { TOKENS } from "../constants"; export interface Creator { address: string; @@ -41,11 +40,6 @@ export interface PumpfunLaunchResponse { } -/** - * Mint addresses of supported tokens for lending on Lulo - */ -export type LuloDepositAssetMint = (typeof TOKENS)[keyof typeof TOKENS]; - /** * Lulo Account Details response format */