Skip to content

Commit

Permalink
deposit and withdraw with lulo
Browse files Browse the repository at this point in the history
  • Loading branch information
zhourunlai committed Jan 4, 2025
1 parent 61abe10 commit e186960
Show file tree
Hide file tree
Showing 8 changed files with 340 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ OPENAI_API_KEY=
RPC_URL=
SOLANA_PRIVATE_KEY=
JUPITER_REFERRAL_ACCOUNT=
JUPITER_FEE_BPS=
JUPITER_FEE_BPS=
FLEXLEND_API_KEY=
63 changes: 63 additions & 0 deletions src/actions/depositWithLulo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { depositWithLulo } from "../tools";

const depositWithLuloAction: Action = {
name: "DEPOSIT_WITH_LULO",
similes: [
"deposit with lulo",
"deposit usdc with lulo",
"deposit pyusc with lulo",
"deposit usds with lulo",
"deposit usdt with lulo",
"deposit SOL with lulo",
"deposit jitoSOL with lulo",
"deposit bSOL with lulo",
"deposit mSOL with lulo",
"deposit BONK with lulo",
"deposit JUP with lulo",
],
description:
"Deposit tokens with Lulo staking protocol",
examples: [
[
{
input: {
mintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
amount: 1.5,
},
output: {
status: "success",
signature: "5KtPn3...",
message: "Successfully deposited 1.5 SOL with lulo",
},
explanation: "Deposit 1.5 SOL with lulo",
},
],
],
schema: z.object({
mintAddress: z.string().describe("Token mint address to deposit"),
amount: z.number().positive().describe("Amount to deposit"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const mintAddress = input.mintAddress as string;
const amount = input.amount as number;

const res = await depositWithLulo(agent, mintAddress, amount);
return {
status: "success",
res,
message: `Successfully deposited ${amount} of ${mintAddress}`,
};
} catch (error: any) {
return {
status: "error",
message: `deposit failed: ${error.message}`,
};
}
},
};

export default depositWithLuloAction;
4 changes: 4 additions & 0 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import getTPSAction from "./getTPS";
import fetchPriceAction from "./fetchPrice";
import stakeWithJupAction from "./stakeWithJup";
import stakeWithSolayerAction from "./stakeWithSolayer";
import depositWithLuloAction from "./depositWithLulo";
import withdrawWithLuloAction from "./withdrawWithLulo";
import registerDomainAction from "./registerDomain";
import lendAssetAction from "./lendAsset";
import createGibworkTaskAction from "./createGibworkTask";
Expand Down Expand Up @@ -44,6 +46,8 @@ export const ACTIONS = {
FETCH_PRICE_ACTION: fetchPriceAction,
STAKE_WITH_JUP_ACTION: stakeWithJupAction,
STAKE_WITH_SOLAYER_ACTION : stakeWithSolayerAction,
DEPOSIT_WITH_LULO_ACTION: depositWithLuloAction,
WITHDRAW_WITH_LULO_ACTION: withdrawWithLuloAction,
REGISTER_DOMAIN_ACTION: registerDomainAction,
LEND_ASSET_ACTION: lendAssetAction,
CREATE_GIBWORK_TASK_ACTION: createGibworkTaskAction,
Expand Down
63 changes: 63 additions & 0 deletions src/actions/withdrawWithLulo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { withdrawWithLulo } from "../tools";

const withdrawWithLuloAction: Action = {
name: "WITHDRAW_WITH_LULO",
similes: [
"withdraw with lulo",
"withdraw usdc with lulo",
"withdraw pyusc with lulo",
"withdraw usds with lulo",
"withdraw usdt with lulo",
"withdraw SOL with lulo",
"withdraw jitoSOL with lulo",
"withdraw bSOL with lulo",
"withdraw mSOL with lulo",
"withdraw BONK with lulo",
"withdraw JUP with lulo",
],
description:
"Withdraw tokens with Lulo staking protocol",
examples: [
[
{
input: {
mintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
amount: 1.5,
},
output: {
status: "success",
signature: "5KtPn3...",
message: "Successfully withdrawed 1.5 SOL with lulo",
},
explanation: "Withdraw 1.5 SOL with lulo",
},
],
],
schema: z.object({
mintAddress: z.string().describe("Token mint address to withdraw"),
amount: z.number().positive().describe("Amount to withdraw"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
try {
const mintAddress = input.mintAddress as string;
const amount = input.amount as number;

const res = await withdrawWithLulo(agent, mintAddress, amount);
return {
status: "success",
res,
message: `Successfully withdrawed ${amount} of ${mintAddress}`,
};
} catch (error: any) {
return {
status: "error",
message: `withdraw failed: ${error.message}`,
};
}
},
};

export default withdrawWithLuloAction;
10 changes: 10 additions & 0 deletions src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
getTokenDataByTicker,
stakeWithJup,
stakeWithSolayer,
depositWithLulo,
withdrawWithLulo,
sendCompressedAirdrop,
orcaCreateSingleSidedLiquidityPool,
orcaCreateCLMM,
Expand Down Expand Up @@ -259,6 +261,14 @@ export class SolanaAgentKit {
return stakeWithSolayer(this, amount);
}

async deposit(mintAddress: string, amount: number): Promise<string> {
return depositWithLulo(this, mintAddress, amount);
}

async withdraw(mintAddress: string, amount: number): Promise<string> {
return withdrawWithLulo(this, mintAddress, amount);
}

async sendCompressedAirdrop(
mintAddress: string,
amount: number,
Expand Down
72 changes: 72 additions & 0 deletions src/langchain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,76 @@ export class SolanaRestakeTool extends Tool {
}
}

export class SolanaDepositWithLuloTool extends Tool {
name = "solana_deposit_with_lulo";
description = `This tool can be used to deposit your token with lulo.
Inputs ( input is a JSON string ):
mintAddress: string, eg "So11111111111111111111111111111111111111112" (required)
amount: number, eg 1 or 0.01 (required)`;

constructor(private solanaKit: SolanaAgentKit) {
super();
}

protected async _call(input: string): Promise<string> {
try {
const parsedInput = JSON.parse(input);

const tx = await this.solanaKit.deposit(parsedInput.mintAddress, parsedInput.amount);

return JSON.stringify({
status: "success",
message: "Deposit successfully",
transaction: tx,
mintAddress: parsedInput.mintAddress,
amount: parsedInput.amount,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}

export class SolanaWithdrawWithLuloTool extends Tool {
name = "solana_withdraw_with_lulo";
description = `This tool can be used to withdraw your token with lulo.
Inputs ( input is a JSON string ):
mintAddress: string, eg "So11111111111111111111111111111111111111112" (required)
amount: number, eg 1 or 0.01 (required)`;

constructor(private solanaKit: SolanaAgentKit) {
super();
}

protected async _call(input: string): Promise<string> {
try {
const parsedInput = JSON.parse(input);

const tx = await this.solanaKit.withdraw(parsedInput.mintAddress, parsedInput.amount);

return JSON.stringify({
status: "success",
message: "Withdraw successfully",
transaction: tx,
mintAddress: parsedInput.mintAddress,
amount: parsedInput.amount,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}

/**
* Tool to fetch the price of a token in USDC
*/
Expand Down Expand Up @@ -2031,6 +2101,8 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
new SolanaTPSCalculatorTool(solanaKit),
new SolanaStakeTool(solanaKit),
new SolanaRestakeTool(solanaKit),
new SolanaDepositWithLuloTool(solanaKit),
new SolanaWithdrawWithLuloTool(solanaKit),
new SolanaFetchPriceTool(solanaKit),
new SolanaGetDomainTool(solanaKit),
new SolanaTokenDataTool(solanaKit),
Expand Down
1 change: 1 addition & 0 deletions src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from "./get_tps";
export * from "./get_token_data";
export * from "./stake_with_jup";
export * from "./stake_with_solayer";
export * from "./stake_with_lulo";
export * from "./fetch_price";
export * from "./send_compressed_airdrop";
export * from "./orca_close_position";
Expand Down
125 changes: 125 additions & 0 deletions src/tools/stake_with_lulo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { VersionedTransaction } from "@solana/web3.js";
import { SolanaAgentKit } from "../index";

/**
* Deposit tokens for yields using Lulo
* @param agent SolanaAgentKit instance
* @param mintAddress Mint address to deposit
* @param amount Amount to deposit
* @returns Transaction signature
*/
export async function depositWithLulo(
agent: SolanaAgentKit,
mintAddress: string,
amount: number,
): Promise<string> {
try {
const response = await fetch(
`https://api.flexlend.fi/generate/account/deposit`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-wallet-pubkey": agent.wallet.publicKey.toBase58(),
"x-api-key": process.env.FLEXLEND_API_KEY!
},
body: JSON.stringify({
owner: agent.wallet.publicKey.toBase58(),
mintAddress: mintAddress,
depositAmount: amount,
}),
},
);

const data = await response.json();

// Deserialize the transaction
const luloTxn = VersionedTransaction.deserialize(
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, {
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(`Deposit failed: ${error.message}`);
}
}

/**
* Withdraw tokens for yields using Lulo
* @param agent SolanaAgentKit instance
* @param mintAddress Mint address to deposit
* @param amount Amount to deposit
* @returns Transaction signature
*/
export async function withdrawWithLulo(
agent: SolanaAgentKit,
mintAddress: string,
amount: number,
): Promise<string> {
try {
const response = await fetch(
`https://api.flexlend.fi/generate/account/withdraw`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-wallet-pubkey": agent.wallet.publicKey.toBase58(),
"x-api-key": process.env.FLEXLEND_API_KEY!
},
body: JSON.stringify({
owner: agent.wallet.publicKey.toBase58(),
mintAddress: mintAddress,
depositAmount: amount,
}),
},
);

const data = await response.json();

const luloTxn = VersionedTransaction.deserialize(
Buffer.from(data.transaction, "base64"),
);

const { blockhash } = await agent.connection.getLatestBlockhash();
luloTxn.message.recentBlockhash = blockhash;

luloTxn.sign([agent.wallet]);

const signature = await agent.connection.sendTransaction(luloTxn, {
preflightCommitment: "confirmed",
maxRetries: 3,
});

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(`Withdraw failed: ${error.message}`);
}
}

0 comments on commit e186960

Please sign in to comment.