mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-21 23:26:45 +00:00
add idle asset lending with lulo
This commit is contained in:
@@ -8,15 +8,17 @@ import {
|
||||
mintCollectionNFT,
|
||||
transfer,
|
||||
trade,
|
||||
registerDomain
|
||||
registerDomain,
|
||||
lendAsset,
|
||||
getLendingDetails,
|
||||
} from "../tools";
|
||||
import { CollectionOptions } from "../types";
|
||||
import { CollectionOptions, LuloDepositAssetMint } from "../types";
|
||||
import { DEFAULT_OPTIONS } from "../constants";
|
||||
|
||||
/**
|
||||
* Main class for interacting with Solana blockchain
|
||||
* Provides a unified interface for token operations, NFT management, and trading
|
||||
*
|
||||
*
|
||||
* @class SolanaAgentKit
|
||||
* @property {Connection} connection - Solana RPC connection
|
||||
* @property {Keypair} wallet - Wallet keypair for signing transactions
|
||||
@@ -28,11 +30,11 @@ export class SolanaAgentKit {
|
||||
public wallet_address: PublicKey;
|
||||
|
||||
constructor(
|
||||
private_key: string,
|
||||
rpc_url = "https://api.mainnet-beta.solana.com"
|
||||
privateKey: string,
|
||||
rpcURL = "https://api.mainnet-beta.solana.com",
|
||||
) {
|
||||
this.connection = new Connection(rpc_url);
|
||||
this.wallet = Keypair.fromSecretKey(bs58.decode(private_key));
|
||||
this.connection = new Connection(rpcURL);
|
||||
this.wallet = Keypair.fromSecretKey(bs58.decode(privateKey));
|
||||
this.wallet_address = this.wallet.publicKey;
|
||||
}
|
||||
|
||||
@@ -59,7 +61,7 @@ export class SolanaAgentKit {
|
||||
async mintNFT(
|
||||
collectionMint: PublicKey,
|
||||
metadata: Parameters<typeof mintCollectionNFT>[2],
|
||||
recipient?: PublicKey
|
||||
recipient?: PublicKey,
|
||||
) {
|
||||
return mintCollectionNFT(this, collectionMint, metadata, recipient);
|
||||
}
|
||||
@@ -76,8 +78,20 @@ 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(
|
||||
asset: LuloDepositAssetMint,
|
||||
amount: number,
|
||||
LULO_API_KEY: string,
|
||||
) {
|
||||
return lendAsset(this, asset, amount, LULO_API_KEY);
|
||||
}
|
||||
|
||||
async fetchLendingDetails(LULO_API_KEY: string) {
|
||||
return getLendingDetails(this, LULO_API_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@ import { PublicKey } from "@solana/web3.js";
|
||||
*/
|
||||
export const TOKENS = {
|
||||
USDC: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
|
||||
USDT: new PublicKey("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"),
|
||||
USDS: new PublicKey("USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA"),
|
||||
SOL: new PublicKey("So11111111111111111111111111111111111111112"),
|
||||
jitoSOL: new PublicKey("J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn"),
|
||||
bSOL: new PublicKey("bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1"),
|
||||
mSOL: new PublicKey("mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So"),
|
||||
BONK: new PublicKey("DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263"),
|
||||
} as const;
|
||||
|
||||
/**
|
||||
@@ -16,3 +23,13 @@ export const DEFAULT_OPTIONS = {
|
||||
SLIPPAGE_BPS: 300,
|
||||
TOKEN_DECIMALS: 9,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 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";
|
||||
|
||||
@@ -4,8 +4,9 @@ import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
export class SolanaBalanceTool extends Tool {
|
||||
name = "solana_balance";
|
||||
description = "Get the balance of a Solana wallet or token account. Input can be a token address or empty for SOL balance.";
|
||||
|
||||
description =
|
||||
"Get the balance of a Solana wallet or token account. Input can be a token address or empty for SOL balance.";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
@@ -23,8 +24,9 @@ export class SolanaBalanceTool extends Tool {
|
||||
|
||||
export class SolanaTransferTool extends Tool {
|
||||
name = "solana_transfer";
|
||||
description = "Transfer tokens or SOL to another address. Input should be JSON string with: {to: string, amount: number, mint?: string}";
|
||||
|
||||
description =
|
||||
"Transfer tokens or SOL to another address. Input should be JSON string with: {to: string, amount: number, mint?: string}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
@@ -34,7 +36,7 @@ export class SolanaTransferTool extends Tool {
|
||||
const { to, amount, mint } = JSON.parse(input);
|
||||
const recipient = new PublicKey(to);
|
||||
const mintAddress = mint ? new PublicKey(mint) : undefined;
|
||||
|
||||
|
||||
await this.solanaKit.transfer(recipient, amount, mintAddress);
|
||||
return `Successfully transferred ${amount} to ${to}`;
|
||||
} catch (error: any) {
|
||||
@@ -45,15 +47,16 @@ export class SolanaTransferTool extends Tool {
|
||||
|
||||
export class SolanaDeployTokenTool extends Tool {
|
||||
name = "solana_deploy_token";
|
||||
description = "Deploy a new SPL token. Input should be JSON string with: {decimals?: number, initialSupply?: number}";
|
||||
|
||||
description =
|
||||
"Deploy a new SPL token. Input should be JSON string with: {decimals?: number, initialSupply?: number}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const validJson = input
|
||||
const validJson = input
|
||||
.replace(/([a-zA-Z0-9_]+):/g, '"$1":') // Add quotes around keys
|
||||
.trim();
|
||||
const { decimals = 9 } = JSON.parse(validJson);
|
||||
@@ -67,8 +70,9 @@ export class SolanaDeployTokenTool extends Tool {
|
||||
|
||||
export class SolanaDeployCollectionTool extends Tool {
|
||||
name = "solana_deploy_collection";
|
||||
description = "Deploy a new NFT collection. Input should be JSON with: {name: string, uri: string, royaltyBasisPoints?: number, creators?: Array<{address: string, percentage: number}>}";
|
||||
|
||||
description =
|
||||
"Deploy a new NFT collection. Input should be JSON with: {name: string, uri: string, royaltyBasisPoints?: number, creators?: Array<{address: string, percentage: number}>}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
@@ -86,8 +90,9 @@ export class SolanaDeployCollectionTool extends Tool {
|
||||
|
||||
export class SolanaMintNFTTool extends Tool {
|
||||
name = "solana_mint_nft";
|
||||
description = "Mint a new NFT in a collection. Input should be JSON with: {collectionMint: string, metadata: {name: string, symbol: string, uri: string}, recipient?: string}";
|
||||
|
||||
description =
|
||||
"Mint a new NFT in a collection. Input should be JSON with: {collectionMint: string, metadata: {name: string, symbol: string, uri: string}, recipient?: string}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
@@ -99,7 +104,7 @@ export class SolanaMintNFTTool extends Tool {
|
||||
const result = await this.solanaKit.mintNFT(
|
||||
new PublicKey(collectionMint),
|
||||
metadata,
|
||||
recipientPubkey
|
||||
recipientPubkey,
|
||||
);
|
||||
return `NFT minted successfully. Mint address: ${result.mint.toString()}`;
|
||||
} catch (error: any) {
|
||||
@@ -110,20 +115,22 @@ export class SolanaMintNFTTool extends Tool {
|
||||
|
||||
export class SolanaTradeTool extends Tool {
|
||||
name = "solana_trade";
|
||||
description = "Swap tokens using Jupiter Exchange. Input should be JSON with: {outputMint: string, inputAmount: number, inputMint?: string, slippageBps?: number}";
|
||||
|
||||
description =
|
||||
"Swap tokens using Jupiter Exchange. Input should be JSON with: {outputMint: string, inputAmount: number, inputMint?: string, slippageBps?: number}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const { outputMint, inputAmount, inputMint, slippageBps } = JSON.parse(input);
|
||||
const { outputMint, inputAmount, inputMint, slippageBps } =
|
||||
JSON.parse(input);
|
||||
const tx = await this.solanaKit.trade(
|
||||
new PublicKey(outputMint),
|
||||
inputAmount,
|
||||
inputMint ? new PublicKey(inputMint) : undefined,
|
||||
slippageBps
|
||||
slippageBps,
|
||||
);
|
||||
return `Trade executed successfully. Transaction: ${tx}`;
|
||||
} catch (error: any) {
|
||||
@@ -135,7 +142,7 @@ export class SolanaTradeTool extends Tool {
|
||||
export class SolanaRequestFundsTool extends Tool {
|
||||
name = "solana_request_funds";
|
||||
description = "Request SOL from Solana faucet (devnet/testnet only)";
|
||||
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
@@ -152,8 +159,9 @@ export class SolanaRequestFundsTool extends Tool {
|
||||
|
||||
export class SolanaRegisterDomainTool extends Tool {
|
||||
name = "solana_register_domain";
|
||||
description = "Register a .sol domain name. Input should be JSON with: {name: string, spaceKB?: number}";
|
||||
|
||||
description =
|
||||
"Register a .sol domain name. Input should be JSON with: {name: string, spaceKB?: number}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
@@ -172,7 +180,7 @@ export class SolanaRegisterDomainTool extends Tool {
|
||||
export class SolanaGetWalletAddressTool extends Tool {
|
||||
name = "solana_get_wallet_address";
|
||||
description = "Get the wallet address of the agent";
|
||||
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
@@ -182,6 +190,55 @@ export class SolanaGetWalletAddressTool extends Tool {
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaLendAssetTool extends Tool {
|
||||
name = "solana_lend_asset";
|
||||
description =
|
||||
"Lend idle assets for yield using Lulo. Input should be JSON with: {asset: string, amount: number, luloApiKey: string}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const { asset, amount, luloApiKey } = JSON.parse(input);
|
||||
|
||||
const tx = await this.solanaKit.lendAssets(
|
||||
new PublicKey(asset),
|
||||
amount,
|
||||
luloApiKey,
|
||||
);
|
||||
|
||||
return `Asset lent successfully. Transaction: ${tx}`;
|
||||
} catch (error: any) {
|
||||
return `Error lending asset: ${error.message}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaFetchLendingDetailsTool extends Tool {
|
||||
name = "solana_get_lending_details";
|
||||
description =
|
||||
"Get details of assets lent on Lulo. Input should be JSON with: {luloApiKey: string}";
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const { luloApiKey } = JSON.parse(input);
|
||||
|
||||
const lendingDetails =
|
||||
await this.solanaKit.fetchLendingDetails(luloApiKey);
|
||||
|
||||
return `Lending details: ${lendingDetails}`;
|
||||
} catch (error: any) {
|
||||
return `Error fetching lending details: ${error.message}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updated createSolanaTools function
|
||||
export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
return [
|
||||
@@ -194,5 +251,7 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaRequestFundsTool(solanaKit),
|
||||
new SolanaRegisterDomainTool(solanaKit),
|
||||
new SolanaGetWalletAddressTool(solanaKit),
|
||||
new SolanaLendAssetTool(solanaKit),
|
||||
new SolanaFetchLendingDetailsTool(solanaKit),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import {
|
||||
createUmi,
|
||||
generateSigner,
|
||||
publicKey,
|
||||
} from '@metaplex-foundation/umi';
|
||||
import { createCollection, ruleSet } from '@metaplex-foundation/mpl-core';
|
||||
import { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';
|
||||
import { CollectionOptions, CollectionDeployment } from '../types';
|
||||
import { toWeb3JsPublicKey } from '@metaplex-foundation/umi-web3js-adapters';
|
||||
import { createUmi, generateSigner, publicKey } from "@metaplex-foundation/umi";
|
||||
import { createCollection, ruleSet } from "@metaplex-foundation/mpl-core";
|
||||
import { mplTokenMetadata } from "@metaplex-foundation/mpl-token-metadata";
|
||||
import { CollectionOptions, CollectionDeployment } from "../types";
|
||||
import { toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
|
||||
|
||||
/**
|
||||
* Deploy a new NFT collection
|
||||
* @param agent SolanaAgentKit instance
|
||||
@@ -16,24 +13,25 @@ import { toWeb3JsPublicKey } from '@metaplex-foundation/umi-web3js-adapters';
|
||||
*/
|
||||
export async function deploy_collection(
|
||||
agent: SolanaAgentKit,
|
||||
options: CollectionOptions
|
||||
options: CollectionOptions,
|
||||
): Promise<CollectionDeployment> {
|
||||
try {
|
||||
// Initialize Umi
|
||||
const umi = createUmi()
|
||||
.use(mplTokenMetadata());
|
||||
|
||||
const umi = createUmi().use(mplTokenMetadata());
|
||||
|
||||
// Generate collection signer
|
||||
const collectionSigner = generateSigner(umi);
|
||||
|
||||
// Format creators if provided
|
||||
const formattedCreators = options.creators?.map(creator => ({
|
||||
const formattedCreators = options.creators?.map((creator) => ({
|
||||
address: publicKey(creator.address),
|
||||
percentage: creator.percentage,
|
||||
})) || [{
|
||||
address: publicKey(agent.wallet_address.toString()),
|
||||
percentage: 100,
|
||||
}];
|
||||
})) || [
|
||||
{
|
||||
address: publicKey(agent.wallet_address.toString()),
|
||||
percentage: 100,
|
||||
},
|
||||
];
|
||||
|
||||
// Create collection
|
||||
const tx = await createCollection(umi, {
|
||||
@@ -42,17 +40,17 @@ export async function deploy_collection(
|
||||
uri: options.uri,
|
||||
plugins: [
|
||||
{
|
||||
type: 'Royalties',
|
||||
type: "Royalties",
|
||||
basisPoints: options.royaltyBasisPoints || 500, // Default 5%
|
||||
creators: formattedCreators,
|
||||
ruleSet: ruleSet('None'), // Compatibility rule set
|
||||
ruleSet: ruleSet("None"), // Compatibility rule set
|
||||
},
|
||||
],
|
||||
}).sendAndConfirm(umi);
|
||||
|
||||
return {
|
||||
collectionAddress: toWeb3JsPublicKey(collectionSigner.publicKey),
|
||||
signature: tx.signature
|
||||
signature: tx.signature,
|
||||
};
|
||||
} catch (error: any) {
|
||||
throw new Error(`Collection deployment failed: ${error.message}`);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
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 "./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 "./lend";
|
||||
|
||||
94
src/tools/lend.ts
Normal file
94
src/tools/lend.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
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";
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns Transaction signature
|
||||
*/
|
||||
export async function lendAsset(
|
||||
agent: SolanaAgentKit,
|
||||
asset: LuloDepositAssetMint,
|
||||
amount: number,
|
||||
LULO_API_KEY = "",
|
||||
): Promise<string> {
|
||||
try {
|
||||
if (!LULO_API_KEY) {
|
||||
throw new Error("Missing Lulo API key");
|
||||
}
|
||||
|
||||
const request = {
|
||||
owner: agent.wallet.publicKey.toBase58(),
|
||||
mintAddress: asset,
|
||||
depositAmount: amount,
|
||||
};
|
||||
|
||||
const priority = `?priorityFee=${getPriorityFees(agent.connection)}`;
|
||||
|
||||
const response = await fetch(
|
||||
`${LULO_API}/generate/account/deposit${priority}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"x-wallet-pubkey": agent.wallet.publicKey.toBase58(),
|
||||
"x-api-key": LULO_API_KEY,
|
||||
},
|
||||
body: JSON.stringify(request),
|
||||
},
|
||||
);
|
||||
|
||||
const {
|
||||
data: { transactionMeta },
|
||||
} = await response.json();
|
||||
|
||||
const luloTxn = VersionedTransaction.deserialize(
|
||||
Buffer.from(transactionMeta[0].transaction, "base64"),
|
||||
);
|
||||
|
||||
// Sign and send transaction
|
||||
luloTxn.sign([agent.wallet]);
|
||||
const signature = await agent.connection.sendTransaction(luloTxn);
|
||||
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { Transaction } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
|
||||
import { TOKENS } from "../constants";
|
||||
|
||||
/**
|
||||
* Register a .sol domain name using Bonfida Name Service
|
||||
* @param agent SolanaAgentKit instance
|
||||
@@ -13,7 +14,7 @@ import { TOKENS } from "../constants";
|
||||
export async function registerDomain(
|
||||
agent: SolanaAgentKit,
|
||||
name: string,
|
||||
spaceKB: number = 1
|
||||
spaceKB: number = 1,
|
||||
): Promise<string> {
|
||||
try {
|
||||
// Validate space size
|
||||
@@ -26,7 +27,7 @@ export async function registerDomain(
|
||||
|
||||
const buyerTokenAccount = await getAssociatedTokenAddressSync(
|
||||
agent.wallet_address,
|
||||
TOKENS.USDC
|
||||
TOKENS.USDC,
|
||||
);
|
||||
|
||||
// Create registration instruction
|
||||
@@ -35,7 +36,7 @@ export async function registerDomain(
|
||||
name,
|
||||
space,
|
||||
agent.wallet_address,
|
||||
buyerTokenAccount
|
||||
buyerTokenAccount,
|
||||
);
|
||||
|
||||
// Create and sign transaction
|
||||
|
||||
@@ -4,13 +4,24 @@ import { LAMPORTS_PER_SOL } from "@solana/web3.js";
|
||||
/**
|
||||
* Request SOL from the Solana faucet (devnet/testnet only)
|
||||
* @param agent - SolanaAgentKit instance
|
||||
* @returns Promise that resolves when the airdrop is confirmed
|
||||
* @returns Transaction signature
|
||||
* @throws Error if the request fails or times out
|
||||
*/
|
||||
export async function request_faucet_funds(agent: SolanaAgentKit) {
|
||||
export async function request_faucet_funds(
|
||||
agent: SolanaAgentKit,
|
||||
): Promise<string> {
|
||||
const tx = await agent.connection.requestAirdrop(
|
||||
agent.wallet_address,
|
||||
5 * LAMPORTS_PER_SOL
|
||||
5 * LAMPORTS_PER_SOL,
|
||||
);
|
||||
await agent.connection.confirmTransaction(tx);
|
||||
}
|
||||
|
||||
const latestBlockHash = await agent.connection.getLatestBlockhash();
|
||||
|
||||
await agent.connection.confirmTransaction({
|
||||
signature: tx,
|
||||
blockhash: latestBlockHash.blockhash,
|
||||
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
|
||||
});
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import {
|
||||
VersionedTransaction,
|
||||
PublicKey,
|
||||
} from "@solana/web3.js";
|
||||
import { VersionedTransaction, PublicKey } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { TOKENS, DEFAULT_OPTIONS } from "../constants";
|
||||
import { TOKENS, DEFAULT_OPTIONS, JUP_API } from "../constants";
|
||||
|
||||
/**
|
||||
* Swap tokens using Jupiter Exchange
|
||||
* @param agent SolanaAgentKit instance
|
||||
@@ -18,19 +16,19 @@ export async function trade(
|
||||
outputMint: PublicKey,
|
||||
inputAmount: number,
|
||||
inputMint: PublicKey = TOKENS.USDC,
|
||||
slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS
|
||||
slippageBps: number = DEFAULT_OPTIONS.SLIPPAGE_BPS,
|
||||
): Promise<string> {
|
||||
try {
|
||||
// Get quote for the swap
|
||||
const quoteResponse = await (
|
||||
await fetch(
|
||||
`https://quote-api.jup.ag/v6/quote?` +
|
||||
`${JUP_API}/quote?` +
|
||||
`inputMint=${inputMint.toString()}` +
|
||||
`&outputMint=${outputMint.toString()}` +
|
||||
`&amount=${inputAmount}` +
|
||||
`&slippageBps=${slippageBps}` +
|
||||
`&onlyDirectRoutes=true` +
|
||||
`&maxAccounts=20`
|
||||
`&maxAccounts=20`,
|
||||
)
|
||||
).json();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { TOKENS } from "../constants";
|
||||
|
||||
export interface Creator {
|
||||
address: string;
|
||||
@@ -22,3 +23,23 @@ export interface MintCollectionNFTResponse {
|
||||
mint: PublicKey;
|
||||
metadata: PublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mint addresses of supported tokens for lending on Lulo
|
||||
*/
|
||||
export type LuloDepositAssetMint = (typeof TOKENS)[keyof typeof TOKENS];
|
||||
|
||||
/**
|
||||
* Lulo Account Details response format
|
||||
*/
|
||||
export interface LuloAccountDetailsResponse {
|
||||
totalValue: number;
|
||||
interestEarned: number;
|
||||
realtimeApy: number;
|
||||
settings: {
|
||||
owner: string;
|
||||
allowedProtocols: string | null;
|
||||
homebase: string | null;
|
||||
minimumRate: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Connection, ComputeBudgetProgram } from "@solana/web3.js";
|
||||
* @param connection - Solana RPC connection
|
||||
* @returns Priority fees statistics and instructions for different fee levels
|
||||
*/
|
||||
async function getPriorityFees(connection: Connection) {
|
||||
export async function getPriorityFees(connection: Connection) {
|
||||
try {
|
||||
// Get recent prioritization fees
|
||||
const priorityFees = await connection.getRecentPrioritizationFees();
|
||||
@@ -32,7 +32,7 @@ async function getPriorityFees(connection: Connection) {
|
||||
const median =
|
||||
sortedFees.length % 2 === 0
|
||||
? ((sortedFees[mid - 1] ?? 0) + (sortedFees[mid] ?? 0)) / 2
|
||||
: sortedFees[mid] ?? 0;
|
||||
: (sortedFees[mid] ?? 0);
|
||||
|
||||
// Helper to create priority fee IX based on chosen strategy
|
||||
const createPriorityFeeIx = (fee: number) => {
|
||||
@@ -67,7 +67,7 @@ async function getPriorityFees(connection: Connection) {
|
||||
export async function sendTx(
|
||||
agent: SolanaAgentKit,
|
||||
tx: Transaction,
|
||||
otherKeypairs?: Keypair[]
|
||||
otherKeypairs?: Keypair[],
|
||||
) {
|
||||
tx.recentBlockhash = (await agent.connection.getLatestBlockhash()).blockhash;
|
||||
tx.feePayer = agent.wallet_address;
|
||||
@@ -81,9 +81,8 @@ export async function sendTx(
|
||||
await agent.connection.confirmTransaction({
|
||||
signature: txid,
|
||||
blockhash: (await agent.connection.getLatestBlockhash()).blockhash,
|
||||
lastValidBlockHeight: (
|
||||
await agent.connection.getLatestBlockhash()
|
||||
).lastValidBlockHeight,
|
||||
lastValidBlockHeight: (await agent.connection.getLatestBlockhash())
|
||||
.lastValidBlockHeight,
|
||||
});
|
||||
return txid;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user