add idle asset lending with lulo

This commit is contained in:
Arihant Bansal
2024-11-26 16:24:38 +05:30
parent e3d1ff1d41
commit c26f6093ec
26 changed files with 340 additions and 2096 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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();