feat: add Voltr check balance, deposit and withdraw strategy

This commit is contained in:
jakeyvee
2025-01-04 13:05:31 +08:00
parent 61abe10b0d
commit b56116df09
8 changed files with 5066 additions and 2794 deletions

View File

@@ -48,6 +48,7 @@
"@tensor-oss/tensorswap-sdk": "^4.5.0",
"@solana/web3.js": "^1.98.0",
"@tiplink/api": "^0.3.1",
"@voltr/sdk": "^0.1.0",
"bn.js": "^5.2.1",
"bs58": "^6.0.0",
"chai": "^5.1.2",

7537
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -55,6 +55,9 @@ import {
fetchTokenReportSummary,
fetchTokenDetailedReport,
OrderParams,
voltrGetAssetAmount,
voltrDepositStrategy,
voltrWithdrawStrategy,
} from "../tools";
import {
@@ -497,4 +500,24 @@ export class SolanaAgentKit {
async fetchTokenDetailedReport(mint: string): Promise<TokenCheck> {
return fetchTokenDetailedReport(mint);
}
async voltrDepositStrategy(
depositAmount: BN,
vault: PublicKey,
strategy: PublicKey,
): Promise<string> {
return voltrDepositStrategy(this, depositAmount, vault, strategy);
}
async voltrWithdrawStrategy(
withdrawAmount: BN,
vault: PublicKey,
strategy: PublicKey,
): Promise<string> {
return voltrWithdrawStrategy(this, withdrawAmount, vault, strategy);
}
async voltrGetAssetAmount(vault: PublicKey): Promise<string> {
return voltrGetAssetAmount(this, vault);
}
}

View File

@@ -2013,6 +2013,91 @@ export class SolanaFetchTokenDetailedReportTool extends Tool {
}
}
export class SolanaVoltrDepositStrategy extends Tool {
name = "solana_voltr_deposit_strategy";
description = `Deposit amount into a strategy for Voltr's vaults
Inputs (input is a json string):
depositAmount: number (required)
vault: string (required)
strategy: string (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
async _call(input: string): Promise<string> {
try {
let inputFormat = JSON.parse(input);
const tx = await this.solanaKit.voltrDepositStrategy(
new BN(inputFormat.depositAmount),
new PublicKey(inputFormat.vault),
new PublicKey(inputFormat.strategy),
);
return JSON.stringify({
status: "success",
message: `Deposited ${inputFormat.depositAmount} into strategy ${inputFormat.strategy} of vault ${inputFormat.vault} successfully`,
transaction: tx,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export class SolanaVoltrWithdrawStrategy extends Tool {
name = "solana_voltr_withdraw_strategy";
description = `Withdraw amount from a strategy for Voltr's vaults
Inputs (input is a json string):
withdrawAmount: number (required)
vault: string (required)
strategy: string (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
async _call(input: string): Promise<string> {
try {
let inputFormat = JSON.parse(input);
const tx = await this.solanaKit.voltrWithdrawStrategy(
new BN(inputFormat.withdrawAmount),
new PublicKey(inputFormat.vault),
new PublicKey(inputFormat.strategy),
);
return JSON.stringify({
status: "success",
message: `Withdrew ${inputFormat.withdrawAmount} from strategy ${inputFormat.strategy} of vault ${inputFormat.vault} successfully`,
transaction: tx,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
export class SolanaVoltrGetAssetAmount extends Tool {
name = "solana_voltr_get_asset_amount";
description = `Get the total asset amount and current amount for each strategy of a given Voltr vault
Inputs:
vault: string (required)
`;
constructor(private solanaKit: SolanaAgentKit) {
super();
}
async _call(input: string): Promise<string> {
return this.solanaKit.voltrGetAssetAmount(new PublicKey(input));
}
}
export function createSolanaTools(solanaKit: SolanaAgentKit) {
return [
new SolanaBalanceTool(solanaKit),
@@ -2065,5 +2150,8 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
new SolanaCancelNFTListingTool(solanaKit),
new SolanaFetchTokenReportSummaryTool(solanaKit),
new SolanaFetchTokenDetailedReportTool(solanaKit),
new SolanaVoltrDepositStrategy(solanaKit),
new SolanaVoltrWithdrawStrategy(solanaKit),
new SolanaVoltrGetAssetAmount(solanaKit),
];
}

View File

@@ -58,3 +58,7 @@ export * from "./create_tiplinks";
export * from "./tensor_trade";
export * from "./rugcheck";
export * from "./voltr_deposit_strategy";
export * from "./voltr_withdraw_strategy";
export * from "./voltr_get_asset_amount";

View File

@@ -0,0 +1,77 @@
import { VoltrClient } from "@voltr/sdk";
import { SolanaAgentKit } from "../agent";
import {
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
import BN from "bn.js";
/**
* Deposits assets into a Voltr strategy
* @param agent SolanaAgentKit instance
* @param depositAmount Amount to deposit in base units (BN)
* @param vault Public key of the target vault
* @param strategy Public key of the target strategy
* @returns Transaction signature for the deposit
*/
export async function voltrDepositStrategy(
agent: SolanaAgentKit,
depositAmount: BN,
vault: PublicKey,
strategy: PublicKey,
): Promise<string> {
const vc = new VoltrClient(agent.connection, agent.wallet);
const { vaultAssetIdleAuth } = vc.findVaultAddresses(vault);
const vaultAccount = await vc.fetchVaultAccount(vault);
const vaultAssetMint = vaultAccount.asset.assetMint;
const strategyAccount = await vc.fetchStrategyAccount(strategy);
const liquidityReserve = strategyAccount.counterpartyAssetTa;
const protocolProgram = strategyAccount.protocolProgram;
const vaultStrategy = vc.findVaultStrategy(vaultAssetIdleAuth, strategy);
const response = await fetch(
`https://voltr.xyz/api/remaining-accounts/deposit-strategy?vault=${vault.toBase58()}&strategy=${strategy.toBase58()}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
},
);
const data = (await response.json()).data as {
pubkey: string;
isSigner: boolean;
isWritable: boolean;
}[];
const remainingAccounts = data.map((account) => ({
pubkey: new PublicKey(account.pubkey),
isSigner: account.isSigner,
isWritable: account.isWritable,
}));
const depositIx = await vc.createDepositStrategyIx(depositAmount, {
vault,
vaultAssetMint,
strategy: strategy,
vaultStrategy: vaultStrategy,
counterpartyAssetTa: liquidityReserve,
protocolProgram: protocolProgram,
remainingAccounts,
});
const transaction = new Transaction();
transaction.add(depositIx);
const txSig = await sendAndConfirmTransaction(
agent.connection,
transaction,
[agent.wallet],
{
commitment: "confirmed",
},
);
return txSig;
}

View File

@@ -0,0 +1,33 @@
import { VoltrClient } from "@voltr/sdk";
import { SolanaAgentKit } from "../agent";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
/**
* Deposits assets into a Voltr strategy
* @param agent SolanaAgentKit instance
* @param vault Public key of the target vault
* @returns Transaction signature for the deposit
*/
export async function voltrGetAssetAmount(
agent: SolanaAgentKit,
vault: PublicKey,
): Promise<string> {
const vc = new VoltrClient(agent.connection, agent.wallet);
const vaultAccount = await vc.fetchVaultAccount(vault);
const totalAssetAmount: BN = vaultAccount.asset.totalAmount;
const { vaultAssetIdleAuth } = vc.findVaultAddresses(vault);
const vaultStrategyAccounts =
await vc.fetchVaultStrategyAccounts(vaultAssetIdleAuth);
const strategyInfo = vaultStrategyAccounts.map((vaultStrategyAccount) => ({
strategyId: vaultStrategyAccount.account.strategy.toBase58(),
amount: vaultStrategyAccount.account.currentAmount.toString(),
}));
const result = {
totalAmount: totalAssetAmount.toString(),
strategies: strategyInfo,
};
return JSON.stringify(result);
}

View File

@@ -0,0 +1,97 @@
import { VoltrClient } from "@voltr/sdk";
import { SolanaAgentKit } from "../agent";
import {
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
import BN from "bn.js";
import {
Account,
getAccount,
TOKEN_2022_PROGRAM_ID,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
/**
* Withdraws assets from a Voltr strategy
* @param agent SolanaAgentKit instance
* @param withdrawAmount Amount to withdraw in base units (BN)
* @param vault Public key of the target vault
* @param strategy Public key of the target strategy
* @returns Transaction signature for the deposit
*/
export async function voltrWithdrawStrategy(
agent: SolanaAgentKit,
withdrawAmount: BN,
vault: PublicKey,
strategy: PublicKey,
): Promise<string> {
const vc = new VoltrClient(agent.connection, agent.wallet);
const { vaultAssetIdleAuth } = vc.findVaultAddresses(vault);
const vaultAccount = await vc.fetchVaultAccount(vault);
const vaultAssetMint = vaultAccount.asset.assetMint;
const strategyAccount = await vc.fetchStrategyAccount(strategy);
const liquidityReserve = strategyAccount.counterpartyAssetTa;
const protocolProgram = strategyAccount.protocolProgram;
const vaultStrategy = vc.findVaultStrategy(vaultAssetIdleAuth, strategy);
let liquidityReserveAccount: Account;
try {
liquidityReserveAccount = await getAccount(
agent.connection,
liquidityReserve,
"confirmed",
TOKEN_PROGRAM_ID,
);
} catch (error) {
liquidityReserveAccount = await getAccount(
agent.connection,
liquidityReserve,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
}
const liquidityReserveAuth = liquidityReserveAccount.owner;
const response = await fetch(
`https://voltr.xyz/api/remaining-accounts/withdraw-strategy?vault=${vault.toBase58()}&strategy=${strategy.toBase58()}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
},
);
const data = (await response.json()).data as {
pubkey: string;
isSigner: boolean;
isWritable: boolean;
}[];
const remainingAccounts = data.map((account) => ({
pubkey: new PublicKey(account.pubkey),
isSigner: account.isSigner,
isWritable: account.isWritable,
}));
const withdrawIx = await vc.createWithdrawStrategyIx(withdrawAmount, {
vault,
vaultAssetMint,
strategy: strategy,
vaultStrategy: vaultStrategy,
counterpartyAssetTa: liquidityReserve,
counterpartyAssetTaAuth: liquidityReserveAuth,
protocolProgram: protocolProgram,
remainingAccounts,
});
const transaction = new Transaction();
transaction.add(withdrawIx);
const txSig = await sendAndConfirmTransaction(agent.connection, transaction, [
agent.wallet,
]);
return txSig;
}