mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-15 23:26:46 +00:00
Merge branch 'main' into quangkeu95/main
This commit is contained in:
55
src/actions/drift/availableMarkets.ts
Normal file
55
src/actions/drift/availableMarkets.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { MainnetSpotMarkets } from "@drift-labs/sdk";
|
||||
import type { Action } from "../../types";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
getAvailableDriftPerpMarkets,
|
||||
getAvailableDriftSpotMarkets,
|
||||
} from "../../tools";
|
||||
|
||||
const availableDriftMarketsAction: Action = {
|
||||
name: "AVAILABLE_DRIFT_MARKETS",
|
||||
description: "Get a list of available drift markets",
|
||||
similes: [
|
||||
"get drift markets",
|
||||
"drift markets",
|
||||
"available drift markets",
|
||||
"get available drift perp markets",
|
||||
"get available spot markets on drift",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
marketType: "spot",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: `The list of available spot markets are ${MainnetSpotMarkets.map((v) => v.symbol).join(", ")}`,
|
||||
data: MainnetSpotMarkets,
|
||||
},
|
||||
explanation: "Get the list of available spot markets/tokens on drift",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
marketType: z
|
||||
.enum(["spot", "perp"])
|
||||
.describe("Type of market to get")
|
||||
.optional(),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
switch (input.marketType) {
|
||||
case "perp":
|
||||
return getAvailableDriftPerpMarkets();
|
||||
case "spot":
|
||||
return getAvailableDriftSpotMarkets();
|
||||
default:
|
||||
return {
|
||||
spot: getAvailableDriftSpotMarkets(),
|
||||
perp: getAvailableDriftPerpMarkets(),
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default availableDriftMarketsAction;
|
||||
64
src/actions/drift/createDriftUserAccount.ts
Normal file
64
src/actions/drift/createDriftUserAccount.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { createDriftUserAccount } from "../../tools";
|
||||
|
||||
const createDriftUserAccountAction: Action = {
|
||||
name: "CREATE_DRIFT_USER_ACCOUNT",
|
||||
similes: [
|
||||
"create drift account",
|
||||
"create drift user account",
|
||||
"create user account on drift",
|
||||
],
|
||||
description: "Create a new user account on Drift protocol",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
symbol: "SOL",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "User account created with 100 SOL successfully deposited",
|
||||
account: "4xKpN2...",
|
||||
},
|
||||
explanation: "Create a new user account with 100 SOL",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"Amount of the token to deposit. In normal token amounts e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
symbol: z.string().describe("Symbol of the token to deposit"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const res = await createDriftUserAccount(
|
||||
agent,
|
||||
input.amount,
|
||||
input.symbol,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message:
|
||||
res.message ??
|
||||
`User account created with ${input.amount} ${input.symobl} successfully deposited.`,
|
||||
account: res.account,
|
||||
signature: res.txSignature,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message is a string
|
||||
message: `Failed to create user account: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default createDriftUserAccountAction;
|
||||
113
src/actions/drift/createVault.ts
Normal file
113
src/actions/drift/createVault.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import type { SolanaAgentKit } from "../..";
|
||||
import { createVault } from "../../tools";
|
||||
|
||||
const createDriftVaultAction: Action = {
|
||||
name: "CREATE_DRIFT_VAULT",
|
||||
similes: ["create a drift vault", "open a drift vault", "create vault"],
|
||||
description:
|
||||
"Create a new drift vault delegating the agents address as the owner.",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
name: "My Drift Vault",
|
||||
marketName: "SOL-SPOT",
|
||||
redeemPeriod: 30,
|
||||
maxTokens: 1000,
|
||||
minDepositAmount: 100,
|
||||
managementFee: 10,
|
||||
profitShare: 5,
|
||||
hurdleRate: 0.1,
|
||||
permissioned: false,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Drift vault created successfully",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Create a drift vault",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
name: z
|
||||
.string()
|
||||
.min(5, "Name must be at least 5 characters")
|
||||
.describe("Has to be unique. 2 Vaults can not have the same name."),
|
||||
// regex matches SOL-SPOT
|
||||
marketName: z
|
||||
.string()
|
||||
.describe('Market name must be in the format "TOKEN-SPOT"'),
|
||||
redeemPeriod: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1, "Redeem period must be at least 1")
|
||||
.describe(
|
||||
"Number of days to wait before funds deposited in a vault can be redeemed ",
|
||||
),
|
||||
maxTokens: z
|
||||
.number()
|
||||
.int()
|
||||
.min(100, "Max tokens must be at least 100")
|
||||
.describe(
|
||||
"The maximum amount of tokens the vault will be accomodating. For example some vaults have a cap at 10 million USDC. This amount should be normal token amounts e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
minDepositAmount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"Minimum deposit amount in normal token values e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
managementFee: z
|
||||
.number()
|
||||
.positive()
|
||||
.max(20)
|
||||
.describe(
|
||||
"How much of a fee you'll be taking to manage depositors funds. This is in percentage e.g 2 for 2%",
|
||||
),
|
||||
profitShare: z
|
||||
.number()
|
||||
.positive()
|
||||
.max(90)
|
||||
.optional()
|
||||
.default(5)
|
||||
.describe(
|
||||
"How much of the profit you'll be sharing with depositors. This is in percentage e.g 2 for 2%. Defaults to 5%",
|
||||
),
|
||||
hurdleRate: z.number().optional(),
|
||||
permissioned: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Should the vault have a whitelist of not"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
try {
|
||||
const tx = await createVault(
|
||||
agent,
|
||||
// @ts-expect-error - zod schema validation
|
||||
{
|
||||
...input,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message:
|
||||
"Drift vault created successfully. Please note down the name of your vault as it is unique and was used to derive your vault address",
|
||||
vaultName: input.name,
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - e is not a string
|
||||
message: `Failed to create drift vault: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default createDriftVaultAction;
|
||||
58
src/actions/drift/depositIntoVault.ts
Normal file
58
src/actions/drift/depositIntoVault.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { depositIntoVault } from "../../tools";
|
||||
|
||||
const depositIntoDriftVaultAction: Action = {
|
||||
name: "DEPOSIT_INTO_DRIFT_VAULT",
|
||||
description: "Deposit funds into an existing drift vault",
|
||||
similes: ["deposit into drift vault", "add funds to drift vault"],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
vaultAddress: "2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBD",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Funds deposited successfully",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Deposit 100 USDC into a drift vault",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vaultAddress: z.string(),
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"The amount in tokens you'd like to deposit into the vault in normal token amounts e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const tx = await depositIntoVault(
|
||||
agent,
|
||||
input.amount as number,
|
||||
input.vaultAddress as string,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Funds deposited successfully",
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to deposit funds: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default depositIntoDriftVaultAction;
|
||||
73
src/actions/drift/depositToDriftUserAccount.ts
Normal file
73
src/actions/drift/depositToDriftUserAccount.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { z } from "zod";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import type { Action } from "../../types";
|
||||
import { depositToDriftUserAccount } from "../../tools";
|
||||
|
||||
const depositToDriftUserAccountAction: Action = {
|
||||
name: "DEPOSIT_TO_DRIFT_USER_ACCOUNT",
|
||||
description: "Deposit funds into your drift user account",
|
||||
similes: [
|
||||
"deposit into drift user account",
|
||||
"add funds to drift user account",
|
||||
"add funds to my drift account",
|
||||
"deposit collateral into drift account",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
symbol: "usdc",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Funds deposited successfully",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Deposit 100 USDC into your drift user account",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"The amount in tokens you'd like to deposit into your drift user account in normal token amounts e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
symbol: z
|
||||
.string()
|
||||
.toUpperCase()
|
||||
.describe("The symbol of the token you'd like to deposit"),
|
||||
repay: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(false)
|
||||
.describe("Whether or not to repay the borrowed funds in the account"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
try {
|
||||
const tx = await depositToDriftUserAccount(
|
||||
agent,
|
||||
input.amount as number,
|
||||
input.symbol as string,
|
||||
input.repay as boolean,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Funds deposited successfully",
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to deposit funds: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default depositToDriftUserAccountAction;
|
||||
46
src/actions/drift/deriveVaultAddress.ts
Normal file
46
src/actions/drift/deriveVaultAddress.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { getVaultAddress } from "../../tools";
|
||||
|
||||
const deriveDriftVaultAddressAction: Action = {
|
||||
name: "DERIVE_DRIFT_VAULT_ADDRESS_ACTION",
|
||||
similes: ["derive drift vault address", "get drift vault address"],
|
||||
description: "Derive a drift vault address from the vaults name",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
name: "My Drift Vault",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Vault address derived successfully",
|
||||
address: "2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBD",
|
||||
},
|
||||
explanation: "Derive a drift vault address",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
name: z.string().describe("The name of the vault to derive the address of"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const address = await getVaultAddress(agent, input.name as string);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Vault address derived successfully",
|
||||
address,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to derive vault address: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default deriveDriftVaultAddressAction;
|
||||
53
src/actions/drift/doesUserHaveDriftAccount.ts
Normal file
53
src/actions/drift/doesUserHaveDriftAccount.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { z } from "zod";
|
||||
import { doesUserHaveDriftAccount } from "../../tools";
|
||||
import type { Action } from "../../types";
|
||||
|
||||
export const doesUserHaveDriftAccountAction: Action = {
|
||||
name: "DOES_USER_HAVE_DRIFT_ACCOUNT",
|
||||
description: "Check if a user has a Drift account",
|
||||
similes: [
|
||||
"check if user has drift account",
|
||||
"check if user has account on drift",
|
||||
"do I have an account on drift",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Nice! You have a Drift account",
|
||||
account: "4xKpN2...",
|
||||
},
|
||||
explanation: "Check if a user has a Drift account",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({}),
|
||||
handler: async (agent) => {
|
||||
try {
|
||||
const res = await doesUserHaveDriftAccount(agent);
|
||||
|
||||
if (!res.hasAccount) {
|
||||
return {
|
||||
status: "error",
|
||||
message: "You do not have a Drift account",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Nice! You have a Drift account",
|
||||
account: res.account,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message is a string
|
||||
message: `Failed to check if you have a Drift account: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default doesUserHaveDriftAccountAction;
|
||||
39
src/actions/drift/driftUserAccountInfo.ts
Normal file
39
src/actions/drift/driftUserAccountInfo.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { driftUserAccountInfo } from "../../tools";
|
||||
|
||||
const driftUserAccountInfoAction: Action = {
|
||||
name: "DRIFT_USER_ACCOUNT_INFO",
|
||||
similes: ["get drift user account info", "get drift account info"],
|
||||
description: "Get information about your drift account",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {},
|
||||
explanation: "Get information about your drift account",
|
||||
output: {
|
||||
status: "success",
|
||||
data: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({}),
|
||||
handler: async (agent) => {
|
||||
try {
|
||||
const accountInfo = await driftUserAccountInfo(agent);
|
||||
return {
|
||||
status: "success",
|
||||
data: accountInfo,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message is a string
|
||||
message: `Failed to get drift account info: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default driftUserAccountInfoAction;
|
||||
65
src/actions/drift/entryQuoteOfPerpTrade.ts
Normal file
65
src/actions/drift/entryQuoteOfPerpTrade.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { getEntryQuoteOfPerpTrade } from "../../tools";
|
||||
|
||||
const entryQuoteOfPerpTradeAction: Action = {
|
||||
name: "DRIFT_GET_ENTRY_QUOTE_OF_PERP_TRADE_ACTION",
|
||||
description: "Get the entry quote of a perpetual trade on Drift",
|
||||
similes: [
|
||||
"get the entry quote of a perpetual trade on drift",
|
||||
"get the entry quote of a perp trade on drift",
|
||||
"get the entry quote of the BTC-PERP trade on drift",
|
||||
"get the entry quote of the SOL-PERP trade on drift",
|
||||
"get the entry quote of a 1000 USDC long on the SOL-PERP market",
|
||||
"get the entry quote of a 1000 USDC short on the SOL-PERP market",
|
||||
"quote for a $1000 long on the BTC-PERP market",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
marketSymbol: "BTC-PERP",
|
||||
type: "long",
|
||||
amount: 1000,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
data: {
|
||||
entryPrice: 100000,
|
||||
priceImpact: 0.0001,
|
||||
bestPrice: 100001,
|
||||
worstPrice: 99999,
|
||||
baseFilled: 1000,
|
||||
quoteFilled: 1000,
|
||||
},
|
||||
},
|
||||
explanation:
|
||||
"Get the entry quote of a $1000 long on the BTC-PERP market",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
marketSymbol: z.string().describe("Symbol of the perpetual market"),
|
||||
type: z.enum(["long", "short"]).describe("Type of trade"),
|
||||
amount: z.number().positive().describe("Amount to trade"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const data = await getEntryQuoteOfPerpTrade(
|
||||
input.marketSymbol,
|
||||
input.amount,
|
||||
input.type,
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: e.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default entryQuoteOfPerpTradeAction;
|
||||
52
src/actions/drift/getLendAndBorrowAPY.ts
Normal file
52
src/actions/drift/getLendAndBorrowAPY.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { getLendingAndBorrowAPY } from "../../tools";
|
||||
|
||||
const lendAndBorrowAPYAction: Action = {
|
||||
name: "DRIFT_GET_LEND_AND_BORROW_APY_ACTION",
|
||||
description: "Get the lending and borrowing APY (in %) of a token on Drift",
|
||||
similes: [
|
||||
"get the lending and borrowing APY of a token on drift",
|
||||
"get the lending and borrowing APY of a token on drift",
|
||||
"get the lending and borrowing APY of the USDC token on drift",
|
||||
"get the lending and borrowing APY of the SOL token on drift",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
symbol: "USDC",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
data: {
|
||||
lendingAPY: 10,
|
||||
borrowingAPY: 12.1,
|
||||
},
|
||||
},
|
||||
explanation: "Get the lending and borrowing APY of the USDC token",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
symbol: z.string().describe("Symbol of the token"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const data = await getLendingAndBorrowAPY(agent, input.symbol);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
data,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: e.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default lendAndBorrowAPYAction;
|
||||
61
src/actions/drift/perpMarketFundingRate.ts
Normal file
61
src/actions/drift/perpMarketFundingRate.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { calculatePerpMarketFundingRate } from "../../tools";
|
||||
|
||||
const perpMarktetFundingRateAction: Action = {
|
||||
name: "DRIFT_PERP_MARKET_FUNDING_RATE_ACTION",
|
||||
description: "Get the funding rate of a perpetual market on Drift",
|
||||
similes: [
|
||||
"get the yearly funding rate of a perpetual market on drift",
|
||||
"get the funding rate of a perp market on drift",
|
||||
"get the hourly funding rate of a perpetual market on drift",
|
||||
"get the funding rate of the BTC-PERP market on drift",
|
||||
"get the funding rate of the SOL-PERP market on drift",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
marketSymbol: "BTC-PERP",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
data: {
|
||||
longRate: 0.0001,
|
||||
shortRate: 0.0002,
|
||||
},
|
||||
},
|
||||
explanation: "Get the funding rate of the BTC-PERP market",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
marketSymbol: z
|
||||
.string()
|
||||
.toUpperCase()
|
||||
.describe("Symbol of the perpetual market"),
|
||||
period: z.enum(["year", "hour"]).default("hour").optional(),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const data = await calculatePerpMarketFundingRate(
|
||||
agent,
|
||||
input.marketSymbol,
|
||||
input.period,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
data,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: e.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default perpMarktetFundingRateAction;
|
||||
61
src/actions/drift/requestUnstakeFromDriftInsuranceFund.ts
Normal file
61
src/actions/drift/requestUnstakeFromDriftInsuranceFund.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { requestUnstakeFromDriftInsuranceFund } from "../../tools";
|
||||
|
||||
const requestUnstakeFromDriftInsuranceFundAction: Action = {
|
||||
name: "REQUEST_UNSTAKE_FROM_DRIFT_INSURANCE_FUND_ACTION",
|
||||
description:
|
||||
"Request to unstake a certain amount of a token from the Drift Insurance Fund",
|
||||
similes: [
|
||||
"request an unstake from the drift insurance fund",
|
||||
"request to unstake an amount from the drift insurance fund",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
symbol: "SOL",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Requested to unstake 100 SOL from the Drift Insurance Fund",
|
||||
signature: "4FdasklhiIHyOI",
|
||||
},
|
||||
explanation: "Request to unstake 100 SOL from the Drift Insurance Fund",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe("Amount to unstake in normal units e.g 50 === 50 SOL"),
|
||||
symbol: z.string().describe("Symbol of the token to unstake"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const tx = await requestUnstakeFromDriftInsuranceFund(
|
||||
agent,
|
||||
input.amount,
|
||||
input.symbol,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: `Requested to unstake ${input.amount} ${input.symbol} from the Drift Insurance Fund`,
|
||||
data: {
|
||||
signature: tx,
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: e.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default requestUnstakeFromDriftInsuranceFundAction;
|
||||
59
src/actions/drift/requestWithdrawalFromVault.ts
Normal file
59
src/actions/drift/requestWithdrawalFromVault.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import { requestWithdrawalFromVault } from "../../tools";
|
||||
|
||||
const requestWithdrawalFromVaultAction: Action = {
|
||||
name: "REQUEST_WITHDRAWAL_FROM_DRIFT_VAULT",
|
||||
description: "Request a withdrawal from an existing drift vault",
|
||||
similes: ["withdraw from drift vault", "request withdrawal from vault"],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
vaultAddress: "2nFeP7taii",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Withdrawal request successful",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Request a withdrawal of 100 USDC from a drift vault",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vaultAddress: z.string(),
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"Amount of shares you would like to withdraw from the vault in normal token amounts e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
try {
|
||||
const tx = await requestWithdrawalFromVault(
|
||||
agent,
|
||||
input.amount as number,
|
||||
input.vaultAddress as string,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Withdrawal request successful",
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to request withdrawal: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default requestWithdrawalFromVaultAction;
|
||||
59
src/actions/drift/stakeToDriftInsuranceFund.ts
Normal file
59
src/actions/drift/stakeToDriftInsuranceFund.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { stakeToDriftInsuranceFund } from "../../tools";
|
||||
|
||||
const stakeToDriftInsuranceFundAction: Action = {
|
||||
name: "STAKE_TO_DRIFT_INSURANCE_FUND_ACTION",
|
||||
description: "Stake a token to Drift Insurance Fund",
|
||||
similes: ["Stake a token to Drift Insurance Fund"],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
symbol: "SOL",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Staked 100 SOL to the Drift Insurance Fund",
|
||||
data: {
|
||||
signature: "signature",
|
||||
},
|
||||
},
|
||||
explanation: "Stake 100 SOL to the Drift Insurance Fund",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe("Amount to stake in normal units e.g 50 === 50 SOL"),
|
||||
symbol: z.string().describe("Symbol of the token stake"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const tx = await stakeToDriftInsuranceFund(
|
||||
agent,
|
||||
input.amount,
|
||||
input.symbol,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "sucess",
|
||||
message: `Staked ${input.amount} ${input.symbol} to the Drift Insurance Fund`,
|
||||
data: {
|
||||
signature: tx,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default stakeToDriftInsuranceFundAction;
|
||||
78
src/actions/drift/swapSpotToken.ts
Normal file
78
src/actions/drift/swapSpotToken.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { swapSpotToken } from "../../tools";
|
||||
|
||||
const driftSpotTokenSwapAction: Action = {
|
||||
name: "DRIFT_SPOT_TOKEN_SWAP_ACTION",
|
||||
description: "Swap a token for another token on Drift",
|
||||
similes: [
|
||||
"swap a token for another token on drift",
|
||||
"exchange a token for another token on drift",
|
||||
"trade a token for another token on drift",
|
||||
"swap usdc to 5 sol on drift (in this case 5 sol is the toAmount)",
|
||||
"swap 5 usdt to DRIFT on drift (in this case 5 usdt is the fromAmount)",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
fromSymbol: "SOL",
|
||||
toSymbol: "USDC",
|
||||
fromAmount: 100,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Swapped 100 SOL for USDC on Drift",
|
||||
signature: "4FdasklhiIHyOI",
|
||||
},
|
||||
explanation: "Swap 100 SOL for USDC on Drift",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
fromSymbol: z.string().describe("Symbol of the token to swap from"),
|
||||
toSymbol: z.string().describe("Symbol of the token to swap to"),
|
||||
fromAmount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe("Amount to swap from e.g 50 === 50 SOL")
|
||||
.optional(),
|
||||
toAmount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe("Amount to swap to e.g 5000 === 5000 USDC")
|
||||
.optional(),
|
||||
slippage: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe("Slippage tolerance in percentage e.g 0.5 === 0.5%")
|
||||
.default(0.5),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const tx = await swapSpotToken(agent, {
|
||||
fromSymbol: input.fromSymbol,
|
||||
toSymbol: input.toSymbol,
|
||||
fromAmount: input.fromAmount,
|
||||
toAmount: input.toAmount,
|
||||
slippage: input.slippage,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: `Swapped ${input.fromAmount} ${input.fromSymbol} for ${input.toAmount} ${input.toSymbol} on Drift`,
|
||||
data: {
|
||||
signature: tx,
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: e.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default driftSpotTokenSwapAction;
|
||||
123
src/actions/drift/tradeDelegatedDriftVault.ts
Normal file
123
src/actions/drift/tradeDelegatedDriftVault.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import { tradeDriftVault } from "../../tools";
|
||||
|
||||
const tradeDelegatedDriftVaultAction: Action = {
|
||||
name: "TRADE_DELEGATED_DRIFT_VAULT",
|
||||
similes: [
|
||||
"trade delegated drift vault",
|
||||
"trade delegated vault",
|
||||
"trade vault",
|
||||
"trade drift vault",
|
||||
"trade delegated vault",
|
||||
"trade vault",
|
||||
"trade drift vault",
|
||||
"open drift vault trade",
|
||||
],
|
||||
description: "Carry out trades in a Drift vault.",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
vaultAddress: "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w",
|
||||
amount: 100,
|
||||
symbol: "SOL",
|
||||
action: "buy",
|
||||
type: "market",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Trade successful",
|
||||
transactionId: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
|
||||
amount: 100,
|
||||
symbol: "SOL",
|
||||
action: "buy",
|
||||
type: "market",
|
||||
},
|
||||
explanation: "Buy 100 SOL in the vault",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
input: {
|
||||
vaultAddress: "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w",
|
||||
amount: 50,
|
||||
symbol: "SOL",
|
||||
action: "sell",
|
||||
type: "limit",
|
||||
price: 200,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Order placed successful",
|
||||
transactionId: "8nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkM",
|
||||
amount: 50,
|
||||
symbol: "SOL",
|
||||
action: "sell",
|
||||
type: "limit",
|
||||
price: 200,
|
||||
},
|
||||
explanation: "Sell 50 SOL in the vault at $200",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vaultAddress: z.string().describe("Address of the Drift vault to trade in"),
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"Amount to trade in normal token amounts e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
symbol: z.string().describe("Symbol of the token to trade"),
|
||||
action: z.enum(["long", "short"]).describe("Trade action - long or short"),
|
||||
type: z.enum(["market", "limit"]).describe("Trade type - market or limit"),
|
||||
price: z
|
||||
.number()
|
||||
.positive()
|
||||
.optional()
|
||||
.describe("USD price for limit order"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
try {
|
||||
const params = {
|
||||
vaultAddress: input.vaultAddress as string,
|
||||
amount: input.amount as number,
|
||||
symbol: input.symbol as string,
|
||||
action: input.action as "long" | "short",
|
||||
type: input.type as "market" | "limit",
|
||||
price: input.price as number | undefined,
|
||||
};
|
||||
|
||||
// Carry out the trade
|
||||
const transactionId = await tradeDriftVault(
|
||||
agent,
|
||||
params.vaultAddress,
|
||||
params.amount,
|
||||
params.symbol,
|
||||
params.action,
|
||||
params.type,
|
||||
params.price,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message:
|
||||
params.type === "limit"
|
||||
? "Order placed successfully"
|
||||
: "Trade successful",
|
||||
transactionId,
|
||||
...params,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default tradeDelegatedDriftVaultAction;
|
||||
95
src/actions/drift/tradePerpAccount.ts
Normal file
95
src/actions/drift/tradePerpAccount.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { driftPerpTrade } from "../../tools";
|
||||
|
||||
export const tradeDriftPerpAccountAction: Action = {
|
||||
name: "TRADE_DRIFT_PERP_ACCOUNT",
|
||||
similes: [
|
||||
"trade drift perp account",
|
||||
"trade drift perp",
|
||||
"trade drift perpetual account",
|
||||
"trade perp account",
|
||||
"trade account",
|
||||
],
|
||||
description: "Trade a perpetual account on Drift protocol",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
symbol: "SOL",
|
||||
action: "long",
|
||||
type: "market",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Trade successful",
|
||||
},
|
||||
explanation: "Open a $100 long position on SOL.",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 50,
|
||||
symbol: "BTC",
|
||||
action: "short",
|
||||
type: "limit",
|
||||
price: 50000,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Trade successful",
|
||||
},
|
||||
explanation: "$50 short position on BTC at $50,000.",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"The amount of the token to trade in normal token amounts e.g 50 SOL, 100 USDC",
|
||||
),
|
||||
symbol: z
|
||||
.string()
|
||||
.toUpperCase()
|
||||
.describe("Symbol of the token to open a position on "),
|
||||
action: z
|
||||
.enum(["long", "short"])
|
||||
.describe(
|
||||
"The action you would like to carry out whether it be a long or a short",
|
||||
),
|
||||
type: z
|
||||
.enum(["market", "limit"])
|
||||
.describe(
|
||||
"The type of trade you would like to open, market or limit order",
|
||||
),
|
||||
price: z.number().positive().optional().describe("USD price of the token"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const signature = await driftPerpTrade(agent, {
|
||||
action: input.action,
|
||||
amount: input.amount,
|
||||
symbol: input.symbol,
|
||||
type: input.type,
|
||||
price: input.price,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signature: signature,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message is a string
|
||||
message: `Failed to trade perp account: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default tradeDriftPerpAccountAction;
|
||||
51
src/actions/drift/unstakeFromDriftInsuranceFund.ts
Normal file
51
src/actions/drift/unstakeFromDriftInsuranceFund.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { unstakeFromDriftInsuranceFund } from "../../tools";
|
||||
|
||||
const unstakeFromDriftInsuranceFundAction: Action = {
|
||||
name: "UNSTAKE_FROM_DRIFT_INSURANCE_FUND_ACTION",
|
||||
description:
|
||||
"Unstake requested unstake token from the Drift Insurance fund once the cool period has elapsed",
|
||||
similes: [
|
||||
"unstake from the drift insurance fund",
|
||||
"withdraw from the drift insurance fund",
|
||||
"take out funds from the drift insurance fund",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
symbol: "SOL",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Unstaked your SOL from the Drift Insurance Fund",
|
||||
signature: "4FdasklhiIHyOI",
|
||||
},
|
||||
explanation: "Unstake SOL from the Drift Insurance Fund",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
symbol: z.string().describe("Symbol of the token to unstake"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const tx = await unstakeFromDriftInsuranceFund(agent, input.symbol);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: `Unstaked your ${input.symbol} from the Drift Insurance Fund`,
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error error is not a string
|
||||
message: e.message,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default unstakeFromDriftInsuranceFundAction;
|
||||
53
src/actions/drift/updateDriftVaultDelegate.ts
Normal file
53
src/actions/drift/updateDriftVaultDelegate.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { updateVaultDelegate } from "../../tools";
|
||||
|
||||
const updateDriftVaultDelegateAction: Action = {
|
||||
name: "UPDATE_DRIFT_VAULT_DELEGATE_ACTION",
|
||||
similes: ["update drift vault delegate", "change drift vault delegate"],
|
||||
description: "Update the delegate of a drift vault",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
vaultAddress: "2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBD",
|
||||
newDelegate: "2nFeP7tai",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Vault delegate updated successfully",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Update the delegate of a drift vault to another address",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vaultAddress: z.string().describe("vault's address"),
|
||||
newDelegate: z.string().describe("new address to delegate the vault to"),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const tx = await updateVaultDelegate(
|
||||
agent,
|
||||
input.vaultAddress as string,
|
||||
input.newDelegate as string,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Vault delegate updated successfully",
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to update vault delegate: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default updateDriftVaultDelegateAction;
|
||||
106
src/actions/drift/updateVault.ts
Normal file
106
src/actions/drift/updateVault.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import { updateVault } from "../../tools";
|
||||
|
||||
const updateDriftVaultAction: Action = {
|
||||
name: "UPDATE_DRIFT_VAULT",
|
||||
similes: ["update a drift vault", "modify a drift vault", "update vault"],
|
||||
description: "Update an existing drift vault with new settings.",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
redeemPeriod: 30,
|
||||
maxTokens: 10000,
|
||||
minDepositAmount: 10,
|
||||
managementFee: 5,
|
||||
profitShare: 10,
|
||||
handleRate: 0.1,
|
||||
permissioned: false,
|
||||
vaultAddress: "2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBD",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Drift vault updated successfully",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Update a drift vault",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vaultAddress: z.string(),
|
||||
name: z.string().min(5, "Name must be at least 5 characters").optional(),
|
||||
// regex matches SOL-SPOT
|
||||
marketName: z
|
||||
.string()
|
||||
.regex(/^([A-Za-z0-9]{2,7})-SPOT$/)
|
||||
.optional(),
|
||||
redeemPeriod: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1, "Redeem period must be at least 1 day")
|
||||
.optional(),
|
||||
maxTokens: z
|
||||
.number()
|
||||
.int()
|
||||
.min(100, "Max tokens must be at least be 100 units")
|
||||
.optional()
|
||||
.describe(
|
||||
"The maximum number of tokens the vault is willing to accept and manage",
|
||||
),
|
||||
minDepositAmount: z
|
||||
.number()
|
||||
.positive()
|
||||
.optional()
|
||||
.describe(
|
||||
"The minimum amount that is allowed to be deposited into the vault in normal token amounts e.g 10 USDC",
|
||||
),
|
||||
managementFee: z
|
||||
.number()
|
||||
.positive()
|
||||
.max(20)
|
||||
.optional()
|
||||
.describe("The percentage fee the vault takes for asset management"),
|
||||
profitShare: z
|
||||
.number()
|
||||
.positive()
|
||||
.max(90)
|
||||
.optional()
|
||||
.describe("Profit share in percentage e.g 2 === 2%"),
|
||||
handleRate: z.number().optional(),
|
||||
permissioned: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Should the vault have a whitelist of not"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
try {
|
||||
const tx = await updateVault(agent, input.vaultAddress, {
|
||||
hurdleRate: input.hurdleRate,
|
||||
maxTokens: input.maxTokens,
|
||||
minDepositAmount: input.minDepositAmount,
|
||||
profitShare: input.profitShare,
|
||||
managementFee: input.managementFee,
|
||||
permissioned: input.permissioned,
|
||||
redeemPeriod: input.redeemPeriod,
|
||||
});
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Drift vault parameters updated successfully",
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to update drift vault: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default updateDriftVaultAction;
|
||||
57
src/actions/drift/vaultInfo.ts
Normal file
57
src/actions/drift/vaultInfo.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { getVaultInfo } from "../../tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
const vaultInfoAction: Action = {
|
||||
name: "DRIFT_VAULT_INFO",
|
||||
similes: ["get drift vault info", "vault info", "vault information"],
|
||||
description: "Get information about a drift vault",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
vaultNameOrAddress: "test-vault",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Vault info retrieved successfully",
|
||||
data: {
|
||||
name: "My Drift Vault",
|
||||
marketName: "SOL-SPOT",
|
||||
redeemPeriod: 30,
|
||||
maxTokens: 1000,
|
||||
minDepositAmount: 100,
|
||||
managementFee: 10,
|
||||
profitShare: 5,
|
||||
hurdleRate: 0.1,
|
||||
permissioned: false,
|
||||
},
|
||||
},
|
||||
explanation: "Get information about a drift vault",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vaultNameOrAddress: z.string().describe("Name or address of the vault"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
try {
|
||||
const vaultInfo = await getVaultInfo(agent, input.vaultNameOrAddress);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Vault info retrieved successfully",
|
||||
data: vaultInfo,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to retrieve vault info: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default vaultInfoAction;
|
||||
77
src/actions/drift/withdrawFromDriftAccount.ts
Normal file
77
src/actions/drift/withdrawFromDriftAccount.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import { withdrawFromDriftUserAccount } from "../../tools";
|
||||
|
||||
const withdrawFromDriftAccountAction: Action = {
|
||||
name: "WITHDRAW_OR_BORROW_FROM_DRIFT_ACCOUNT",
|
||||
description: "Withdraw funds from your drift account",
|
||||
similes: [
|
||||
"withdraw from drift account",
|
||||
"withdraw funds from drift account",
|
||||
"withdraw funds from my drift account",
|
||||
"borrow from drift account",
|
||||
"borrow funds from my drift account",
|
||||
"borrow from drift",
|
||||
"withdraw from drift",
|
||||
],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 100,
|
||||
symbol: "usdc",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Funds withdrawn successfully",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Withdraw 100 USDC from your drift account",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe(
|
||||
"The amount in tokens you'd like to withdraw from your drift account in normal token amounts, e.g 50 SOL, 100 USDC, etc",
|
||||
),
|
||||
symbol: z
|
||||
.string()
|
||||
.toUpperCase()
|
||||
.describe("The symbol of the token you'd like to withdraw"),
|
||||
isBorrow: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(false)
|
||||
.describe(
|
||||
"Whether or not to borrow funds based on collateral provided instead of withdrawing",
|
||||
),
|
||||
}),
|
||||
handler: async (agent, input) => {
|
||||
try {
|
||||
const tx = await withdrawFromDriftUserAccount(
|
||||
agent,
|
||||
input.amount,
|
||||
input.symbol,
|
||||
input.isBorrow,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Funds withdrawn successfully",
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message is a string
|
||||
message: `Failed to withdraw funds: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default withdrawFromDriftAccountAction;
|
||||
52
src/actions/drift/withdrawFromVault.ts
Normal file
52
src/actions/drift/withdrawFromVault.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { z } from "zod";
|
||||
import type { Action } from "../../types";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import { withdrawFromDriftVault } from "../../tools";
|
||||
|
||||
const withdrawFromVaultAction: Action = {
|
||||
name: "WITHDRAW_FROM_DRIFT_VAULT",
|
||||
description:
|
||||
"Withdraw funds from a vault given the redemption time has elapsed.",
|
||||
similes: ["withdraw from drift vault", "redeem funds from vault"],
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
vaultAddress: "2nFeP7taii",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Withdrawal successful",
|
||||
signature:
|
||||
"2nFeP7taii3wGVgrWk4YiLMPmhtu3Zg9iXCUu4zGBDadwunHw8reXFxRWT7khbFsQ9JT3zK4RYDLNDFDRYvM3wJk",
|
||||
},
|
||||
explanation: "Withdraw funds from a drift vault",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vaultAddress: z.string().describe("Vault's address"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
try {
|
||||
const tx = await withdrawFromDriftVault(
|
||||
agent,
|
||||
input.vaultAddress as string,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Withdrawal successful",
|
||||
signature: tx,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
status: "error",
|
||||
// @ts-expect-error - error message
|
||||
message: `Failed to withdraw funds: ${e.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default withdrawFromVaultAction;
|
||||
@@ -1,3 +1,4 @@
|
||||
import tokenBalancesAction from "./tokenBalances";
|
||||
import deployTokenAction from "./metaplex/deployToken";
|
||||
import balanceAction from "./solana/balance";
|
||||
import transferAction from "./solana/transfer";
|
||||
@@ -13,6 +14,8 @@ import stakeWithJupAction from "./jupiter/stakeWithJup";
|
||||
import stakeWithSolayerAction from "./solayer/stakeWithSolayer";
|
||||
import registerDomainAction from "./sns/registerDomain";
|
||||
import lendAssetAction from "./lulo/lendAsset";
|
||||
import luloLendAction from "./lulo/luloLend";
|
||||
import luloWithdrawAction from "./lulo/luloWithdraw";
|
||||
import createGibworkTaskAction from "./gibwork/createGibworkTask";
|
||||
import resolveSolDomainAction from "./sns/resolveSolDomain";
|
||||
import pythFetchPriceAction from "./pyth/pythFetchPrice";
|
||||
@@ -43,9 +46,36 @@ import getAssetsByOwnerAction from "./helius/getAssetsbyOwner";
|
||||
import getWebhookAction from "./helius/getWebhook";
|
||||
import parseSolanaTransactionAction from "./helius/parseTransaction";
|
||||
import sendTransactionWithPriorityFeeAction from "./helius/sendTransactionWithPriority";
|
||||
import createDriftVaultAction from "./drift/createVault";
|
||||
import updateDriftVaultAction from "./drift/updateVault";
|
||||
import depositIntoDriftVaultAction from "./drift/depositIntoVault";
|
||||
import requestWithdrawalFromVaultAction from "./drift/requestWithdrawalFromVault";
|
||||
import withdrawFromVaultAction from "./drift/withdrawFromVault";
|
||||
import tradeDelegatedDriftVaultAction from "./drift/tradeDelegatedDriftVault";
|
||||
import vaultInfoAction from "./drift/vaultInfo";
|
||||
import createDriftUserAccountAction from "./drift/createDriftUserAccount";
|
||||
import tradeDriftPerpAccountAction from "./drift/tradePerpAccount";
|
||||
import doesUserHaveDriftAccountAction from "./drift/doesUserHaveDriftAccount";
|
||||
import depositToDriftUserAccountAction from "./drift/depositToDriftUserAccount";
|
||||
import withdrawFromDriftAccountAction from "./drift/withdrawFromDriftAccount";
|
||||
import driftUserAccountInfoAction from "./drift/driftUserAccountInfo";
|
||||
import deriveDriftVaultAddressAction from "./drift/deriveVaultAddress";
|
||||
import updateDriftVaultDelegateAction from "./drift/updateDriftVaultDelegate";
|
||||
import availableDriftMarketsAction from "./drift/availableMarkets";
|
||||
import stakeToDriftInsuranceFundAction from "./drift/stakeToDriftInsuranceFund";
|
||||
import requestUnstakeFromDriftInsuranceFundAction from "./drift/requestUnstakeFromDriftInsuranceFund";
|
||||
import unstakeFromDriftInsuranceFundAction from "./drift/unstakeFromDriftInsuranceFund";
|
||||
import driftSpotTokenSwapAction from "./drift/swapSpotToken";
|
||||
import perpMarktetFundingRateAction from "./drift/perpMarketFundingRate";
|
||||
import entryQuoteOfPerpTradeAction from "./drift/entryQuoteOfPerpTrade";
|
||||
import lendAndBorrowAPYAction from "./drift/getLendAndBorrowAPY";
|
||||
import getVoltrPositionValuesAction from "./voltr/getPositionValues";
|
||||
import depositVoltrStrategyAction from "./voltr/depositStrategy";
|
||||
import withdrawVoltrStrategyAction from "./voltr/withdrawStrategy";
|
||||
|
||||
export const ACTIONS = {
|
||||
WALLET_ADDRESS_ACTION: getWalletAddressAction,
|
||||
TOKEN_BALANCES_ACTION: tokenBalancesAction,
|
||||
DEPLOY_TOKEN_ACTION: deployTokenAction,
|
||||
BALANCE_ACTION: balanceAction,
|
||||
TRANSFER_ACTION: transferAction,
|
||||
@@ -61,6 +91,8 @@ export const ACTIONS = {
|
||||
STAKE_WITH_SOLAYER_ACTION: stakeWithSolayerAction,
|
||||
REGISTER_DOMAIN_ACTION: registerDomainAction,
|
||||
LEND_ASSET_ACTION: lendAssetAction,
|
||||
LULO_LEND_ACTION: luloLendAction,
|
||||
LULO_WITHDRAW_ACTION: luloWithdrawAction,
|
||||
CREATE_GIBWORK_TASK_ACTION: createGibworkTaskAction,
|
||||
RESOLVE_SOL_DOMAIN_ACTION: resolveSolDomainAction,
|
||||
PYTH_FETCH_PRICE_ACTION: pythFetchPriceAction,
|
||||
@@ -91,6 +123,33 @@ export const ACTIONS = {
|
||||
GET_WEBHOOK_ACTION: getWebhookAction,
|
||||
PARSE_TRANSACTION_ACTION: parseSolanaTransactionAction,
|
||||
SEND_TRANSACTION_WITH_PRIORITY_ACTION: sendTransactionWithPriorityFeeAction,
|
||||
CREATE_DRIFT_VAULT_ACTION: createDriftVaultAction,
|
||||
UPDATE_DRIFT_VAULT_ACTION: updateDriftVaultAction,
|
||||
DEPOSIT_INTO_DRIFT_VAULT_ACTION: depositIntoDriftVaultAction,
|
||||
REQUEST_WITHDRAWAL_FROM_DRIFT_VAULT_ACTION: requestWithdrawalFromVaultAction,
|
||||
WITHDRAW_FROM_DRIFT_VAULT_ACTION: withdrawFromVaultAction,
|
||||
TRADE_DELEGATED_DRIFT_VAULT_ACTION: tradeDelegatedDriftVaultAction,
|
||||
DRIFT_VAULT_INFO_ACTION: vaultInfoAction,
|
||||
CREATE_DRIFT_USER_ACCOUNT_ACTION: createDriftUserAccountAction,
|
||||
TRADE_DRIFT_PERP_ACCOUNT_ACTION: tradeDriftPerpAccountAction,
|
||||
DOES_USER_HAVE_DRIFT_ACCOUNT_ACTION: doesUserHaveDriftAccountAction,
|
||||
DEPOSIT_TO_DRIFT_USER_ACCOUNT_ACTION: depositToDriftUserAccountAction,
|
||||
WITHDRAW_OR_BORROW_FROM_DRIFT_ACCOUNT_ACTION: withdrawFromDriftAccountAction,
|
||||
DRIFT_USER_ACCOUNT_INFO_ACTION: driftUserAccountInfoAction,
|
||||
DERIVE_DRIFT_VAULT_ADDRESS_ACTION: deriveDriftVaultAddressAction,
|
||||
UPDATE_DRIFT_VAULT_DELEGATE_ACTION: updateDriftVaultDelegateAction,
|
||||
AVAILABLE_DRIFT_MARKETS_ACTION: availableDriftMarketsAction,
|
||||
STAKE_TO_DRIFT_INSURANCE_FUND_ACTION: stakeToDriftInsuranceFundAction,
|
||||
REQUEST_UNSTAKE_FROM_DRIFT_INSURANCE_FUND_ACTION:
|
||||
requestUnstakeFromDriftInsuranceFundAction,
|
||||
UNSTAKE_FROM_DRIFT_INSURANCE_FUND_ACTION: unstakeFromDriftInsuranceFundAction,
|
||||
DRIFT_SPOT_TOKEN_SWAP_ACTION: driftSpotTokenSwapAction,
|
||||
DRIFT_PERP_MARKET_FUNDING_RATE_ACTION: perpMarktetFundingRateAction,
|
||||
DRIFT_GET_ENTRY_QUOTE_OF_PERP_TRADE_ACTION: entryQuoteOfPerpTradeAction,
|
||||
DRIFT_GET_LEND_AND_BORROW_APY_ACTION: lendAndBorrowAPYAction,
|
||||
GET_VOLTR_POSITION_VALUES_ACTION: getVoltrPositionValuesAction,
|
||||
DEPOSIT_VOLTR_STRATEGY_ACTION: depositVoltrStrategyAction,
|
||||
WITHDRAW_VOLTR_STRATEGY_ACTION: withdrawVoltrStrategyAction,
|
||||
};
|
||||
|
||||
export type { Action, ActionExample, Handler } from "../types/action";
|
||||
|
||||
62
src/actions/lulo/luloLend.ts
Normal file
62
src/actions/lulo/luloLend.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { luloLend } from "../../tools/lulo";
|
||||
|
||||
const luloLendAction: Action = {
|
||||
name: "LULO_LEND",
|
||||
similes: [
|
||||
"lend USDC with lulo",
|
||||
"lend PYUSD with lulo",
|
||||
"lend USDS with lulo",
|
||||
"lend USDT with lulo",
|
||||
"lend SQL with lulo",
|
||||
"lend jitoSQL with lulo",
|
||||
"lend bSQL with lulo",
|
||||
"lend mSQL with lulo",
|
||||
"lend BONK with lulo",
|
||||
"lend JUP with lulo",
|
||||
],
|
||||
description: "Lend SPL tokens using Lulo protocol",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
mintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
amount: 100,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
signature: "4xKpN2...",
|
||||
message: "Successfully lend 100 USDC",
|
||||
},
|
||||
explanation: "Lend 100 USDC on Lulo",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
mintAddress: z.string().describe("SPL Mint address"),
|
||||
amount: z.number().positive().describe("Amount to lend"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const mintAddress = input.mintAddress as string;
|
||||
const amount = input.amount as number;
|
||||
|
||||
const response = await luloLend(agent, mintAddress, amount);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signature: response,
|
||||
message: `Successfully lend ${amount} of token ${mintAddress}`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Lend failed: ${error.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default luloLendAction;
|
||||
62
src/actions/lulo/luloWithdraw.ts
Normal file
62
src/actions/lulo/luloWithdraw.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { luloWithdraw } from "../../tools/lulo";
|
||||
|
||||
const luloWithdrawAction: Action = {
|
||||
name: "LULO_WITHDRAW",
|
||||
similes: [
|
||||
"withdraw USDC with lulo",
|
||||
"withdraw PYUSD with lulo",
|
||||
"withdraw USDS with lulo",
|
||||
"withdraw USDT with lulo",
|
||||
"withdraw SQL with lulo",
|
||||
"withdraw jitoSQL with lulo",
|
||||
"withdraw bSQL with lulo",
|
||||
"withdraw mSQL with lulo",
|
||||
"withdraw BONK with lulo",
|
||||
"withdraw JUP with lulo",
|
||||
],
|
||||
description: "Withdraw SPL tokens using Lulo protocol",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
mintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
amount: 100,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
signature: "4xKpN2...",
|
||||
message: "Successfully withdraw 100 USDC",
|
||||
},
|
||||
explanation: "Withdraw 100 USDC on Lulo",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
mintAddress: z.string().describe("SPL Mint address"),
|
||||
amount: z.number().positive().describe("Amount to lend"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const mintAddress = input.mintAddress as string;
|
||||
const amount = input.amount as number;
|
||||
|
||||
const response = await luloWithdraw(agent, mintAddress, amount);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
signature: response,
|
||||
message: `Successfully withdraw ${amount} of token ${mintAddress}`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Withdraw failed: ${error.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default luloWithdrawAction;
|
||||
@@ -13,7 +13,7 @@ const mintNFTAction: Action = {
|
||||
"create token",
|
||||
"add nft to collection",
|
||||
],
|
||||
description: `Mint a new NFT in a collection on Solana blockchain.`,
|
||||
description: "Mint a new NFT in a collection on Solana blockchain.",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import type { Action } from "../../types/action";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { get_balance } from "../../tools";
|
||||
|
||||
|
||||
80
src/actions/tokenBalances.ts
Normal file
80
src/actions/tokenBalances.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import type { Action } from "../types/action";
|
||||
import type { SolanaAgentKit } from "../agent";
|
||||
import { z } from "zod";
|
||||
import { get_token_balance } from "../tools";
|
||||
|
||||
const tokenBalancesAction: Action = {
|
||||
name: "TOKEN_BALANCE_ACTION",
|
||||
similes: [
|
||||
"check token balances",
|
||||
"get wallet token balances",
|
||||
"view token balances",
|
||||
"show token balances",
|
||||
"check token balance",
|
||||
],
|
||||
description: `Get the token balances of a Solana wallet.
|
||||
If you want to get the balance of your wallet, you don't need to provide the wallet address.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {},
|
||||
output: {
|
||||
status: "success",
|
||||
balance: {
|
||||
sol: 100,
|
||||
tokens: [
|
||||
{
|
||||
tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
name: "USD Coin",
|
||||
symbol: "USDC",
|
||||
balance: 100,
|
||||
decimals: 9,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
explanation: "Get token balances of the wallet",
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
input: {
|
||||
walletAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
balance: {
|
||||
sol: 100,
|
||||
tokens: [
|
||||
{
|
||||
tokenAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
name: "USD Coin",
|
||||
symbol: "USDC",
|
||||
balance: 100,
|
||||
decimals: 9,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
explanation: "Get address token balance",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
walletAddress: z.string().optional(),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input) => {
|
||||
const balance = await get_token_balance(
|
||||
agent,
|
||||
input.tokenAddress && new PublicKey(input.tokenAddress),
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
balance: balance,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default tokenBalancesAction;
|
||||
83
src/actions/voltr/depositStrategy.ts
Normal file
83
src/actions/voltr/depositStrategy.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { BN } from "bn.js";
|
||||
|
||||
const depositVoltrStrategyAction: Action = {
|
||||
name: "DEPOSIT_VOLTR_STRATEGY",
|
||||
similes: [
|
||||
"deposit to voltr strategy",
|
||||
"add funds to voltr vault strategy",
|
||||
"invest in voltr strategy",
|
||||
"deposit assets to voltr",
|
||||
"contribute to voltr vault",
|
||||
"fund voltr strategy",
|
||||
],
|
||||
description: "Deposit assets into a specific strategy within a Voltr vault",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
depositAmount: "1000000000", // 1 USDC with 6 decimals
|
||||
vault: "7opUkqYtxmQRriZvwZkPcg6LqmGjAh1RSEsVrdsGDx5K",
|
||||
strategy: "9ZQQYvr4x7AMqd6abVa1f5duGjti5wk1MHsX6hogPsLk",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
vault: "7opUkqYtxmQRriZvwZkPcg6LqmGjAh1RSEsVrdsGDx5K",
|
||||
strategy: "9ZQQYvr4x7AMqd6abVa1f5duGjti5wk1MHsX6hogPsLk",
|
||||
signature: "2ZE7Rz...",
|
||||
message: "Successfully deposited 1000000000 into strategy",
|
||||
},
|
||||
explanation: "Deposit 1 USDC into a Voltr vault strategy",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
depositAmount: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("The amount to deposit (in base units including decimals)"),
|
||||
vault: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe(
|
||||
"The public key of the Voltr source vault to take assets from, e.g., 'Ga27...'",
|
||||
),
|
||||
strategy: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe(
|
||||
"The public key of the initialized target strategy to deposit into, e.g., 'Jheh...'",
|
||||
),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const depositAmount = new BN(input.depositAmount);
|
||||
const vault = new PublicKey(input.vault);
|
||||
const strategy = new PublicKey(input.strategy);
|
||||
|
||||
const signature = await agent.voltrDepositStrategy(
|
||||
depositAmount,
|
||||
vault,
|
||||
strategy,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
vault: vault.toBase58(),
|
||||
strategy: strategy.toBase58(),
|
||||
signature,
|
||||
message: `Successfully deposited ${input.depositAmount} into strategy`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to deposit into strategy: ${error.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default depositVoltrStrategyAction;
|
||||
74
src/actions/voltr/getPositionValues.ts
Normal file
74
src/actions/voltr/getPositionValues.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const getVoltrPositionValuesAction: Action = {
|
||||
name: "GET_VOLTR_POSITION_VALUES",
|
||||
similes: [
|
||||
"get voltr vault value",
|
||||
"check voltr position",
|
||||
"get voltr vault assets",
|
||||
"view voltr holdings",
|
||||
"check voltr portfolio",
|
||||
"get voltr vault breakdown",
|
||||
],
|
||||
description:
|
||||
"Get the current position values and total assets for a Voltr vault",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
vault: "7opUkqYtxmQRriZvwZkPcg6LqmGjAh1RSEsVrdsGDx5K",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
data: {
|
||||
totalValue: 1000000,
|
||||
positions: [
|
||||
{
|
||||
strategy: "4JHtgXyMb9gFJ1hGd2sh645jrZcxurSG3QP7Le3aTMTx",
|
||||
value: 600000,
|
||||
},
|
||||
{
|
||||
strategy: "4i9kzGr1UkxBCCUkQUQ4vsF51fjdt2knKxrwM1h1NW4g",
|
||||
value: 400000,
|
||||
},
|
||||
],
|
||||
},
|
||||
message: "Successfully retrieved Voltr vault position values",
|
||||
},
|
||||
explanation:
|
||||
"Get position values for a Voltr vault showing total value and value per strategy",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
vault: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("The public key of the Voltr vault to query, e.g., 'Ga27...'"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const vault = new PublicKey(input.vault);
|
||||
|
||||
const result = await agent.voltrGetPositionValues(vault);
|
||||
const positionData = JSON.parse(result);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
vault: vault.toBase58(),
|
||||
data: positionData,
|
||||
message: "Successfully retrieved Voltr vault position values",
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to get vault position values: ${error.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default getVoltrPositionValuesAction;
|
||||
83
src/actions/voltr/withdrawStrategy.ts
Normal file
83
src/actions/voltr/withdrawStrategy.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { BN } from "bn.js";
|
||||
|
||||
const withdrawVoltrStrategyAction: Action = {
|
||||
name: "WITHDRAW_VOLTR_STRATEGY",
|
||||
similes: [
|
||||
"withdraw from voltr strategy",
|
||||
"remove funds from voltr vault strategy",
|
||||
"take out from voltr strategy",
|
||||
"withdraw assets from voltr",
|
||||
"pull from voltr vault",
|
||||
"redeem from voltr strategy",
|
||||
],
|
||||
description: "Withdraw assets from a specific strategy within a Voltr vault",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
withdrawAmount: "1000000000", // 1 USDC with 6 decimals
|
||||
vault: "7opUkqYtxmQRriZvwZkPcg6LqmGjAh1RSEsVrdsGDx5K",
|
||||
strategy: "9ZQQYvr4x7AMqd6abVa1f5duGjti5wk1MHsX6hogPsLk",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
vault: "7opUkqYtxmQRriZvwZkPcg6LqmGjAh1RSEsVrdsGDx5K",
|
||||
strategy: "9ZQQYvr4x7AMqd6abVa1f5duGjti5wk1MHsX6hogPsLk",
|
||||
signature: "2ZE7Rz...",
|
||||
message: "Successfully withdrew 1000000000 from strategy",
|
||||
},
|
||||
explanation: "Withdraw 1 USDC from a Voltr vault strategy",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
withdrawAmount: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("The amount to withdraw (in base units including decimals)"),
|
||||
vault: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe(
|
||||
"The public key of the Voltr source vault to deposit assets into, e.g., 'Ga27...'",
|
||||
),
|
||||
strategy: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe(
|
||||
"The public key of the initialized target strategy to withdraw from, e.g., 'Jheh...'",
|
||||
),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const withdrawAmount = new BN(input.withdrawAmount);
|
||||
const vault = new PublicKey(input.vault);
|
||||
const strategy = new PublicKey(input.strategy);
|
||||
|
||||
const signature = await agent.voltrWithdrawStrategy(
|
||||
withdrawAmount,
|
||||
vault,
|
||||
strategy,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
vault: vault.toBase58(),
|
||||
strategy: strategy.toBase58(),
|
||||
signature,
|
||||
message: `Successfully withdrew ${input.withdrawAmount} from strategy`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to withdraw from strategy: ${error.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default withdrawVoltrStrategyAction;
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
getPrimaryDomain,
|
||||
launchPumpFunToken,
|
||||
lendAsset,
|
||||
luloLend,
|
||||
luloWithdraw,
|
||||
mintCollectionNFT,
|
||||
openbookCreateMarket,
|
||||
manifestCreateMarket,
|
||||
@@ -84,6 +86,34 @@ import {
|
||||
getHeliusWebhook,
|
||||
create_HeliusWebhook,
|
||||
deleteHeliusWebhook,
|
||||
createDriftUserAccount,
|
||||
createVault,
|
||||
depositIntoVault,
|
||||
depositToDriftUserAccount,
|
||||
getVaultAddress,
|
||||
doesUserHaveDriftAccount,
|
||||
driftUserAccountInfo,
|
||||
requestWithdrawalFromVault,
|
||||
tradeDriftVault,
|
||||
driftPerpTrade,
|
||||
updateVault,
|
||||
getVaultInfo,
|
||||
withdrawFromDriftUserAccount,
|
||||
withdrawFromDriftVault,
|
||||
updateVaultDelegate,
|
||||
get_token_balance,
|
||||
getAvailableDriftSpotMarkets,
|
||||
getAvailableDriftPerpMarkets,
|
||||
stakeToDriftInsuranceFund,
|
||||
requestUnstakeFromDriftInsuranceFund,
|
||||
unstakeFromDriftInsuranceFund,
|
||||
swapSpotToken,
|
||||
calculatePerpMarketFundingRate,
|
||||
getEntryQuoteOfPerpTrade,
|
||||
getLendingAndBorrowAPY,
|
||||
voltrGetPositionValues,
|
||||
voltrDepositStrategy,
|
||||
voltrWithdrawStrategy,
|
||||
} from "../tools";
|
||||
import {
|
||||
Config,
|
||||
@@ -176,6 +206,19 @@ export class SolanaAgentKit {
|
||||
return get_balance(this, token_address);
|
||||
}
|
||||
|
||||
async getTokenBalances(wallet_address?: PublicKey): Promise<{
|
||||
sol: number;
|
||||
tokens: Array<{
|
||||
tokenAddress: string;
|
||||
name: string;
|
||||
symbol: string;
|
||||
balance: number;
|
||||
decimals: number;
|
||||
}>;
|
||||
}> {
|
||||
return get_token_balance(this, wallet_address);
|
||||
}
|
||||
|
||||
async getBalanceOther(
|
||||
walletAddress: PublicKey,
|
||||
tokenAddress?: PublicKey,
|
||||
@@ -284,6 +327,14 @@ export class SolanaAgentKit {
|
||||
return lendAsset(this, amount);
|
||||
}
|
||||
|
||||
async luloLend(mintAddress: string, amount: number): Promise<string> {
|
||||
return luloLend(this, mintAddress, amount);
|
||||
}
|
||||
|
||||
async luloWithdraw(mintAddress: string, amount: number): Promise<string> {
|
||||
return luloWithdraw(this, mintAddress, amount);
|
||||
}
|
||||
|
||||
async getTPS(): Promise<number> {
|
||||
return getTPS(this);
|
||||
}
|
||||
@@ -655,24 +706,43 @@ export class SolanaAgentKit {
|
||||
}
|
||||
|
||||
async create3LandCollection(
|
||||
optionsWithBase58: StoreInitOptions,
|
||||
collectionOpts: CreateCollectionOptions,
|
||||
isDevnet: boolean = false,
|
||||
): Promise<string> {
|
||||
const optionsWithBase58: StoreInitOptions = {
|
||||
privateKey: this.wallet.secretKey,
|
||||
};
|
||||
if (isDevnet) {
|
||||
optionsWithBase58.isMainnet = false;
|
||||
} else {
|
||||
optionsWithBase58.isMainnet = true;
|
||||
}
|
||||
|
||||
const tx = await createCollection(optionsWithBase58, collectionOpts);
|
||||
return `Transaction: ${tx}`;
|
||||
}
|
||||
|
||||
async create3LandNft(
|
||||
optionsWithBase58: StoreInitOptions,
|
||||
collectionAccount: string,
|
||||
createItemOptions: CreateSingleOptions,
|
||||
isMainnet: boolean,
|
||||
isDevnet: boolean = false,
|
||||
withPool: boolean = false,
|
||||
): Promise<string> {
|
||||
const optionsWithBase58: StoreInitOptions = {
|
||||
privateKey: this.wallet.secretKey,
|
||||
};
|
||||
if (isDevnet) {
|
||||
optionsWithBase58.isMainnet = false;
|
||||
} else {
|
||||
optionsWithBase58.isMainnet = true;
|
||||
}
|
||||
|
||||
const tx = await createSingle(
|
||||
optionsWithBase58,
|
||||
collectionAccount,
|
||||
createItemOptions,
|
||||
isMainnet,
|
||||
!isDevnet,
|
||||
withPool,
|
||||
);
|
||||
return `Transaction: ${tx}`;
|
||||
}
|
||||
@@ -747,4 +817,185 @@ export class SolanaAgentKit {
|
||||
async deleteWebhook(webhookID: string): Promise<any> {
|
||||
return deleteHeliusWebhook(this, webhookID);
|
||||
}
|
||||
|
||||
async createDriftUserAccount(depositAmount: number, depositSymbol: string) {
|
||||
return await createDriftUserAccount(this, depositAmount, depositSymbol);
|
||||
}
|
||||
|
||||
async createDriftVault(params: {
|
||||
name: string;
|
||||
marketName: `${string}-${string}`;
|
||||
redeemPeriod: number;
|
||||
maxTokens: number;
|
||||
minDepositAmount: number;
|
||||
managementFee: number;
|
||||
profitShare: number;
|
||||
hurdleRate?: number;
|
||||
permissioned?: boolean;
|
||||
}) {
|
||||
return await createVault(this, params);
|
||||
}
|
||||
|
||||
async depositIntoDriftVault(amount: number, vault: string) {
|
||||
return await depositIntoVault(this, amount, vault);
|
||||
}
|
||||
async depositToDriftUserAccount(
|
||||
amount: number,
|
||||
symbol: string,
|
||||
isRepayment?: boolean,
|
||||
) {
|
||||
return await depositToDriftUserAccount(this, amount, symbol, isRepayment);
|
||||
}
|
||||
async deriveDriftVaultAddress(name: string) {
|
||||
return await getVaultAddress(this, name);
|
||||
}
|
||||
async doesUserHaveDriftAccount() {
|
||||
return await doesUserHaveDriftAccount(this);
|
||||
}
|
||||
async driftUserAccountInfo() {
|
||||
return await driftUserAccountInfo(this);
|
||||
}
|
||||
async requestWithdrawalFromDriftVault(amount: number, vault: string) {
|
||||
return await requestWithdrawalFromVault(this, amount, vault);
|
||||
}
|
||||
async tradeUsingDelegatedDriftVault(
|
||||
vault: string,
|
||||
amount: number,
|
||||
symbol: string,
|
||||
action: "long" | "short",
|
||||
type: "market" | "limit",
|
||||
price?: number,
|
||||
) {
|
||||
return await tradeDriftVault(
|
||||
this,
|
||||
vault,
|
||||
amount,
|
||||
symbol,
|
||||
action,
|
||||
type,
|
||||
price,
|
||||
);
|
||||
}
|
||||
async tradeUsingDriftPerpAccount(
|
||||
amount: number,
|
||||
symbol: string,
|
||||
action: "long" | "short",
|
||||
type: "market" | "limit",
|
||||
price?: number,
|
||||
) {
|
||||
return await driftPerpTrade(this, { action, amount, symbol, type, price });
|
||||
}
|
||||
async updateDriftVault(
|
||||
vaultAddress: string,
|
||||
params: {
|
||||
name: string;
|
||||
marketName: `${string}-${string}`;
|
||||
redeemPeriod: number;
|
||||
maxTokens: number;
|
||||
minDepositAmount: number;
|
||||
managementFee: number;
|
||||
profitShare: number;
|
||||
hurdleRate?: number;
|
||||
permissioned?: boolean;
|
||||
},
|
||||
) {
|
||||
return await updateVault(this, vaultAddress, params);
|
||||
}
|
||||
async getDriftVaultInfo(vaultName: string) {
|
||||
return await getVaultInfo(this, vaultName);
|
||||
}
|
||||
async withdrawFromDriftAccount(
|
||||
amount: number,
|
||||
symbol: string,
|
||||
isBorrow?: boolean,
|
||||
) {
|
||||
return await withdrawFromDriftUserAccount(this, amount, symbol, isBorrow);
|
||||
}
|
||||
async withdrawFromDriftVault(vault: string) {
|
||||
return await withdrawFromDriftVault(this, vault);
|
||||
}
|
||||
async updateDriftVaultDelegate(vaultAddress: string, delegate: string) {
|
||||
return await updateVaultDelegate(this, vaultAddress, delegate);
|
||||
}
|
||||
|
||||
getAvailableDriftMarkets(type?: "spot" | "perp") {
|
||||
switch (type) {
|
||||
case "spot":
|
||||
return getAvailableDriftSpotMarkets();
|
||||
case "perp":
|
||||
return getAvailableDriftPerpMarkets();
|
||||
default:
|
||||
return {
|
||||
spot: getAvailableDriftSpotMarkets(),
|
||||
perp: getAvailableDriftPerpMarkets(),
|
||||
};
|
||||
}
|
||||
}
|
||||
async stakeToDriftInsuranceFund(amount: number, symbol: string) {
|
||||
return await stakeToDriftInsuranceFund(this, amount, symbol);
|
||||
}
|
||||
async requestUnstakeFromDriftInsuranceFund(amount: number, symbol: string) {
|
||||
return await requestUnstakeFromDriftInsuranceFund(this, amount, symbol);
|
||||
}
|
||||
async unstakeFromDriftInsuranceFund(symbol: string) {
|
||||
return await unstakeFromDriftInsuranceFund(this, symbol);
|
||||
}
|
||||
async driftSpotTokenSwap(
|
||||
params: {
|
||||
fromSymbol: string;
|
||||
toSymbol: string;
|
||||
slippage?: number;
|
||||
} & (
|
||||
| {
|
||||
toAmount: number;
|
||||
}
|
||||
| { fromAmount: number }
|
||||
),
|
||||
) {
|
||||
return await swapSpotToken(this, {
|
||||
fromSymbol: params.fromSymbol,
|
||||
toSymbol: params.toSymbol,
|
||||
// @ts-expect-error - fromAmount and toAmount are mutually exclusive
|
||||
fromAmount: params.fromAmount,
|
||||
// @ts-expect-error - fromAmount and toAmount are mutually exclusive
|
||||
toAmount: params.toAmount,
|
||||
slippage: params.slippage,
|
||||
});
|
||||
}
|
||||
async getPerpMarketFundingRate(
|
||||
symbol: `${string}-PERP`,
|
||||
period: "year" | "hour" = "year",
|
||||
) {
|
||||
return calculatePerpMarketFundingRate(this, symbol, period);
|
||||
}
|
||||
async getEntryQuoteOfPerpTrade(
|
||||
amount: number,
|
||||
symbol: `${string}-PERP`,
|
||||
action: "short" | "long",
|
||||
) {
|
||||
return getEntryQuoteOfPerpTrade(symbol, amount, action);
|
||||
}
|
||||
async getLendAndBorrowAPY(symbol: string) {
|
||||
return getLendingAndBorrowAPY(this, symbol);
|
||||
}
|
||||
|
||||
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 voltrGetPositionValues(vault: PublicKey): Promise<string> {
|
||||
return voltrGetPositionValues(this, vault);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,3 +42,8 @@ export const METEORA_DYNAMIC_AMM_PROGRAM_ID = new PublicKey(
|
||||
export const METEORA_DLMM_PROGRAM_ID = new PublicKey(
|
||||
"LbVRzDTvBDEcrthxfZ4RL6yiq3uZw8bS6MwtdY6UhFQ",
|
||||
);
|
||||
/**
|
||||
* Minimum compute price required to carry out complex transactions on the Drift protocol
|
||||
*/
|
||||
export const MINIMUM_COMPUTE_PRICE_FOR_COMPLEX_ACTIONS =
|
||||
0.000003 * 1000000 * 1000000;
|
||||
|
||||
@@ -10,7 +10,6 @@ export class Solana3LandCreateCollection extends Tool {
|
||||
description = `Creates an NFT Collection that you can visit on 3.land's website (3.land/collection/{collectionAccount})
|
||||
|
||||
Inputs:
|
||||
privateKey (required): represents the privateKey of the wallet - can be an array of numbers, Uint8Array or base58 string
|
||||
isMainnet (required): defines is the tx takes places in mainnet
|
||||
collectionSymbol (required): the symbol of the collection
|
||||
collectionName (required): the name of the collection
|
||||
@@ -26,14 +25,8 @@ export class Solana3LandCreateCollection extends Tool {
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const inputFormat = JSON.parse(input);
|
||||
const privateKey = inputFormat.privateKey;
|
||||
const isMainnet = inputFormat.isMainnet;
|
||||
|
||||
const optionsWithBase58: StoreInitOptions = {
|
||||
...(privateKey && { privateKey }),
|
||||
...(isMainnet && { isMainnet }),
|
||||
};
|
||||
|
||||
const collectionSymbol = inputFormat?.collectionSymbol;
|
||||
const collectionName = inputFormat?.collectionName;
|
||||
const collectionDescription = inputFormat?.collectionDescription;
|
||||
@@ -49,8 +42,8 @@ export class Solana3LandCreateCollection extends Tool {
|
||||
};
|
||||
|
||||
const tx = await this.solanaKit.create3LandCollection(
|
||||
optionsWithBase58,
|
||||
collectionOpts,
|
||||
!isMainnet,
|
||||
);
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
|
||||
@@ -10,7 +10,6 @@ export class Solana3LandCreateSingle extends Tool {
|
||||
description = `Creates an NFT and lists it on 3.land's website
|
||||
|
||||
Inputs:
|
||||
privateKey (required): represents the privateKey of the wallet - can be an array of numbers, Uint8Array or base58 string
|
||||
collectionAccount (optional): represents the account for the nft collection
|
||||
itemName (required): the name of the NFT
|
||||
sellerFee (required): the fee of the seller
|
||||
@@ -21,7 +20,9 @@ export class Solana3LandCreateSingle extends Tool {
|
||||
mainImageUrl (required): the main image of the NFT
|
||||
coverImageUrl (optional): the cover image of the NFT
|
||||
splHash (optional): the hash of the spl token, if not provided listing will be in $SOL
|
||||
isMainnet (required): defines is the tx takes places in mainnet
|
||||
poolName (optional): the name of the pool
|
||||
isMainnet (required): defines if the tx takes places in mainnet
|
||||
withPool (optional): defines if minted edition will be tied to a liquidity pool
|
||||
`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
@@ -31,13 +32,9 @@ export class Solana3LandCreateSingle extends Tool {
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const inputFormat = JSON.parse(input);
|
||||
const privateKey = inputFormat.privateKey;
|
||||
const isMainnet = inputFormat.isMainnet;
|
||||
|
||||
const optionsWithBase58: StoreInitOptions = {
|
||||
...(privateKey && { privateKey }),
|
||||
...(isMainnet && { isMainnet }),
|
||||
};
|
||||
const withPool = inputFormat.withPool;
|
||||
const poolName = inputFormat.poolName;
|
||||
|
||||
const collectionAccount = inputFormat.collectionAccount;
|
||||
|
||||
@@ -52,6 +49,15 @@ export class Solana3LandCreateSingle extends Tool {
|
||||
const coverImageUrl = inputFormat?.coverImageUrl;
|
||||
const splHash = inputFormat?.splHash;
|
||||
|
||||
if (withPool) {
|
||||
if (!poolName) {
|
||||
throw new Error("poolName is required when withPool is true");
|
||||
}
|
||||
if (!splHash) {
|
||||
throw new Error("splHash is required when withPool is true");
|
||||
}
|
||||
}
|
||||
|
||||
const createItemOptions: CreateSingleOptions = {
|
||||
...(itemName && { itemName }),
|
||||
...(sellerFee && { sellerFee }),
|
||||
@@ -63,6 +69,7 @@ export class Solana3LandCreateSingle extends Tool {
|
||||
...(mainImageUrl && { mainImageUrl }),
|
||||
...(coverImageUrl && { coverImageUrl }),
|
||||
...(splHash && { splHash }),
|
||||
...(poolName && { poolName }),
|
||||
};
|
||||
|
||||
if (!collectionAccount) {
|
||||
@@ -70,10 +77,10 @@ export class Solana3LandCreateSingle extends Tool {
|
||||
}
|
||||
|
||||
const tx = await this.solanaKit.create3LandNft(
|
||||
optionsWithBase58,
|
||||
collectionAccount,
|
||||
createItemOptions,
|
||||
isMainnet,
|
||||
!isMainnet,
|
||||
withPool,
|
||||
);
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
|
||||
38
src/langchain/drift/create_user_account.ts
Normal file
38
src/langchain/drift/create_user_account.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaCreateDriftUserAccountTool extends Tool {
|
||||
name = "create_drift_user_account";
|
||||
description = `Create a new user account with a deposit on Drift protocol.
|
||||
|
||||
Inputs (JSON string):
|
||||
- amount: number, amount of the token to deposit (required)
|
||||
- symbol: string, symbol of the token to deposit (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const res = await this.solanaKit.createDriftUserAccount(
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `User account created with ${parsedInput.amount} ${parsedInput.symbol} successfully deposited`,
|
||||
account: res.account,
|
||||
signature: res.txSignature,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "CREATE_DRIFT_USER_ACCOUNT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/langchain/drift/create_vault.ts
Normal file
42
src/langchain/drift/create_vault.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaCreateDriftVaultTool extends Tool {
|
||||
name = "create_drift_vault";
|
||||
description = `Create a new drift vault delegating the agents address as the owner.
|
||||
|
||||
Inputs (JSON string):
|
||||
- name: string, unique vault name (min 5 chars)
|
||||
- marketName: string, market name in TOKEN-SPOT format
|
||||
- redeemPeriod: number, days to wait before funds can be redeemed (min 1)
|
||||
- maxTokens: number, maximum tokens vault can accommodate (min 100)
|
||||
- minDepositAmount: number, minimum deposit amount
|
||||
- managementFee: number, fee percentage for managing funds (max 20)
|
||||
- profitShare: number, profit sharing percentage (max 90, default 5)
|
||||
- hurdleRate: number, optional hurdle rate
|
||||
- permissioned: boolean, whether vault has whitelist`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.createDriftVault(parsedInput);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Drift vault created successfully",
|
||||
vaultName: parsedInput.name,
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "CREATE_DRIFT_VAULT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/langchain/drift/deposit_into_vault.ts
Normal file
37
src/langchain/drift/deposit_into_vault.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDepositIntoDriftVaultTool extends Tool {
|
||||
name = "deposit_into_drift_vault";
|
||||
description = `Deposit funds into an existing drift vault.
|
||||
|
||||
Inputs (JSON string):
|
||||
- vaultAddress: string, address of the vault (required)
|
||||
- amount: number, amount to deposit (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.depositIntoDriftVault(
|
||||
parsedInput.amount,
|
||||
parsedInput.vaultAddress,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Funds deposited successfully",
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "DEPOSIT_INTO_VAULT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/langchain/drift/deposit_to_user_account.ts
Normal file
39
src/langchain/drift/deposit_to_user_account.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDepositToDriftUserAccountTool extends Tool {
|
||||
name = "deposit_to_drift_user_account";
|
||||
description = `Deposit funds into your drift user account.
|
||||
|
||||
Inputs (JSON string):
|
||||
- amount: number, amount to deposit (required)
|
||||
- symbol: string, token symbol (required)
|
||||
- repay: boolean, whether to repay borrowed funds (optional, default: false)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.depositToDriftUserAccount(
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
parsedInput.repay,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Funds deposited successfully",
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "DEPOSIT_TO_DRIFT_ACCOUNT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/langchain/drift/derive_vault_address.ts
Normal file
32
src/langchain/drift/derive_vault_address.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDeriveVaultAddressTool extends Tool {
|
||||
name = "derive_drift_vault_address";
|
||||
description = `Derive a drift vault address from the vault's name.
|
||||
|
||||
Inputs (JSON string):
|
||||
- name: string, name of the vault to derive the address of (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const address = await this.solanaKit.deriveDriftVaultAddress(input);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Vault address derived successfully",
|
||||
address,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "DERIVE_VAULT_ADDRESS_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/langchain/drift/does_user_have_drift_account.ts
Normal file
38
src/langchain/drift/does_user_have_drift_account.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaCheckDriftAccountTool extends Tool {
|
||||
name = "does_user_have_drift_account";
|
||||
description = `Check if a user has a Drift account.
|
||||
|
||||
Inputs: No inputs required - checks the current user's account`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(_input: string): Promise<string> {
|
||||
try {
|
||||
const res = await this.solanaKit.doesUserHaveDriftAccount();
|
||||
|
||||
if (!res.hasAccount) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: "You do not have a Drift account",
|
||||
});
|
||||
}
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Nice! You have a Drift account",
|
||||
account: res.account,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "CHECK_DRIFT_ACCOUNT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/langchain/drift/drift_user_account_info.ts
Normal file
29
src/langchain/drift/drift_user_account_info.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDriftUserAccountInfoTool extends Tool {
|
||||
name = "drift_user_account_info";
|
||||
description = `Get information about your drift account.
|
||||
|
||||
Inputs: No inputs required - retrieves current user's account info`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(_input: string): Promise<string> {
|
||||
try {
|
||||
const accountInfo = await this.solanaKit.driftUserAccountInfo();
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
data: accountInfo,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "DRIFT_ACCOUNT_INFO_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/langchain/drift/entry_quote_of_perp_trade.ts
Normal file
39
src/langchain/drift/entry_quote_of_perp_trade.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDriftEntryQuoteOfPerpTradeTool extends Tool {
|
||||
name = "drift_entry_quote_of_perp_trade";
|
||||
description = `Get an entry quote for a perpetual trade on Drift protocol.
|
||||
|
||||
Inputs (JSON string):
|
||||
- amount: number, amount to trade (required)
|
||||
- symbol: string, market symbol (required)
|
||||
- action: "long" | "short", trade direction (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const quote = await this.solanaKit.getEntryQuoteOfPerpTrade(
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
parsedInput.action,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `Entry quote retrieved for ${parsedInput.action} ${parsedInput.amount} ${parsedInput.symbol}`,
|
||||
data: quote,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "ENTRY_QUOTE_OF_PERP_TRADE_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/langchain/drift/index.ts
Normal file
22
src/langchain/drift/index.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export * from "./create_user_account";
|
||||
export * from "./create_vault";
|
||||
export * from "./deposit_into_vault";
|
||||
export * from "./deposit_to_user_account";
|
||||
export * from "./derive_vault_address";
|
||||
export * from "./does_user_have_drift_account";
|
||||
export * from "./drift_user_account_info";
|
||||
export * from "./request_withdrawal";
|
||||
export * from "./trade_delegated_vault";
|
||||
export * from "./trade_perp_account";
|
||||
export * from "./update_drift_vault_delegate";
|
||||
export * from "./update_vault";
|
||||
export * from "./vault_info";
|
||||
export * from "./withdraw_from_account";
|
||||
export * from "./withdraw_from_vault";
|
||||
export * from "./perp_market_funding_rate";
|
||||
export * from "./entry_quote_of_perp_trade";
|
||||
export * from "./lend_and_borrow_apy";
|
||||
export * from "./stake_to_insurance_fund";
|
||||
export * from "./swap_spot_token";
|
||||
export * from "./unstake_from_insurance_fund";
|
||||
export * from "./request_unstake_from_insurance_fund";
|
||||
32
src/langchain/drift/lend_and_borrow_apy.ts
Normal file
32
src/langchain/drift/lend_and_borrow_apy.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDriftLendAndBorrowAPYTool extends Tool {
|
||||
name = "drift_lend_and_borrow_apy";
|
||||
description = `Get lending and borrowing APY for a token on Drift protocol.
|
||||
|
||||
Inputs (JSON string):
|
||||
- symbol: string, token symbol (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const apyInfo = await this.solanaKit.getLendAndBorrowAPY(input);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `APY information retrieved for ${input}`,
|
||||
data: apyInfo,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "LEND_AND_BORROW_APY_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/langchain/drift/perp_market_funding_rate.ts
Normal file
36
src/langchain/drift/perp_market_funding_rate.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDriftPerpMarketFundingRateTool extends Tool {
|
||||
name = "drift_perp_market_funding_rate";
|
||||
description = `Get the funding rate for a perpetual market on Drift protocol.
|
||||
|
||||
Inputs (JSON string):
|
||||
- symbol: string, market symbol (required)
|
||||
- period: year or hour (default: hour)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const fundingRate = await this.solanaKit.getPerpMarketFundingRate(
|
||||
parsedInput.symbol,
|
||||
parsedInput.period,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `Funding rate retrieved for ${parsedInput.symbol}`,
|
||||
data: fundingRate,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/langchain/drift/request_unstake_from_insurance_fund.ts
Normal file
37
src/langchain/drift/request_unstake_from_insurance_fund.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaRequestUnstakeFromDriftInsuranceFundTool extends Tool {
|
||||
name = "request_unstake_from_drift_insurance_fund";
|
||||
description = `Request to unstake tokens from Drift Insurance Fund.
|
||||
|
||||
Inputs (JSON string):
|
||||
- amount: number, amount to unstake (required)
|
||||
- symbol: string, token symbol (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.requestUnstakeFromDriftInsuranceFund(
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `Requested unstake of ${parsedInput.amount} ${parsedInput.symbol} from the Drift Insurance Fund`,
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "REQUEST_UNSTAKE_FROM_DRIFT_INSURANCE_FUND_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/langchain/drift/request_withdrawal.ts
Normal file
37
src/langchain/drift/request_withdrawal.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaRequestDriftWithdrawalTool extends Tool {
|
||||
name = "request_withdrawal_from_drift_vault";
|
||||
description = `Request a withdrawal from an existing drift vault.
|
||||
|
||||
Inputs (JSON string):
|
||||
- vaultAddress: string, vault address (required)
|
||||
- amount: number, amount of shares to withdraw (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.requestWithdrawalFromDriftVault(
|
||||
parsedInput.amount,
|
||||
parsedInput.vaultAddress,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Withdrawal request successful",
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "REQUEST_DRIFT_WITHDRAWAL_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/langchain/drift/stake_to_insurance_fund.ts
Normal file
37
src/langchain/drift/stake_to_insurance_fund.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaStakeToDriftInsuranceFundTool extends Tool {
|
||||
name = "stake_to_drift_insurance_fund";
|
||||
description = `Stake a token to Drift Insurance Fund.
|
||||
|
||||
Inputs (JSON string):
|
||||
- amount: number, amount to stake (required)
|
||||
- symbol: string, token symbol (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.stakeToDriftInsuranceFund(
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `Staked ${parsedInput.amount} ${parsedInput.symbol} to the Drift Insurance Fund`,
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "STAKE_TO_DRIFT_INSURANCE_FUND_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/langchain/drift/swap_spot_token.ts
Normal file
37
src/langchain/drift/swap_spot_token.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDriftSpotTokenSwapTool extends Tool {
|
||||
name = "drift_spot_token_swap";
|
||||
description = `Swap spot tokens on Drift protocol.
|
||||
|
||||
Inputs (JSON string):
|
||||
- fromSymbol: string, symbol of token to swap from (required)
|
||||
- toSymbol: string, symbol of token to swap to (required)
|
||||
- fromAmount: number, amount to swap from (optional) required if toAmount is not provided
|
||||
- toAmount: number, amount to swap to (optional) required if fromAmount is not provided
|
||||
- slippage: number, slippage tolerance in percentage (optional)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.driftSpotTokenSwap(parsedInput);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `Swapped ${parsedInput.fromAmount} ${parsedInput.fromSymbol} for ${parsedInput.toSymbol}`,
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "DRIFT_SPOT_TOKEN_SWAP_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/langchain/drift/trade_delegated_vault.ts
Normal file
49
src/langchain/drift/trade_delegated_vault.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaTradeDelegatedDriftVaultTool extends Tool {
|
||||
name = "trade_delegated_drift_vault";
|
||||
description = `Carry out trades in a Drift vault.
|
||||
|
||||
Inputs (JSON string):
|
||||
- vaultAddress: string, address of the Drift vault
|
||||
- amount: number, amount to trade
|
||||
- symbol: string, symbol of the token to trade
|
||||
- action: "long" | "short", trade direction
|
||||
- type: "market" | "limit", order type
|
||||
- price: number, optional limit price`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.tradeUsingDelegatedDriftVault(
|
||||
parsedInput.vaultAddress,
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
parsedInput.action,
|
||||
parsedInput.type,
|
||||
parsedInput.price,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message:
|
||||
parsedInput.type === "limit"
|
||||
? "Order placed successfully"
|
||||
: "Trade successful",
|
||||
transactionId: tx,
|
||||
...parsedInput,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "TRADE_DRIFT_VAULT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/langchain/drift/trade_perp_account.ts
Normal file
42
src/langchain/drift/trade_perp_account.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaTradeDriftPerpAccountTool extends Tool {
|
||||
name = "trade_drift_perp_account";
|
||||
description = `Trade a perpetual account on Drift protocol.
|
||||
|
||||
Inputs (JSON string):
|
||||
- amount: number, amount to trade (required)
|
||||
- symbol: string, token symbol (required)
|
||||
- action: "long" | "short", trade direction (required)
|
||||
- type: "market" | "limit", order type (required)
|
||||
- price: number, required for limit orders`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const signature = await this.solanaKit.tradeUsingDriftPerpAccount(
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
parsedInput.action,
|
||||
parsedInput.type,
|
||||
parsedInput.price,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
signature,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "TRADE_PERP_ACCOUNT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/langchain/drift/unstake_from_insurance_fund.ts
Normal file
32
src/langchain/drift/unstake_from_insurance_fund.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaUnstakeFromDriftInsuranceFundTool extends Tool {
|
||||
name = "unstake_from_drift_insurance_fund";
|
||||
description = `Unstake tokens from Drift Insurance Fund after request period has elapsed.
|
||||
|
||||
Inputs (JSON string):
|
||||
- symbol: string, token symbol (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const tx = await this.solanaKit.unstakeFromDriftInsuranceFund(input);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: `Unstaked ${input} from the Drift Insurance Fund`,
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNSTAKE_FROM_DRIFT_INSURANCE_FUND_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/langchain/drift/update_drift_vault_delegate.ts
Normal file
37
src/langchain/drift/update_drift_vault_delegate.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaUpdateDriftVaultDelegateTool extends Tool {
|
||||
name = "update_drift_vault_delegate";
|
||||
description = `Update the delegate of a drift vault.
|
||||
|
||||
Inputs (JSON string):
|
||||
- vaultAddress: string, address of the vault (required)
|
||||
- newDelegate: string, address of the new delegate (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.updateDriftVaultDelegate(
|
||||
parsedInput.vaultAddress,
|
||||
parsedInput.newDelegate,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Vault delegate updated successfully",
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UPDATE_DRIFT_VAULT_DELEGATE_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/langchain/drift/update_vault.ts
Normal file
52
src/langchain/drift/update_vault.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaUpdateDriftVaultTool extends Tool {
|
||||
name = "update_drift_vault";
|
||||
description = `Update an existing drift vault with new settings.
|
||||
|
||||
Inputs (JSON string):
|
||||
- vaultAddress: string, vault address (required)
|
||||
- redeemPeriod: number, days until redemption (optional)
|
||||
- maxTokens: number, maximum tokens allowed (optional)
|
||||
- minDepositAmount: number, minimum deposit amount (optional)
|
||||
- managementFee: number, management fee percentage (optional)
|
||||
- profitShare: number, profit sharing percentage (optional)
|
||||
- hurdleRate: number, hurdle rate (optional)
|
||||
- permissioned: boolean, whitelist requirement (optional)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.updateDriftVault(
|
||||
parsedInput.vaultAddress,
|
||||
// @ts-expect-error - type mismatch
|
||||
{
|
||||
hurdleRate: parsedInput.hurdleRate,
|
||||
maxTokens: parsedInput.maxTokens,
|
||||
minDepositAmount: parsedInput.minDepositAmount,
|
||||
profitShare: parsedInput.profitShare,
|
||||
managementFee: parsedInput.managementFee,
|
||||
permissioned: parsedInput.permissioned,
|
||||
redeemPeriod: parsedInput.redeemPeriod,
|
||||
},
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Drift vault parameters updated successfully",
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UPDATE_DRIFT_VAULT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/langchain/drift/vault_info.ts
Normal file
32
src/langchain/drift/vault_info.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDriftVaultInfoTool extends Tool {
|
||||
name = "drift_vault_info";
|
||||
description = `Get information about a drift vault.
|
||||
|
||||
Inputs (JSON string):
|
||||
- vaultNameOrAddress: string, name or address of the vault (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const vaultInfo = await this.solanaKit.getDriftVaultInfo(input);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Vault info retrieved successfully",
|
||||
data: vaultInfo,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "DRIFT_VAULT_INFO_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/langchain/drift/withdraw_from_account.ts
Normal file
39
src/langchain/drift/withdraw_from_account.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaWithdrawFromDriftAccountTool extends Tool {
|
||||
name = "withdraw_from_drift_account";
|
||||
description = `Withdraw or borrow funds from your drift account.
|
||||
|
||||
Inputs (JSON string):
|
||||
- amount: number, amount to withdraw (required)
|
||||
- symbol: string, token symbol (required)
|
||||
- isBorrow: boolean, whether to borrow funds instead of withdrawing (optional, default: false)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const tx = await this.solanaKit.withdrawFromDriftAccount(
|
||||
parsedInput.amount,
|
||||
parsedInput.symbol,
|
||||
parsedInput.isBorrow,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Funds withdrawn successfully",
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "WITHDRAW_FROM_DRIFT_ACCOUNT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/langchain/drift/withdraw_from_vault.ts
Normal file
32
src/langchain/drift/withdraw_from_vault.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaWithdrawFromDriftVaultTool extends Tool {
|
||||
name = "withdraw_from_drift_vault";
|
||||
description = `Withdraw funds from a vault given the redemption time has elapsed.
|
||||
|
||||
Inputs (JSON string):
|
||||
- vaultAddress: string, vault address (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const tx = await this.solanaKit.withdrawFromDriftVault(input);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Withdrawal successful",
|
||||
signature: tx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "WITHDRAW_FROM_DRIFT_VAULT_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,10 @@ export * from "./lightprotocol";
|
||||
export * from "./squads";
|
||||
export * from "./meteora";
|
||||
export * from "./helius";
|
||||
export * from "./drift";
|
||||
export * from "./voltr";
|
||||
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import type { SolanaAgentKit } from "../agent";
|
||||
import {
|
||||
SolanaBalanceTool,
|
||||
SolanaBalanceOtherTool,
|
||||
@@ -42,6 +44,8 @@ import {
|
||||
SolanaPumpfunTokenLaunchTool,
|
||||
SolanaCreateImageTool,
|
||||
SolanaLendAssetTool,
|
||||
SolanaLuloLendTool,
|
||||
SolanaLuloWithdrawTool,
|
||||
SolanaTPSCalculatorTool,
|
||||
SolanaStakeTool,
|
||||
SolanaRestakeTool,
|
||||
@@ -101,6 +105,31 @@ import {
|
||||
SolanaDeleteHeliusWebhookTool,
|
||||
SolanaParseTransactionHeliusTool,
|
||||
SolanaGetAllAssetsByOwner,
|
||||
SolanaCheckDriftAccountTool,
|
||||
SolanaCreateDriftUserAccountTool,
|
||||
SolanaCreateDriftVaultTool,
|
||||
SolanaDepositIntoDriftVaultTool,
|
||||
SolanaDepositToDriftUserAccountTool,
|
||||
SolanaDeriveVaultAddressTool,
|
||||
SolanaDriftUserAccountInfoTool,
|
||||
SolanaDriftVaultInfoTool,
|
||||
SolanaRequestDriftWithdrawalTool,
|
||||
SolanaTradeDelegatedDriftVaultTool,
|
||||
SolanaTradeDriftPerpAccountTool,
|
||||
SolanaUpdateDriftVaultDelegateTool,
|
||||
SolanaUpdateDriftVaultTool,
|
||||
SolanaWithdrawFromDriftAccountTool,
|
||||
SolanaWithdrawFromDriftVaultTool,
|
||||
SolanaDriftLendAndBorrowAPYTool,
|
||||
SolanaDriftEntryQuoteOfPerpTradeTool,
|
||||
SolanaDriftPerpMarketFundingRateTool,
|
||||
SolanaDriftSpotTokenSwapTool,
|
||||
SolanaRequestUnstakeFromDriftInsuranceFundTool,
|
||||
SolanaStakeToDriftInsuranceFundTool,
|
||||
SolanaUnstakeFromDriftInsuranceFundTool,
|
||||
SolanaVoltrGetPositionValues,
|
||||
SolanaVoltrDepositStrategy,
|
||||
SolanaVoltrWithdrawStrategy,
|
||||
} from "./index";
|
||||
|
||||
export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
@@ -118,6 +147,8 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaPumpfunTokenLaunchTool(solanaKit),
|
||||
new SolanaCreateImageTool(solanaKit),
|
||||
new SolanaLendAssetTool(solanaKit),
|
||||
new SolanaLuloLendTool(solanaKit),
|
||||
new SolanaLuloWithdrawTool(solanaKit),
|
||||
new SolanaTPSCalculatorTool(solanaKit),
|
||||
new SolanaStakeTool(solanaKit),
|
||||
new SolanaRestakeTool(solanaKit),
|
||||
@@ -182,5 +213,30 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaHeliusWebhookTool(solanaKit),
|
||||
new SolanaGetHeliusWebhookTool(solanaKit),
|
||||
new SolanaDeleteHeliusWebhookTool(solanaKit),
|
||||
new SolanaCreateDriftUserAccountTool(solanaKit),
|
||||
new SolanaCreateDriftVaultTool(solanaKit),
|
||||
new SolanaDepositIntoDriftVaultTool(solanaKit),
|
||||
new SolanaDepositToDriftUserAccountTool(solanaKit),
|
||||
new SolanaDeriveVaultAddressTool(solanaKit),
|
||||
new SolanaCheckDriftAccountTool(solanaKit),
|
||||
new SolanaDriftUserAccountInfoTool(solanaKit),
|
||||
new SolanaRequestDriftWithdrawalTool(solanaKit),
|
||||
new SolanaTradeDelegatedDriftVaultTool(solanaKit),
|
||||
new SolanaTradeDriftPerpAccountTool(solanaKit),
|
||||
new SolanaUpdateDriftVaultDelegateTool(solanaKit),
|
||||
new SolanaUpdateDriftVaultTool(solanaKit),
|
||||
new SolanaDriftVaultInfoTool(solanaKit),
|
||||
new SolanaWithdrawFromDriftAccountTool(solanaKit),
|
||||
new SolanaWithdrawFromDriftVaultTool(solanaKit),
|
||||
new SolanaDriftSpotTokenSwapTool(solanaKit),
|
||||
new SolanaStakeToDriftInsuranceFundTool(solanaKit),
|
||||
new SolanaRequestUnstakeFromDriftInsuranceFundTool(solanaKit),
|
||||
new SolanaUnstakeFromDriftInsuranceFundTool(solanaKit),
|
||||
new SolanaDriftLendAndBorrowAPYTool(solanaKit),
|
||||
new SolanaDriftEntryQuoteOfPerpTradeTool(solanaKit),
|
||||
new SolanaDriftPerpMarketFundingRateTool(solanaKit),
|
||||
new SolanaVoltrGetPositionValues(solanaKit),
|
||||
new SolanaVoltrDepositStrategy(solanaKit),
|
||||
new SolanaVoltrWithdrawStrategy(solanaKit),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from "./lend_asset";
|
||||
export * from "./lulo_lend";
|
||||
export * from "./lulo_withdraw";
|
||||
|
||||
37
src/langchain/lulo/lulo_lend.ts
Normal file
37
src/langchain/lulo/lulo_lend.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaLuloLendTool extends Tool {
|
||||
name = "solana_lulo_lend";
|
||||
description = `Lend token for yield using Lulo. (support USDC/PYUSD/USDS/USDT/SOL/jitoSOL/bSOL/mSOL/BONK/JUP)
|
||||
Inputs:
|
||||
mintAddress: string, eg "So11111111111111111111111111111111111111112" (required)
|
||||
amount: number, eg 1, 0.01 (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const mintAddress = parsedInput.mintAddress;
|
||||
const amount = parsedInput.amount;
|
||||
|
||||
const tx = await this.solanaKit.luloLend(mintAddress, amount);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Asset lent successfully",
|
||||
transaction: tx,
|
||||
amount,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/langchain/lulo/lulo_withdraw.ts
Normal file
37
src/langchain/lulo/lulo_withdraw.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaLuloWithdrawTool extends Tool {
|
||||
name = "solana_lulo_withdraw";
|
||||
description = `Withdraw token USDC using Lulo. (support USDC/PYUSD/USDS/USDT/SOL/jitoSOL/bSOL/mSOL/BONK/JUP)
|
||||
Inputs (input is a json string):
|
||||
mintAddress: string, eg "So11111111111111111111111111111111111111112" (required)
|
||||
amount: number, eg 1, 0.01 (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
const mintAddress = parsedInput.mintAddress;
|
||||
const amount = parsedInput.amount;
|
||||
|
||||
const tx = await this.solanaKit.luloWithdraw(mintAddress, amount);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Asset withdraw successfully",
|
||||
transaction: tx,
|
||||
amount,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/langchain/voltr/deposit_strategy.ts
Normal file
39
src/langchain/voltr/deposit_strategy.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { BN } from "bn.js";
|
||||
|
||||
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 {
|
||||
const 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",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/langchain/voltr/get_position_values.ts
Normal file
18
src/langchain/voltr/get_position_values.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
export class SolanaVoltrGetPositionValues extends Tool {
|
||||
name = "solana_voltr_get_position_values";
|
||||
description = `Get the total asset value and current value 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.voltrGetPositionValues(new PublicKey(input));
|
||||
}
|
||||
}
|
||||
3
src/langchain/voltr/index.ts
Normal file
3
src/langchain/voltr/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./deposit_strategy";
|
||||
export * from "./withdraw_strategy";
|
||||
export * from "./get_position_values";
|
||||
39
src/langchain/voltr/withdraw_strategy.ts
Normal file
39
src/langchain/voltr/withdraw_strategy.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { BN } from "bn.js";
|
||||
|
||||
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 {
|
||||
const 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",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,8 @@ export async function createSingle(
|
||||
optionsWithBase58: StoreInitOptions,
|
||||
collectionAccount: string,
|
||||
createItemOptions: CreateSingleOptions,
|
||||
isMainnet: boolean,
|
||||
isMainnet: boolean = false,
|
||||
withPool: boolean = false,
|
||||
) {
|
||||
try {
|
||||
const landStore = isMainnet
|
||||
@@ -49,6 +50,8 @@ export async function createSingle(
|
||||
landStore,
|
||||
collectionAccount,
|
||||
createItemOptions,
|
||||
true, //isAI
|
||||
withPool,
|
||||
);
|
||||
return singleEditionTx;
|
||||
} catch (error: any) {
|
||||
|
||||
1011
src/tools/drift/drift.ts
Normal file
1011
src/tools/drift/drift.ts
Normal file
File diff suppressed because it is too large
Load Diff
649
src/tools/drift/drift_vault.ts
Normal file
649
src/tools/drift/drift_vault.ts
Normal file
@@ -0,0 +1,649 @@
|
||||
import {
|
||||
BASE_PRECISION,
|
||||
convertToNumber,
|
||||
getLimitOrderParams,
|
||||
getMarketOrderParams,
|
||||
getOrderParams,
|
||||
MainnetPerpMarkets,
|
||||
MainnetSpotMarkets,
|
||||
MarketType,
|
||||
numberToSafeBN,
|
||||
PERCENTAGE_PRECISION,
|
||||
PositionDirection,
|
||||
PostOnlyParams,
|
||||
PRICE_PRECISION,
|
||||
QUOTE_PRECISION,
|
||||
TEN,
|
||||
} from "@drift-labs/sdk";
|
||||
import {
|
||||
WithdrawUnit,
|
||||
decodeName,
|
||||
encodeName,
|
||||
getVaultAddressSync,
|
||||
getVaultDepositorAddressSync,
|
||||
} from "@drift-labs/vaults-sdk";
|
||||
import {
|
||||
ComputeBudgetProgram,
|
||||
PublicKey,
|
||||
type TransactionInstruction,
|
||||
} from "@solana/web3.js";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import { BN } from "bn.js";
|
||||
import { initClients } from "./drift";
|
||||
|
||||
export function getMarketIndexAndType(name: `${string}-${string}`) {
|
||||
const [symbol, type] = name.toUpperCase().split("-");
|
||||
|
||||
if (type === "PERP") {
|
||||
const token = MainnetPerpMarkets.find((v) => v.baseAssetSymbol === symbol);
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
`Drift doesn't have that market. Here's a list of available perp markets: ${MainnetPerpMarkets.map((v) => v.baseAssetSymbol).join(", ")}`,
|
||||
);
|
||||
}
|
||||
return { marketIndex: token.marketIndex, marketType: MarketType.PERP };
|
||||
}
|
||||
|
||||
const token = MainnetSpotMarkets.find((v) => v.symbol === symbol);
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
`Drift doesn't have that market. Here's a list of available spot markets: ${MainnetSpotMarkets.map((v) => v.symbol).join(", ")}`,
|
||||
);
|
||||
}
|
||||
return { marketIndex: token.marketIndex, marketType: MarketType.SPOT };
|
||||
}
|
||||
|
||||
async function getOrCreateVaultDepositor(agent: SolanaAgentKit, vault: string) {
|
||||
const { vaultClient, cleanUp } = await initClients(agent);
|
||||
const vaultPublicKey = new PublicKey(vault);
|
||||
const vaultDepositor = getVaultDepositorAddressSync(
|
||||
vaultClient.program.programId,
|
||||
vaultPublicKey,
|
||||
agent.wallet.publicKey,
|
||||
);
|
||||
|
||||
try {
|
||||
await vaultClient.getVaultDepositor(vaultDepositor);
|
||||
await cleanUp();
|
||||
return vaultDepositor;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
if (e.message.includes("Account does not exist")) {
|
||||
await vaultClient.initializeVaultDepositor(
|
||||
vaultPublicKey,
|
||||
agent.wallet.publicKey,
|
||||
);
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
await cleanUp();
|
||||
return vaultDepositor;
|
||||
}
|
||||
}
|
||||
|
||||
async function getVaultAvailableBalance(agent: SolanaAgentKit, vault: string) {
|
||||
try {
|
||||
const { cleanUp, vaultClient } = await initClients(agent);
|
||||
const vaultDetails = await vaultClient.getVault(new PublicKey(vault));
|
||||
|
||||
const currentVaultBalance = convertToNumber(
|
||||
vaultDetails.netDeposits,
|
||||
QUOTE_PRECISION,
|
||||
);
|
||||
const vaultWithdrawalsRequested = convertToNumber(
|
||||
vaultDetails.totalWithdrawRequested,
|
||||
QUOTE_PRECISION,
|
||||
);
|
||||
const availableBalanceInUSD =
|
||||
currentVaultBalance - vaultWithdrawalsRequested;
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return availableBalanceInUSD;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to get vault available balance: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Create a vault
|
||||
@param agent SolanaAgentKit instance
|
||||
@param params Vault creation parameters
|
||||
@param params.name Name of the vault (must be unique)
|
||||
@param params.marketName Market name of the vault (e.g. "USDC-SPOT")
|
||||
@param params.redeemPeriod Redeem period in seconds
|
||||
@param params.maxTokens Maximum amount that can be deposited into the vault (in tokens)
|
||||
@param params.minDepositAmount Minimum amount that can be deposited into the vault (in tokens)
|
||||
@param params.managementFee Management fee percentage (e.g 2 == 2%)
|
||||
@param params.profitShare Profit share percentage (e.g 20 == 20%)
|
||||
@param params.hurdleRate Hurdle rate percentage
|
||||
@param params.permissioned Whether the vault uses a whitelist
|
||||
@returns Promise<anchor.Web3.TransactionSignature> - The transaction signature of the vault creation
|
||||
*/
|
||||
export async function createVault(
|
||||
agent: SolanaAgentKit,
|
||||
params: {
|
||||
name: string;
|
||||
marketName: `${string}-${string}`;
|
||||
redeemPeriod: number;
|
||||
maxTokens: number;
|
||||
minDepositAmount: number;
|
||||
managementFee: number;
|
||||
profitShare: number;
|
||||
hurdleRate?: number;
|
||||
permissioned?: boolean;
|
||||
},
|
||||
) {
|
||||
try {
|
||||
const { vaultClient, driftClient, cleanUp } = await initClients(agent);
|
||||
const marketIndexAndType = getMarketIndexAndType(params.marketName);
|
||||
|
||||
const spotMarket = driftClient.getSpotMarketAccount(
|
||||
marketIndexAndType.marketIndex,
|
||||
);
|
||||
|
||||
if (!spotMarket) {
|
||||
throw new Error(
|
||||
`Market not found. Here's a list of available spot markets: ${MainnetSpotMarkets.map((v) => `${v.symbol}-SPOT`).join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
|
||||
|
||||
if (marketIndexAndType.marketType === MarketType.PERP) {
|
||||
throw new Error(
|
||||
`Only SPOT market names are supported. Such as ${MainnetSpotMarkets.map((v) => `${v.symbol}-SPOT`).join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
const tx = await vaultClient.initializeVault({
|
||||
name: encodeName(params.name),
|
||||
spotMarketIndex: marketIndexAndType.marketIndex,
|
||||
hurdleRate: new BN(params.hurdleRate ?? 0)
|
||||
.mul(PERCENTAGE_PRECISION)
|
||||
.div(new BN(100))
|
||||
.toNumber(),
|
||||
profitShare: new BN(params.profitShare)
|
||||
.mul(PERCENTAGE_PRECISION)
|
||||
.div(new BN(100))
|
||||
.toNumber(),
|
||||
minDepositAmount: numberToSafeBN(params.minDepositAmount, spotPrecision),
|
||||
redeemPeriod: new BN(params.redeemPeriod * 86400),
|
||||
maxTokens: numberToSafeBN(params.maxTokens, spotPrecision),
|
||||
managementFee: new BN(params.managementFee)
|
||||
.mul(PERCENTAGE_PRECISION)
|
||||
.div(new BN(100)),
|
||||
permissioned: params.permissioned ?? false,
|
||||
});
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return tx;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to create Drift vault: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateVaultDelegate(
|
||||
agent: SolanaAgentKit,
|
||||
vault: string,
|
||||
delegateAddress: string,
|
||||
) {
|
||||
try {
|
||||
const { vaultClient, cleanUp } = await initClients(agent);
|
||||
const signature = await vaultClient.updateDelegate(
|
||||
new PublicKey(vault),
|
||||
new PublicKey(delegateAddress),
|
||||
);
|
||||
await cleanUp();
|
||||
return signature;
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
// @ts-expect-error - error message is a string
|
||||
`Failed to update vault delegate: ${e.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Update the vault's info
|
||||
@param agent SolanaAgentKit instance
|
||||
@param vault Vault address
|
||||
@param params Vault update parameters
|
||||
@param params.redeemPeriod Redeem period in seconds
|
||||
@param params.maxTokens Maximum amount that can be deposited into the vault (in tokens)
|
||||
@param params.minDepositAmount Minimum amount that can be deposited into the vault (in tokens)
|
||||
@param params.managementFee Management fee percentage (e.g 2 == 2%)
|
||||
@param params.profitShare Profit share percentage (e.g 20 == 20%)
|
||||
@param params.hurdleRate Hurdle rate percentage
|
||||
@param params.permissioned Whether the vault uses a whitelist
|
||||
@returns Promise<anchor.Web3.TransactionSignature> - The transaction signature of the vault update
|
||||
*/
|
||||
export async function updateVault(
|
||||
agent: SolanaAgentKit,
|
||||
vault: string,
|
||||
params: {
|
||||
redeemPeriod?: number;
|
||||
maxTokens?: number;
|
||||
minDepositAmount?: number;
|
||||
managementFee?: number;
|
||||
profitShare?: number;
|
||||
hurdleRate?: number;
|
||||
permissioned?: boolean;
|
||||
},
|
||||
) {
|
||||
try {
|
||||
const { vaultClient, cleanUp, driftClient } = await initClients(agent);
|
||||
const vaultPublicKey = new PublicKey(vault);
|
||||
const vaultDetails = await vaultClient.getVault(vaultPublicKey);
|
||||
|
||||
const spotMarket = driftClient.getSpotMarketAccount(
|
||||
vaultDetails.spotMarketIndex,
|
||||
);
|
||||
|
||||
if (!spotMarket) {
|
||||
throw new Error(
|
||||
"Market not found. This vault's market is no longer supported",
|
||||
);
|
||||
}
|
||||
|
||||
const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
|
||||
|
||||
const tx = await vaultClient.managerUpdateVault(vaultPublicKey, {
|
||||
redeemPeriod: params.redeemPeriod
|
||||
? new BN(params.redeemPeriod * 86400)
|
||||
: null,
|
||||
maxTokens: params.maxTokens
|
||||
? numberToSafeBN(params.maxTokens, spotPrecision)
|
||||
: null,
|
||||
minDepositAmount: params.minDepositAmount
|
||||
? numberToSafeBN(params.minDepositAmount, spotPrecision)
|
||||
: null,
|
||||
managementFee: params.managementFee
|
||||
? new BN(params.managementFee)
|
||||
.mul(PERCENTAGE_PRECISION)
|
||||
.div(new BN(100))
|
||||
: null,
|
||||
profitShare: params.profitShare
|
||||
? new BN(params.profitShare)
|
||||
.mul(PERCENTAGE_PRECISION)
|
||||
.div(new BN(100))
|
||||
.toNumber()
|
||||
: null,
|
||||
hurdleRate: params.hurdleRate
|
||||
? new BN(params.hurdleRate)
|
||||
.mul(PERCENTAGE_PRECISION)
|
||||
.div(new BN(100))
|
||||
.toNumber()
|
||||
: null,
|
||||
permissioned: params.permissioned ?? vaultDetails.permissioned,
|
||||
});
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return tx;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to update Drift vault: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const validateAndEncodeAddress = (input: string, programId: string) => {
|
||||
try {
|
||||
return new PublicKey(input);
|
||||
} catch {
|
||||
return getVaultAddressSync(new PublicKey(programId), encodeName(input));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get information on a particular vault given its name
|
||||
* @param agent
|
||||
* @param vaultNameOrAddress
|
||||
* @returns
|
||||
*/
|
||||
export async function getVaultInfo(
|
||||
agent: SolanaAgentKit,
|
||||
vaultNameOrAddress: string,
|
||||
) {
|
||||
try {
|
||||
const { vaultClient, cleanUp } = await initClients(agent);
|
||||
const vaultPublicKey = validateAndEncodeAddress(
|
||||
vaultNameOrAddress,
|
||||
vaultClient.program.programId.toBase58(),
|
||||
);
|
||||
const [vaultDetails, vaultBalance] = await Promise.all([
|
||||
vaultClient.getVault(vaultPublicKey),
|
||||
getVaultAvailableBalance(agent, vaultPublicKey.toBase58()),
|
||||
]);
|
||||
|
||||
await cleanUp();
|
||||
|
||||
const spotToken = MainnetSpotMarkets[vaultDetails.spotMarketIndex];
|
||||
const data = {
|
||||
name: decodeName(vaultDetails.name),
|
||||
delegate: vaultDetails.delegate.toBase58(),
|
||||
address: vaultPublicKey.toBase58(),
|
||||
marketName: `${spotToken.symbol}-SPOT`,
|
||||
balance: `${vaultBalance} ${spotToken.symbol}`,
|
||||
redeemPeriod: vaultDetails.redeemPeriod.toNumber(),
|
||||
maxTokens: vaultDetails.maxTokens.div(spotToken.precision).toNumber(),
|
||||
minDepositAmount: vaultDetails.minDepositAmount
|
||||
.div(spotToken.precision)
|
||||
.toNumber(),
|
||||
managementFee:
|
||||
(vaultDetails.managementFee.toNumber() /
|
||||
PERCENTAGE_PRECISION.toNumber()) *
|
||||
100,
|
||||
profitShare:
|
||||
(vaultDetails.profitShare / PERCENTAGE_PRECISION.toNumber()) * 100,
|
||||
hurdleRate:
|
||||
(vaultDetails.hurdleRate / PERCENTAGE_PRECISION.toNumber()) * 100,
|
||||
permissioned: vaultDetails.permissioned,
|
||||
};
|
||||
|
||||
return data;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to get vault info: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Deposit tokens into a vault
|
||||
@param agent SolanaAgentKit instance
|
||||
@param amount Amount to deposit into the vault (in tokens)
|
||||
@param vault Vault address
|
||||
@returns Promise<anchor.Web3.TransactionSignature> - The transaction signature of the deposit
|
||||
*/
|
||||
export async function depositIntoVault(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
vault: string,
|
||||
) {
|
||||
const { vaultClient, driftClient, cleanUp } = await initClients(agent);
|
||||
|
||||
try {
|
||||
const vaultPublicKey = new PublicKey(vault);
|
||||
const [isOwned, vaultDetails, vaultDepositor] = await Promise.all([
|
||||
getIsOwned(agent, vault),
|
||||
vaultClient.getVault(vaultPublicKey),
|
||||
getOrCreateVaultDepositor(agent, vault),
|
||||
]);
|
||||
const spotMarket = driftClient.getSpotMarketAccount(
|
||||
vaultDetails.spotMarketIndex,
|
||||
);
|
||||
|
||||
if (!spotMarket) {
|
||||
throw new Error(
|
||||
"Market not found. This vaults market is no longer supported",
|
||||
);
|
||||
}
|
||||
|
||||
const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
|
||||
const amountBN = numberToSafeBN(amount, spotPrecision);
|
||||
|
||||
if (isOwned) {
|
||||
return await vaultClient.managerDeposit(vaultPublicKey, amountBN);
|
||||
}
|
||||
|
||||
const tx = await vaultClient.deposit(vaultDepositor, amountBN);
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return tx;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to deposit into Drift vault: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Request a withdrawal from a vault. If successful redemption period starts and the user can redeem the tokens after the period ends
|
||||
@param agent SolanaAgentKit instance
|
||||
@param amount Amount to withdraw from the vault (in shares)
|
||||
@param vault Vault address
|
||||
*/
|
||||
export async function requestWithdrawalFromVault(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
vault: string,
|
||||
) {
|
||||
try {
|
||||
const { vaultClient, cleanUp } = await initClients(agent);
|
||||
const vaultPublicKey = new PublicKey(vault);
|
||||
const isOwned = await getIsOwned(agent, vault);
|
||||
|
||||
if (isOwned) {
|
||||
return await vaultClient.managerRequestWithdraw(
|
||||
vaultPublicKey,
|
||||
numberToSafeBN(amount, QUOTE_PRECISION),
|
||||
WithdrawUnit.TOKEN,
|
||||
);
|
||||
}
|
||||
|
||||
const vaultDepositor = await getOrCreateVaultDepositor(agent, vault);
|
||||
|
||||
const tx = await vaultClient.requestWithdraw(
|
||||
vaultDepositor,
|
||||
numberToSafeBN(amount, QUOTE_PRECISION),
|
||||
WithdrawUnit.TOKEN,
|
||||
);
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return tx;
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
// @ts-expect-error - error message is a string
|
||||
`Failed to request withdrawal from Drift vault: ${e.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Withdraw tokens once the redemption period has elapsed.
|
||||
@param agent SolanaAgentKit instance
|
||||
@param vault Vault address
|
||||
@returns Promise<anchor.Web3.TransactionSignature> - The transaction signature of the redemption
|
||||
*/
|
||||
export async function withdrawFromDriftVault(
|
||||
agent: SolanaAgentKit,
|
||||
vault: string,
|
||||
) {
|
||||
try {
|
||||
const { vaultClient, cleanUp } = await initClients(agent);
|
||||
const vaultPublicKey = new PublicKey(vault);
|
||||
const isOwned = await getIsOwned(agent, vault);
|
||||
|
||||
if (isOwned) {
|
||||
return await vaultClient.managerWithdraw(vaultPublicKey);
|
||||
}
|
||||
|
||||
const vaultDepositor = await getOrCreateVaultDepositor(agent, vault);
|
||||
|
||||
const tx = await vaultClient.withdraw(vaultDepositor);
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return tx;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to redeem tokens from Drift vault: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get if vault is owned by the user
|
||||
@param agent SolanaAgentKit instance
|
||||
@param vault Vault address
|
||||
@returns Promise<boolean> - Whether the vault is owned by the user
|
||||
*/
|
||||
async function getIsOwned(agent: SolanaAgentKit, vault: string) {
|
||||
try {
|
||||
const { vaultClient, cleanUp } = await initClients(agent);
|
||||
const vaultPublicKey = new PublicKey(vault);
|
||||
const vaultDetails = await vaultClient.getVault(vaultPublicKey);
|
||||
const isOwned = vaultDetails.manager.equals(agent.wallet.publicKey);
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return isOwned;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to check if vault is owned: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a vaults address using the vault's name
|
||||
* @param agent
|
||||
* @param name
|
||||
*/
|
||||
export async function getVaultAddress(agent: SolanaAgentKit, name: string) {
|
||||
const encodedName = encodeName(name);
|
||||
|
||||
try {
|
||||
const { vaultClient, cleanUp } = await initClients(agent);
|
||||
const vaultAddress = getVaultAddressSync(
|
||||
vaultClient.program.programId,
|
||||
encodedName,
|
||||
);
|
||||
|
||||
await cleanUp();
|
||||
return vaultAddress;
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
// @ts-expect-error - error message is a string
|
||||
`Failed to get vault address: ${e.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Carry out a trade with a delegated vault
|
||||
@param agent SolanaAgentKit instance
|
||||
@param amount Amount to trade (in tokens)
|
||||
@param symbol Symbol of the token to trade
|
||||
@param action Action to take (e.g. "buy" or "sell")
|
||||
@param type Type of trade (e.g. "market" or "limit")
|
||||
@param vault Vault address
|
||||
*/
|
||||
export async function tradeDriftVault(
|
||||
agent: SolanaAgentKit,
|
||||
vault: string,
|
||||
amount: number,
|
||||
symbol: string,
|
||||
action: "long" | "short",
|
||||
type: "market" | "limit",
|
||||
price?: number,
|
||||
) {
|
||||
try {
|
||||
const { driftClient, cleanUp } = await initClients(agent, {
|
||||
authority: new PublicKey(vault),
|
||||
activeSubAccountId: 0,
|
||||
subAccountIds: [0],
|
||||
});
|
||||
const [isOwned, driftLookupTableAccount] = await Promise.all([
|
||||
getIsOwned(agent, vault),
|
||||
driftClient.fetchMarketLookupTableAccount(),
|
||||
]);
|
||||
|
||||
if (!isOwned) {
|
||||
throw new Error(
|
||||
"This vault is owned/delegated to someone else, you can't trade with it",
|
||||
);
|
||||
}
|
||||
|
||||
const usdcSpotMarket = driftClient.getSpotMarketAccount(0);
|
||||
if (!usdcSpotMarket) {
|
||||
throw new Error("USDC-SPOT market not found");
|
||||
}
|
||||
|
||||
const perpMarketIndexAndType = getMarketIndexAndType(
|
||||
`${symbol.toUpperCase()}-PERP`,
|
||||
);
|
||||
const perpMarketAccount = driftClient.getPerpMarketAccount(
|
||||
perpMarketIndexAndType.marketIndex,
|
||||
);
|
||||
|
||||
if (!perpMarketIndexAndType || !perpMarketAccount) {
|
||||
throw new Error(
|
||||
"Invalid symbol: Drift doesn't have a market for this token",
|
||||
);
|
||||
}
|
||||
|
||||
const perpOracle = driftClient.getOracleDataForPerpMarket(
|
||||
perpMarketAccount.marketIndex,
|
||||
);
|
||||
const oraclePriceNumber = convertToNumber(
|
||||
perpOracle.price,
|
||||
PRICE_PRECISION,
|
||||
);
|
||||
const baseAmount = amount / oraclePriceNumber;
|
||||
const instructions: TransactionInstruction[] = [];
|
||||
|
||||
instructions.push(
|
||||
ComputeBudgetProgram.setComputeUnitLimit({ units: 1400000 }),
|
||||
);
|
||||
|
||||
if (type === "limit" || price) {
|
||||
if (!price) {
|
||||
throw new Error("Price is required for limit orders");
|
||||
}
|
||||
|
||||
const instruction = await driftClient.getPlaceOrdersIx([
|
||||
getOrderParams(
|
||||
getLimitOrderParams({
|
||||
price: numberToSafeBN(price, PRICE_PRECISION),
|
||||
marketType: MarketType.PERP,
|
||||
baseAssetAmount: numberToSafeBN(baseAmount, BASE_PRECISION),
|
||||
direction:
|
||||
action === "long"
|
||||
? PositionDirection.LONG
|
||||
: PositionDirection.SHORT,
|
||||
marketIndex: perpMarketAccount.marketIndex,
|
||||
postOnly: PostOnlyParams.SLIDE,
|
||||
}),
|
||||
),
|
||||
]);
|
||||
|
||||
instructions.push(instruction);
|
||||
} else {
|
||||
// defaults to market order if type is not limit and price is not provided
|
||||
const instruction = await driftClient.getPlaceOrdersIx([
|
||||
getOrderParams(
|
||||
getMarketOrderParams({
|
||||
marketType: MarketType.PERP,
|
||||
baseAssetAmount: numberToSafeBN(baseAmount, BASE_PRECISION),
|
||||
direction:
|
||||
action === "long"
|
||||
? PositionDirection.LONG
|
||||
: PositionDirection.SHORT,
|
||||
marketIndex: perpMarketAccount.marketIndex,
|
||||
}),
|
||||
),
|
||||
]);
|
||||
instructions.push(instruction);
|
||||
}
|
||||
|
||||
const latestBlockhash = await driftClient.connection.getLatestBlockhash();
|
||||
const tx = await driftClient.txSender.sendVersionedTransaction(
|
||||
await driftClient.txSender.getVersionedTransaction(
|
||||
instructions,
|
||||
[driftLookupTableAccount],
|
||||
[],
|
||||
driftClient.opts,
|
||||
latestBlockhash,
|
||||
),
|
||||
);
|
||||
|
||||
await cleanUp();
|
||||
|
||||
return tx;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to trade with Drift vault: ${e.message}`);
|
||||
}
|
||||
}
|
||||
2
src/tools/drift/index.ts
Normal file
2
src/tools/drift/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./drift";
|
||||
export * from "./drift_vault";
|
||||
33
src/tools/drift/types.ts
Normal file
33
src/tools/drift/types.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { L2OrderBook, MarketType, OraclePriceData } from "@drift-labs/sdk";
|
||||
|
||||
export type L2WithOracle = L2OrderBook & { oracleData: OraclePriceData };
|
||||
|
||||
export type RawL2Output = {
|
||||
marketIndex: number;
|
||||
marketType: MarketType;
|
||||
marketName: string;
|
||||
asks: {
|
||||
price: string;
|
||||
size: string;
|
||||
sources: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}[];
|
||||
bids: {
|
||||
price: string;
|
||||
size: string;
|
||||
sources: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}[];
|
||||
oracleData: {
|
||||
price: string;
|
||||
slot: string;
|
||||
confidence: string;
|
||||
hasSufficientNumberOfDataPoints: boolean;
|
||||
twap?: string;
|
||||
twapConfidence?: string;
|
||||
maxPrice?: string;
|
||||
};
|
||||
slot?: number;
|
||||
};
|
||||
@@ -16,6 +16,7 @@ export * from "./pumpfun";
|
||||
export * from "./pyth";
|
||||
export * from "./raydium";
|
||||
export * from "./rugcheck";
|
||||
export * from "./drift";
|
||||
export * from "./sendarcade";
|
||||
export * from "./solayer";
|
||||
export * from "./tensor";
|
||||
@@ -25,3 +26,4 @@ export * from "./lightprotocol";
|
||||
export * from "./squads";
|
||||
export * from "./meteora";
|
||||
export * from "./helius";
|
||||
export * from "./voltr";
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from "./lend";
|
||||
export * from "./lulo_lend";
|
||||
export * from "./lulo_withdraw";
|
||||
|
||||
66
src/tools/lulo/lulo_lend.ts
Normal file
66
src/tools/lulo/lulo_lend.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { VersionedTransaction } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
|
||||
/**
|
||||
* Lend tokens for yields using Lulo
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param mintAddress SPL Mint address
|
||||
* @param amount Amount to lend
|
||||
* @returns Transaction signature
|
||||
*/
|
||||
export async function luloLend(
|
||||
agent: SolanaAgentKit,
|
||||
mintAddress: string,
|
||||
amount: number,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://api.flexlend.fi/generate/account/deposit?priorityFee=50000`,
|
||||
{
|
||||
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.toString(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
const {
|
||||
data: { transactionMeta },
|
||||
} = await response.json();
|
||||
|
||||
// Deserialize the transaction
|
||||
const luloTxn = VersionedTransaction.deserialize(
|
||||
Buffer.from(transactionMeta[0].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(`Lending failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
71
src/tools/lulo/lulo_withdraw.ts
Normal file
71
src/tools/lulo/lulo_withdraw.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { VersionedTransaction } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
|
||||
/**
|
||||
* Withdraw tokens for yields using Lulo
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param mintAddress SPL Mint address
|
||||
* @param amount Amount to withdraw
|
||||
* @returns Transaction signature
|
||||
*/
|
||||
export async function luloWithdraw(
|
||||
agent: SolanaAgentKit,
|
||||
mintAddress: string,
|
||||
amount: number,
|
||||
): Promise<string> {
|
||||
try {
|
||||
if (!agent.config.FLEXLEND_API_KEY) {
|
||||
throw new Error("Lulo API key not found in agent configuration");
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`https://api.flexlend.fi/generate/account/withdraw?priorityFee=50000`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-wallet-pubkey": agent.wallet.publicKey.toBase58(),
|
||||
"x-api-key": agent.config.FLEXLEND_API_KEY,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
owner: agent.wallet.publicKey.toBase58(),
|
||||
mintAddress: mintAddress,
|
||||
depositAmount: amount,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const {
|
||||
data: { transactionMeta },
|
||||
} = await response.json();
|
||||
|
||||
// Deserialize the transaction
|
||||
const luloTxn = VersionedTransaction.deserialize(
|
||||
Buffer.from(transactionMeta[0].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(`Lending failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
59
src/tools/solana/get_token_balances.ts
Normal file
59
src/tools/solana/get_token_balances.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { LAMPORTS_PER_SOL, type PublicKey } from "@solana/web3.js";
|
||||
import type { SolanaAgentKit } from "../../index";
|
||||
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { getTokenMetadata } from "../../utils/tokenMetadata";
|
||||
|
||||
/**
|
||||
* Get the token balances of a Solana wallet
|
||||
* @param agent - SolanaAgentKit instance
|
||||
* @param token_address - Optional SPL token mint address. If not provided, returns SOL balance
|
||||
* @returns Promise resolving to the balance as an object containing sol balance and token balances with their respective mints, symbols, names and decimals
|
||||
*/
|
||||
export async function get_token_balance(
|
||||
agent: SolanaAgentKit,
|
||||
walletAddress?: PublicKey,
|
||||
): Promise<{
|
||||
sol: number;
|
||||
tokens: Array<{
|
||||
tokenAddress: string;
|
||||
name: string;
|
||||
symbol: string;
|
||||
balance: number;
|
||||
decimals: number;
|
||||
}>;
|
||||
}> {
|
||||
const [lamportsBalance, tokenAccountData] = await Promise.all([
|
||||
agent.connection.getBalance(walletAddress ?? agent.wallet_address),
|
||||
agent.connection.getParsedTokenAccountsByOwner(
|
||||
walletAddress ?? agent.wallet_address,
|
||||
{
|
||||
programId: TOKEN_PROGRAM_ID,
|
||||
},
|
||||
),
|
||||
]);
|
||||
|
||||
const removedZeroBalance = tokenAccountData.value.filter(
|
||||
(v) => v.account.data.parsed.info.tokenAmount.uiAmount !== 0,
|
||||
);
|
||||
|
||||
const tokenBalances = await Promise.all(
|
||||
removedZeroBalance.map(async (v) => {
|
||||
const mint = v.account.data.parsed.info.mint;
|
||||
const mintInfo = await getTokenMetadata(agent.connection, mint);
|
||||
return {
|
||||
tokenAddress: mint,
|
||||
name: mintInfo.name ?? "",
|
||||
symbol: mintInfo.symbol ?? "",
|
||||
balance: v.account.data.parsed.info.tokenAmount.uiAmount as number,
|
||||
decimals: v.account.data.parsed.info.tokenAmount.decimals as number,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const solBalance = lamportsBalance / LAMPORTS_PER_SOL;
|
||||
|
||||
return {
|
||||
sol: solBalance,
|
||||
tokens: tokenBalances,
|
||||
};
|
||||
}
|
||||
@@ -4,3 +4,4 @@ export * from "./close_empty_token_accounts";
|
||||
export * from "./transfer";
|
||||
export * from "./get_balance";
|
||||
export * from "./get_balance_other";
|
||||
export * from "./get_token_balances";
|
||||
|
||||
3
src/tools/voltr/index.ts
Normal file
3
src/tools/voltr/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./voltr_deposit_strategy";
|
||||
export * from "./voltr_withdraw_strategy";
|
||||
export * from "./voltr_get_position_values";
|
||||
99
src/tools/voltr/voltr_deposit_strategy.ts
Normal file
99
src/tools/voltr/voltr_deposit_strategy.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import {
|
||||
PublicKey,
|
||||
sendAndConfirmTransaction,
|
||||
Transaction,
|
||||
} from "@solana/web3.js";
|
||||
import { VoltrClient } from "@voltr/vault-sdk";
|
||||
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 vaultAccount = await vc.fetchVaultAccount(vault);
|
||||
const vaultAssetMint = vaultAccount.asset.mint;
|
||||
const assetTokenProgram = await agent.connection
|
||||
.getAccountInfo(new PublicKey(vaultAssetMint))
|
||||
.then((account) => account?.owner);
|
||||
|
||||
if (
|
||||
!assetTokenProgram ||
|
||||
!(
|
||||
assetTokenProgram.equals(TOKEN_PROGRAM_ID) ||
|
||||
assetTokenProgram.equals(TOKEN_2022_PROGRAM_ID)
|
||||
)
|
||||
) {
|
||||
throw new Error("Invalid asset token program");
|
||||
}
|
||||
|
||||
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 {
|
||||
instructionDiscriminator: number[] | null;
|
||||
additionalArgs: number[] | null;
|
||||
remainingAccounts:
|
||||
| {
|
||||
pubkey: string;
|
||||
isSigner: boolean;
|
||||
isWritable: boolean;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
|
||||
const additionalArgs = data.additionalArgs
|
||||
? Buffer.from(data.additionalArgs)
|
||||
: null;
|
||||
const instructionDiscriminator = data.instructionDiscriminator
|
||||
? Buffer.from(data.instructionDiscriminator)
|
||||
: null;
|
||||
const remainingAccounts =
|
||||
data.remainingAccounts?.map((account) => ({
|
||||
pubkey: new PublicKey(account.pubkey),
|
||||
isSigner: account.isSigner,
|
||||
isWritable: account.isWritable,
|
||||
})) ?? [];
|
||||
|
||||
const depositIx = await vc.createDepositStrategyIx(
|
||||
{
|
||||
depositAmount,
|
||||
additionalArgs,
|
||||
instructionDiscriminator,
|
||||
},
|
||||
{
|
||||
vault,
|
||||
vaultAssetMint,
|
||||
strategy: strategy,
|
||||
assetTokenProgram,
|
||||
remainingAccounts,
|
||||
},
|
||||
);
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(depositIx);
|
||||
|
||||
const txSig = await sendAndConfirmTransaction(agent.connection, transaction, [
|
||||
agent.wallet,
|
||||
]);
|
||||
return txSig;
|
||||
}
|
||||
20
src/tools/voltr/voltr_get_position_values.ts
Normal file
20
src/tools/voltr/voltr_get_position_values.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { VoltrClient } from "@voltr/vault-sdk";
|
||||
|
||||
/**
|
||||
* Gets the value of assets in a Voltr vault
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param vault Public key of the target vault
|
||||
* @returns Position and total values for the vault
|
||||
*/
|
||||
export async function voltrGetPositionValues(
|
||||
agent: SolanaAgentKit,
|
||||
vault: PublicKey,
|
||||
): Promise<string> {
|
||||
const vc = new VoltrClient(agent.connection, agent.wallet);
|
||||
const positionAndTotalValues =
|
||||
await vc.getPositionAndTotalValuesForVault(vault);
|
||||
|
||||
return JSON.stringify(positionAndTotalValues);
|
||||
}
|
||||
99
src/tools/voltr/voltr_withdraw_strategy.ts
Normal file
99
src/tools/voltr/voltr_withdraw_strategy.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import {
|
||||
PublicKey,
|
||||
sendAndConfirmTransaction,
|
||||
Transaction,
|
||||
} from "@solana/web3.js";
|
||||
import BN from "bn.js";
|
||||
import { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { VoltrClient } from "@voltr/vault-sdk";
|
||||
|
||||
/**
|
||||
* 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 vaultAccount = await vc.fetchVaultAccount(vault);
|
||||
const vaultAssetMint = vaultAccount.asset.mint;
|
||||
const assetTokenProgram = await agent.connection
|
||||
.getAccountInfo(new PublicKey(vaultAssetMint))
|
||||
.then((account) => account?.owner);
|
||||
|
||||
if (
|
||||
!assetTokenProgram ||
|
||||
!(
|
||||
assetTokenProgram.equals(TOKEN_PROGRAM_ID) ||
|
||||
assetTokenProgram.equals(TOKEN_2022_PROGRAM_ID)
|
||||
)
|
||||
) {
|
||||
throw new Error("Invalid asset token program");
|
||||
}
|
||||
|
||||
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 {
|
||||
instructionDiscriminator: number[] | null;
|
||||
additionalArgs: number[] | null;
|
||||
remainingAccounts:
|
||||
| {
|
||||
pubkey: string;
|
||||
isSigner: boolean;
|
||||
isWritable: boolean;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
|
||||
const additionalArgs = data.additionalArgs
|
||||
? Buffer.from(data.additionalArgs)
|
||||
: null;
|
||||
const instructionDiscriminator = data.instructionDiscriminator
|
||||
? Buffer.from(data.instructionDiscriminator)
|
||||
: null;
|
||||
const remainingAccounts =
|
||||
data.remainingAccounts?.map((account) => ({
|
||||
pubkey: new PublicKey(account.pubkey),
|
||||
isSigner: account.isSigner,
|
||||
isWritable: account.isWritable,
|
||||
})) ?? [];
|
||||
|
||||
const withdrawIx = await vc.createWithdrawStrategyIx(
|
||||
{
|
||||
withdrawAmount,
|
||||
additionalArgs,
|
||||
instructionDiscriminator,
|
||||
},
|
||||
{
|
||||
vault,
|
||||
vaultAssetMint,
|
||||
strategy,
|
||||
assetTokenProgram,
|
||||
remainingAccounts,
|
||||
},
|
||||
);
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(withdrawIx);
|
||||
|
||||
const txSig = await sendAndConfirmTransaction(agent.connection, transaction, [
|
||||
agent.wallet,
|
||||
]);
|
||||
return txSig;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ export interface Config {
|
||||
JUPITER_REFERRAL_ACCOUNT?: string;
|
||||
JUPITER_FEE_BPS?: number;
|
||||
FLASH_PRIVILEGE?: string;
|
||||
FLEXLEND_API_KEY?: string;
|
||||
HELIUS_API_KEY?: string;
|
||||
}
|
||||
|
||||
|
||||
83
src/utils/tokenMetadata.ts
Normal file
83
src/utils/tokenMetadata.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
|
||||
export async function getTokenMetadata(
|
||||
connection: Connection,
|
||||
tokenMint: string,
|
||||
) {
|
||||
const METADATA_PROGRAM_ID = new PublicKey(
|
||||
"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
|
||||
);
|
||||
|
||||
const [metadataPDA] = PublicKey.findProgramAddressSync(
|
||||
[
|
||||
Buffer.from("metadata"),
|
||||
METADATA_PROGRAM_ID.toBuffer(),
|
||||
new PublicKey(tokenMint).toBuffer(),
|
||||
],
|
||||
METADATA_PROGRAM_ID,
|
||||
);
|
||||
|
||||
const metadata = await connection.getAccountInfo(metadataPDA);
|
||||
if (!metadata?.data) {
|
||||
throw new Error("Metadata not found");
|
||||
}
|
||||
|
||||
let offset = 1 + 32 + 32; // key + update auth + mint
|
||||
const data = metadata.data;
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
// Read variable length strings
|
||||
const readString = () => {
|
||||
let nameLength = data[offset];
|
||||
|
||||
while (nameLength === 0) {
|
||||
offset++;
|
||||
nameLength = data[offset];
|
||||
if (offset >= data.length) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
offset++;
|
||||
const name = decoder
|
||||
.decode(data.slice(offset, offset + nameLength))
|
||||
// @eslint-disable-next-line no-control-regex
|
||||
.replace(new RegExp(String.fromCharCode(0), "g"), "");
|
||||
offset += nameLength;
|
||||
return name;
|
||||
};
|
||||
|
||||
const name = readString();
|
||||
const symbol = readString();
|
||||
const uri = readString();
|
||||
|
||||
// Read remaining data
|
||||
const sellerFeeBasisPoints = data.readUInt16LE(offset);
|
||||
offset += 2;
|
||||
|
||||
let creators:
|
||||
| { address: PublicKey; verified: boolean; share: number }[]
|
||||
| null = null;
|
||||
if (data[offset] === 1) {
|
||||
offset++;
|
||||
const numCreators = data[offset];
|
||||
offset++;
|
||||
creators = [...Array(numCreators)].map(() => {
|
||||
const creator = {
|
||||
address: new PublicKey(data.slice(offset, offset + 32)),
|
||||
verified: data[offset + 32] === 1,
|
||||
share: data[offset + 33],
|
||||
};
|
||||
offset += 34;
|
||||
return creator;
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
symbol,
|
||||
uri,
|
||||
sellerFeeBasisPoints,
|
||||
creators,
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,15 @@ export function createSolanaTools(
|
||||
tools[key] = tool({
|
||||
// @ts-expect-error Value matches type however TS still shows error
|
||||
id: action.name,
|
||||
description: action.description,
|
||||
description: `
|
||||
${action.description}
|
||||
|
||||
Similes: ${action.similes.map(
|
||||
(simile) => `
|
||||
${simile}
|
||||
`,
|
||||
)}
|
||||
`.slice(0, 1023),
|
||||
parameters: action.schema,
|
||||
execute: async (params) =>
|
||||
await executeAction(action, solanaAgentKit, params),
|
||||
|
||||
Reference in New Issue
Block a user