Merge pull request #5 from arihantbansal/lulo-blink

refactor: lulo blink
This commit is contained in:
ARYAN
2024-12-13 15:02:42 +05:30
committed by GitHub
8 changed files with 115 additions and 98 deletions

View File

@@ -104,9 +104,7 @@ import { PublicKey } from '@solana/web3.js';
const signature = await lendAsset(
agent,
new PublicKey('asset-mint'),
100, // amount
"lulo-api-key"
);
```

View File

@@ -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<typeof mintCollectionNFT>[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,
);
}
}

View File

@@ -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";

View File

@@ -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<string> {
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<string> {
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),
];
}

View File

@@ -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}`);
}

View File

@@ -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";

View File

@@ -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<string> {
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<LuloAccountDetailsResponse> {
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}`);
}
}

View File

@@ -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
*/