mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-22 23:26:45 +00:00
Merge branch 'main' into deposit_and_withdraw_with_lulo
This commit is contained in:
59
src/actions/drift/createDriftUserAccount.ts
Normal file
59
src/actions/drift/createDriftUserAccount.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
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"),
|
||||
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;
|
||||
108
src/actions/drift/createVault.ts
Normal file
108
src/actions/drift/createVault.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
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",
|
||||
),
|
||||
minDepositAmount: z.number().positive().describe("Minimum deposit amount"),
|
||||
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;
|
||||
56
src/actions/drift/depositIntoVault.ts
Normal file
56
src/actions/drift/depositIntoVault.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
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"),
|
||||
}),
|
||||
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",
|
||||
),
|
||||
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;
|
||||
57
src/actions/drift/requestWithdrawalFromVault.ts
Normal file
57
src/actions/drift/requestWithdrawalFromVault.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
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"),
|
||||
}),
|
||||
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;
|
||||
114
src/actions/drift/tradeDelegatedDriftVault.ts
Normal file
114
src/actions/drift/tradeDelegatedDriftVault.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
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"),
|
||||
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("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;
|
||||
82
src/actions/drift/tradePerpAccount.ts
Normal file
82
src/actions/drift/tradePerpAccount.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
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(),
|
||||
symbol: z
|
||||
.string()
|
||||
.toUpperCase()
|
||||
.describe("Symbol of the token to open a position on "),
|
||||
action: z.enum(["long", "short"]),
|
||||
type: z.enum(["market", "limit"]),
|
||||
price: z.number().positive().optional(),
|
||||
}),
|
||||
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;
|
||||
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(),
|
||||
newDelegate: z.string(),
|
||||
}),
|
||||
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;
|
||||
87
src/actions/drift/updateVault.ts
Normal file
87
src/actions/drift/updateVault.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
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")
|
||||
.optional(),
|
||||
maxTokens: z
|
||||
.number()
|
||||
.int()
|
||||
.min(100, "Max tokens must be at least 100")
|
||||
.optional(),
|
||||
minDepositAmount: z.number().positive().optional(),
|
||||
managementFee: z.number().positive().max(20).optional(),
|
||||
profitShare: z.number().positive().max(90).optional(),
|
||||
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",
|
||||
),
|
||||
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(),
|
||||
}),
|
||||
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;
|
||||
57
src/actions/helius/createWebhook.ts
Normal file
57
src/actions/helius/createWebhook.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { create_HeliusWebhook } from "../../tools/helius";
|
||||
|
||||
const createWebhookAction: Action = {
|
||||
name: "CREATE_HELIOUS_WEBHOOK",
|
||||
similes: ["setup webhook", "register webhook", "initiate webhook"],
|
||||
description:
|
||||
"Creates a new webhook in the Helius system to monitor transactions for specified account addresses",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
accountAddresses: [
|
||||
"BVdNLvyG2DNiWAXBE9qAmc4MTQXymd5Bzfo9xrQSUzVP",
|
||||
"Eo2ciguhMLmcTWXELuEQPdu7DWZt67LHXb2rdHZUbot7",
|
||||
],
|
||||
webhookURL: "https://yourdomain.com/webhook",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
webhookURL: "https://yourdomain.com/webhook",
|
||||
webhookID: "webhook_123",
|
||||
message: "Webhook created successfully.",
|
||||
},
|
||||
explanation:
|
||||
"Creates a Webhook to send live notifications on the given Url with the wallet Addresses.",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
accountAddresses: z
|
||||
.array(z.string())
|
||||
.min(1)
|
||||
.describe("List of Solana account public keys to monitor"),
|
||||
webhookURL: z
|
||||
.string()
|
||||
.url()
|
||||
.describe("The URL where Helius will send webhook notifications"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const response = await create_HeliusWebhook(
|
||||
agent,
|
||||
input.accountAddresses,
|
||||
input.webhookURL,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
...response,
|
||||
message: "Webhook created successfully.",
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default createWebhookAction;
|
||||
40
src/actions/helius/deleteWebhook.ts
Normal file
40
src/actions/helius/deleteWebhook.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { deleteHeliusWebhook } from "../../tools/helius";
|
||||
|
||||
const deleteWebhookAction: Action = {
|
||||
name: "DELETE_HELIOUS_WEBHOOK",
|
||||
similes: ["remove webhook", "unregister webhook", "delete webhook"],
|
||||
description: "Deletes a Helius webhook by its unique ID",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
webhookID: "webhook_123",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Webhook deleted successfully.",
|
||||
},
|
||||
explanation: "Permanently removes a Helius webhook.",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
webhookID: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("The unique identifier of the Helius webhook to delete"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const result = await deleteHeliusWebhook(agent, input.webhookID);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: result.message || "Webhook deleted successfully.",
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default deleteWebhookAction;
|
||||
75
src/actions/helius/getAssetsbyOwner.ts
Normal file
75
src/actions/helius/getAssetsbyOwner.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { getAssetsByOwner } from "../../tools/helius";
|
||||
|
||||
const getAssetsByOwnerAction: Action = {
|
||||
name: "FETCH_ASSETS_BY_OWNER",
|
||||
similes: [
|
||||
"fetch assets",
|
||||
"get assets",
|
||||
"retrieve assets",
|
||||
"list assets",
|
||||
"assets by owner",
|
||||
],
|
||||
description:
|
||||
"Fetch assets owned by a specific Solana wallet address using the Helius Digital Asset Standard API",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
ownerPublicKey: "4Pf8q3mHGLdkoc1M8xWZwW5q32gYmdhwC2gJ8K9EAGDX",
|
||||
limit: 10,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
assets: [
|
||||
{
|
||||
name: "Helius NFT #1",
|
||||
type: "NFT",
|
||||
owner: "4Pf8q3mHGLdkoc1M8xWZwW5q32gYmdhwC2gJ8K9EAGDX",
|
||||
},
|
||||
{
|
||||
name: "Helius Token #10",
|
||||
type: "Token",
|
||||
owner: "4Pf8q3mHGLdkoc1M8xWZwW5q32gYmdhwC2gJ8K9EAGDX",
|
||||
},
|
||||
],
|
||||
message: "Successfully fetched assets for the wallet address",
|
||||
},
|
||||
explanation:
|
||||
"Fetches a list of assets from the for the given wallet address with a limit of 10 items.",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
ownerPublicKey: z.string().describe("Owner's Solana wallet PublicKey"),
|
||||
limit: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe("Number of assets to retrieve per request"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const assets = await getAssetsByOwner(
|
||||
agent,
|
||||
new PublicKey(input.ownerPublicKey),
|
||||
input.limit,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
assets: assets,
|
||||
message: `Successfully fetched assets for the wallet address: ${input.ownerPublicKey}`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to fetch assets: ${error.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default getAssetsByOwnerAction;
|
||||
47
src/actions/helius/getWebhook.ts
Normal file
47
src/actions/helius/getWebhook.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { getHeliusWebhook } from "../../tools/helius";
|
||||
|
||||
const getWebhookAction: Action = {
|
||||
name: "GET_HELIOUS_WEBHOOK",
|
||||
similes: ["fetch webhook details", "retrieve webhook", "get webhook info"],
|
||||
description: "Retrieves details of a Helius webhook by its unique ID",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
webhookID: "webhook_123",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
wallet: "WalletPublicKey",
|
||||
webhookURL: "https://yourdomain.com/webhook",
|
||||
transactionTypes: ["Any"],
|
||||
accountAddresses: ["SomePublicKey", "AnotherPublicKey"],
|
||||
webhookType: "enhanced",
|
||||
message: "Webhook details retrieved successfully.",
|
||||
},
|
||||
explanation:
|
||||
"Retrieves detailed information about an existing Helius webhook, including the wallet address it monitors, the types of transactions it tracks, and the specific webhook URL.",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
webhookID: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("The unique identifier of the Helius webhook to retrieve"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const webhookDetails = await getHeliusWebhook(agent, input.webhookID);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
...webhookDetails,
|
||||
message: "Webhook details retrieved successfully.",
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default getWebhookAction;
|
||||
65
src/actions/helius/parseTransaction.ts
Normal file
65
src/actions/helius/parseTransaction.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { parseTransaction } from "../../tools/helius";
|
||||
|
||||
const parseSolanaTransactionAction: Action = {
|
||||
name: "PARSE_SOLANA_TRANSACTION",
|
||||
similes: [
|
||||
"parse transaction",
|
||||
"analyze transaction",
|
||||
"inspect transaction",
|
||||
"decode transaction",
|
||||
],
|
||||
description:
|
||||
"Parse a Solana transaction to retrieve detailed information using the Helius Enhanced Transactions API",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
transactionId:
|
||||
"4zZVvbgzcriyjAeEiK1w7CeDCt7gYThUCZat3ULTNerzKHF4WLfRG2YUjbRovfFJ639TAyARB4oyRDcLVUvrakq7",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
transaction: {
|
||||
details: "Transaction details...",
|
||||
involvedAccounts: ["Account1", "Account2"],
|
||||
executedOperations: [{ operation: "Transfer", amount: "1000 SOL" }],
|
||||
},
|
||||
message:
|
||||
"Successfully parsed transaction: 4zZVvbgzcriyjAeEiK1w7CeDCt7gYThUCZat3ULTNerzKHF4WLfRG2YUjbRovfFJ639TAyARB4oyRDcLVUvrakq7",
|
||||
},
|
||||
explanation:
|
||||
"Parse a Transaction to transform it into human readable format.",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
transactionId: z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("The Solana transaction ID to parse"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
try {
|
||||
const parsedTransactionData = await parseTransaction(
|
||||
agent,
|
||||
input.transactionId,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
transaction: parsedTransactionData,
|
||||
message: `Successfully parsed transaction: ${input.transactionId}`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
status: "error",
|
||||
message: `Failed to parse transaction: ${error.message}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default parseSolanaTransactionAction;
|
||||
76
src/actions/helius/sendTransactionWithPriority.ts
Normal file
76
src/actions/helius/sendTransactionWithPriority.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { sendTransactionWithPriorityFee } from "../../tools/helius";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const sendTransactionWithPriorityFeeAction: Action = {
|
||||
name: "SEND_TRANSACTION_WITH_PRIORITY_FEE",
|
||||
similes: [
|
||||
"send SOL with fee",
|
||||
"transfer tokens with priority",
|
||||
"execute priority transaction",
|
||||
],
|
||||
description:
|
||||
"Sends SOL or SPL tokens from a wallet with an estimated priority fee, ensuring faster processing on the Solana network.",
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
priorityLevel: "High",
|
||||
amount: 2,
|
||||
to: "BVdNLvyG2DNiWAXBE9qAmc4MTQXymd5Bzfo9xrQSUzVP",
|
||||
splmintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
transactionId: "5Xgq9xVABhwXpNStWpfqxS6Vm5Eau91pjfeHNwJbRgis",
|
||||
fee: 5000,
|
||||
message: "Transaction sent with priority fee successfully.",
|
||||
},
|
||||
explanation:
|
||||
"Sends 2 USDC to BVdNLvyG2DNiWAXBE9qAmc4MTQXymd5Bzfo9xrQSUzVP with High priority fee option.",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
priorityLevel: z
|
||||
.enum(["Min", "Low", "Medium", "High", "VeryHigh", "UnsafeMax"])
|
||||
.describe("Priority level to determine the urgency of the transaction."),
|
||||
amount: z
|
||||
.number()
|
||||
.positive()
|
||||
.describe("Amount of SOL or SPL tokens to send."),
|
||||
to: z.string().describe("Recipient's PublicKey."),
|
||||
splmintAddress: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional SPL token address, if transferring tokens other than SOL.",
|
||||
),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const { priorityLevel, amount, to, splmintAddress } = input;
|
||||
const toPublicKey = new PublicKey(to);
|
||||
const splmintPublicKey = splmintAddress
|
||||
? new PublicKey(splmintAddress)
|
||||
: undefined;
|
||||
|
||||
const result = await sendTransactionWithPriorityFee(
|
||||
agent,
|
||||
priorityLevel,
|
||||
amount,
|
||||
toPublicKey,
|
||||
splmintPublicKey,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
transactionId: result.transactionId,
|
||||
fee: result.fee,
|
||||
message: "Transaction sent with priority fee successfully.",
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default sendTransactionWithPriorityFeeAction;
|
||||
@@ -1,3 +1,4 @@
|
||||
import tokenBalancesAction from "./tokenBalances";
|
||||
import deployTokenAction from "./metaplex/deployToken";
|
||||
import balanceAction from "./solana/balance";
|
||||
import transferAction from "./solana/transfer";
|
||||
@@ -32,9 +33,41 @@ import launchPumpfunTokenAction from "./pumpfun/launchPumpfunToken";
|
||||
import getWalletAddressAction from "./agent/getWalletAddress";
|
||||
import flashOpenTradeAction from "./flash/flashOpenTrade";
|
||||
import flashCloseTradeAction from "./flash/flashCloseTrade";
|
||||
import createMultisigAction from "./squads/createMultisig";
|
||||
import approveMultisigProposalAction from "./squads/approveMultisigProposal";
|
||||
import createMultisigProposalAction from "./squads/createMultisigProposal";
|
||||
import depositToMultisigAction from "./squads/depositToMultisigTreasury";
|
||||
import executeMultisigProposalAction from "./squads/executeMultisigProposal";
|
||||
import rejectMultisigProposalAction from "./squads/rejectMultisigProposal";
|
||||
import transferFromMultisigAction from "./squads/transferFromMultisigTreasury";
|
||||
import createWebhookAction from "./helius/createWebhook";
|
||||
import deleteWebhookAction from "./helius/deleteWebhook";
|
||||
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 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,
|
||||
@@ -69,6 +102,37 @@ export const ACTIONS = {
|
||||
LAUNCH_PUMPFUN_TOKEN_ACTION: launchPumpfunTokenAction,
|
||||
FLASH_OPEN_TRADE_ACTION: flashOpenTradeAction,
|
||||
FLASH_CLOSE_TRADE_ACTION: flashCloseTradeAction,
|
||||
CREATE_MULTISIG_ACTION: createMultisigAction,
|
||||
DEPOSIT_TO_MULTISIG_ACTION: depositToMultisigAction,
|
||||
TRANSFER_FROM_MULTISIG_ACTION: transferFromMultisigAction,
|
||||
CREATE_MULTISIG_PROPOSAL_ACTION: createMultisigProposalAction,
|
||||
APPROVE_MULTISIG_PROPOSAL_ACTION: approveMultisigProposalAction,
|
||||
REJECT_MULTISIG_PROPOSAL_ACTION: rejectMultisigProposalAction,
|
||||
EXECUTE_MULTISIG_PROPOSAL_ACTION: executeMultisigProposalAction,
|
||||
CREATE_WEBHOOK_ACTION: createWebhookAction,
|
||||
DELETE_WEBHOOK_ACTION: deleteWebhookAction,
|
||||
GET_ASSETS_BY_OWNER_ACTION: getAssetsByOwnerAction,
|
||||
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,
|
||||
GET_VOLTR_POSITION_VALUES_ACTION: getVoltrPositionValuesAction,
|
||||
DEPOSIT_VOLTR_STRATEGY_ACTION: depositVoltrStrategyAction,
|
||||
WITHDRAW_VOLTR_STRATEGY_ACTION: withdrawVoltrStrategyAction,
|
||||
};
|
||||
|
||||
export type { Action, ActionExample, Handler } from "../types/action";
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
50
src/actions/squads/approveMultisigProposal.ts
Normal file
50
src/actions/squads/approveMultisigProposal.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { multisig_approve_proposal } from "../../tools";
|
||||
|
||||
const approveMultisigProposalAction: Action = {
|
||||
name: "APPROVE_MULTISIG_PROPOSAL_ACTION",
|
||||
similes: [
|
||||
"approve proposal",
|
||||
"approve proposal to transfer funds",
|
||||
"approve proposal to transfer funds from 2-of-2 multisig",
|
||||
"approve proposal to transfer funds from 2-of-2 multisig account",
|
||||
"approve proposal to transfer funds from 2-of-2 multisig account on Solana",
|
||||
],
|
||||
description: `Approve a proposal to transfer funds from a 2-of-2 multisig account on Solana with the user and the agent, where both approvals will be required to run the transactions.
|
||||
|
||||
Note: For one AI agent, only one 2-by-2 multisig can be created as it is pair-wise.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
transactionIndex: 0,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Proposal approved successfully",
|
||||
transaction: "4xKpN2...",
|
||||
transactionIndex: "0",
|
||||
},
|
||||
explanation:
|
||||
"Approve a proposal to transfer 1 SOL from 2-of-2 multisig account on Solana",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
transactionIndex: z.number().optional(),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const tx = await multisig_approve_proposal(agent, input.transactionIndex);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Proposal approved successfully",
|
||||
transaction: tx,
|
||||
transactionIndex: input.transactionIndex.toString(),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default approveMultisigProposalAction;
|
||||
52
src/actions/squads/createMultisig.ts
Normal file
52
src/actions/squads/createMultisig.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { create_squads_multisig } from "../../tools";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const createMultisigAction: Action = {
|
||||
name: "CREATE_MULTISIG_ACTION",
|
||||
similes: [
|
||||
"create multisig",
|
||||
"create squads multisig",
|
||||
"create 2-by-2 multisig",
|
||||
"create 2-of-2 multisig",
|
||||
"create 2-of-2 multisig account",
|
||||
"create 2-of-2 multisig account on Solana",
|
||||
],
|
||||
description: `Create a 2-of-2 multisig account on Solana using Squads with the user and the agent, where both approvals will be required to run the transactions.
|
||||
|
||||
Note: For one AI agent, only one 2-by-2 multisig can be created as it is pair-wise.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
creator: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "2-by-2 multisig account created successfully",
|
||||
signature: "4xKpN2...",
|
||||
},
|
||||
explanation: "Create a 2-of-2 multisig account on Solana",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
creator: z.string(),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const multisig = await create_squads_multisig(
|
||||
agent,
|
||||
new PublicKey(input.creator as string),
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "2-by-2 multisig account created successfully",
|
||||
signature: multisig,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default createMultisigAction;
|
||||
55
src/actions/squads/createMultisigProposal.ts
Normal file
55
src/actions/squads/createMultisigProposal.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { multisig_create_proposal } from "../../tools";
|
||||
|
||||
const createMultisigProposalAction: Action = {
|
||||
name: "CREATE_MULTISIG_PROPOSAL_ACTION",
|
||||
similes: [
|
||||
"create proposal",
|
||||
"create proposal to transfer funds",
|
||||
"create proposal to transfer funds from 2-of-2 multisig",
|
||||
"create proposal to transfer funds from 2-of-2 multisig account",
|
||||
"create proposal to transfer funds from 2-of-2 multisig account on Solana",
|
||||
],
|
||||
description: `Create a proposal to transfer funds from a 2-of-2 multisig account on Solana with the user and the agent, where both approvals will be required to run the transactions.
|
||||
|
||||
If transactionIndex is not provided, the latest index will automatically be fetched and used.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
transactionIndex: 0,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Proposal created successfully",
|
||||
transaction: "4xKpN2...",
|
||||
transactionIndex: "0",
|
||||
},
|
||||
explanation:
|
||||
"Create a proposal to transfer 1 SOL from 2-of-2 multisig account on Solana",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
transactionIndex: z.number().optional(),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const transactionIndex =
|
||||
input.transactionIndex !== undefined
|
||||
? Number(input.transactionIndex)
|
||||
: undefined;
|
||||
|
||||
const multisig = await multisig_create_proposal(agent, transactionIndex);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Proposal created successfully",
|
||||
transaction: multisig,
|
||||
transactionIndex: transactionIndex,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default createMultisigProposalAction;
|
||||
49
src/actions/squads/depositToMultisigTreasury.ts
Normal file
49
src/actions/squads/depositToMultisigTreasury.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { multisig_deposit_to_treasury } from "../../tools";
|
||||
|
||||
const depositToMultisigAction: Action = {
|
||||
name: "DEPOSIT_TO_MULTISIG_ACTION",
|
||||
similes: [
|
||||
"deposit to multisig",
|
||||
"deposit to squads multisig",
|
||||
"deposit to 2-of-2 multisig account",
|
||||
"deposit to 2-of-2 multisig account on Solana",
|
||||
"deposit SOL to 2-of-2 multisig",
|
||||
"deposit SPL tokens to 2-of-2 multisig",
|
||||
],
|
||||
description: `Deposit funds to a 2-of-2 multisig account on Solana with the user and the agent, where both approvals will be required to run the transactions.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 1,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Funds deposited to 2-by-2 multisig account successfully",
|
||||
signature: "4xKpN2...",
|
||||
},
|
||||
explanation: "Deposit 1 SOL to 2-of-2 multisig account on Solana",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z.number().min(0, "Amount must be greater than 0"),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const multisig = await multisig_deposit_to_treasury(
|
||||
agent,
|
||||
input.amount as number,
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Funds deposited to 2-by-2 multisig account successfully",
|
||||
signature: multisig,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default depositToMultisigAction;
|
||||
53
src/actions/squads/executeMultisigProposal.ts
Normal file
53
src/actions/squads/executeMultisigProposal.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { multisig_execute_proposal } from "../../tools";
|
||||
|
||||
const executeMultisigProposalAction: Action = {
|
||||
name: "EXECUTE_MULTISIG_PROPOSAL_ACTION",
|
||||
similes: [
|
||||
"execute proposal",
|
||||
"execute proposal to transfer funds",
|
||||
"execute proposal to transfer funds from 2-of-2 multisig",
|
||||
"execute proposal to transfer funds from 2-of-2 multisig account",
|
||||
"execute proposal to transfer funds from 2-of-2 multisig account on Solana",
|
||||
],
|
||||
description: `Execute a proposal to transfer funds from a 2-of-2 multisig account on Solana with the user and the agent, where both approvals will be required to run the transactions.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
proposalIndex: 0,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Proposal executed successfully",
|
||||
transaction: "4xKpN2...",
|
||||
proposalIndex: "0",
|
||||
},
|
||||
explanation:
|
||||
"Execute a proposal to transfer 1 SOL from 2-of-2 multisig account on Solana",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
proposalIndex: z.number().optional(),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const proposalIndex =
|
||||
input.proposalIndex !== undefined
|
||||
? Number(input.proposalIndex)
|
||||
: undefined;
|
||||
|
||||
const multisig = await multisig_execute_proposal(agent, proposalIndex);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Proposal executed successfully",
|
||||
transaction: multisig,
|
||||
proposalIndex,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default executeMultisigProposalAction;
|
||||
53
src/actions/squads/rejectMultisigProposal.ts
Normal file
53
src/actions/squads/rejectMultisigProposal.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { multisig_reject_proposal } from "../../tools";
|
||||
|
||||
const rejectMultisigProposalAction: Action = {
|
||||
name: "REJECT_MULTISIG_PROPOSAL_ACTION",
|
||||
similes: [
|
||||
"reject proposal",
|
||||
"reject proposal to transfer funds",
|
||||
"reject proposal to transfer funds from 2-of-2 multisig",
|
||||
"reject proposal to transfer funds from 2-of-2 multisig account",
|
||||
"reject proposal to transfer funds from 2-of-2 multisig account on Solana",
|
||||
],
|
||||
description: `Reject a proposal to transfer funds from a 2-of-2 multisig account on Solana with the user and the agent, where both approvals will be required to run the transactions.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
proposalIndex: 0,
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Proposal rejected successfully",
|
||||
transaction: "4xKpN2...",
|
||||
proposalIndex: "0",
|
||||
},
|
||||
explanation:
|
||||
"Reject a proposal to transfer 1 SOL from 2-of-2 multisig account on Solana",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
proposalIndex: z.number().optional(),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const proposalIndex =
|
||||
input.proposalIndex !== undefined
|
||||
? Number(input.proposalIndex)
|
||||
: undefined;
|
||||
|
||||
const tx = await multisig_reject_proposal(agent, proposalIndex);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Proposal rejected successfully",
|
||||
transaction: tx,
|
||||
proposalIndex,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default rejectMultisigProposalAction;
|
||||
56
src/actions/squads/transferFromMultisigTreasury.ts
Normal file
56
src/actions/squads/transferFromMultisigTreasury.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Action } from "../../types/action";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { z } from "zod";
|
||||
import { multisig_transfer_from_treasury } from "../../tools";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
const transferFromMultisigAction: Action = {
|
||||
name: "TRANSFER_FROM_MULTISIG_ACTION",
|
||||
similes: [
|
||||
"transfer from multisig",
|
||||
"transfer from squads multisig",
|
||||
"transfer SOL from 2-by-2 multisig",
|
||||
"transfer from 2-of-2 multisig account",
|
||||
"transfer from 2-of-2 multisig account on Solana",
|
||||
],
|
||||
description: `Create a transaction to transfer funds from a 2-of-2 multisig account on Solana using Squads with the user and the agent, where both approvals will be required to run the transactions.`,
|
||||
examples: [
|
||||
[
|
||||
{
|
||||
input: {
|
||||
amount: 1,
|
||||
recipient: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
|
||||
},
|
||||
output: {
|
||||
status: "success",
|
||||
message: "Transaction added to 2-by-2 multisig account successfully",
|
||||
transaction: "4xKpN2...",
|
||||
amount: "1",
|
||||
recipient: "7nE9GvcwsqzYxmJLSrYmSB1V1YoJWVK1KWzAcWAzjXkN",
|
||||
},
|
||||
explanation: "Transfer 1 SOL from 2-of-2 multisig account on Solana",
|
||||
},
|
||||
],
|
||||
],
|
||||
schema: z.object({
|
||||
amount: z.number().min(0, "Amount must be greater than 0"),
|
||||
recipient: z.string(),
|
||||
}),
|
||||
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
|
||||
const multisig = await multisig_transfer_from_treasury(
|
||||
agent,
|
||||
input.amount as number,
|
||||
new PublicKey(input.recipient as string),
|
||||
);
|
||||
|
||||
return {
|
||||
status: "success",
|
||||
message: "Transaction added to 2-by-2 multisig account successfully",
|
||||
transaction: multisig,
|
||||
amount: input.amount,
|
||||
recipient: input.recipient,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default transferFromMultisigAction;
|
||||
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;
|
||||
@@ -2,8 +2,12 @@ import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
import bs58 from "bs58";
|
||||
import Decimal from "decimal.js";
|
||||
import {
|
||||
CreateCollectionOptions,
|
||||
CreateSingleOptions,
|
||||
StoreInitOptions,
|
||||
} from "@3land/listings-sdk/dist/types/implementation/implementationTypes";
|
||||
import { DEFAULT_OPTIONS } from "../constants";
|
||||
import { Config, TokenCheck } from "../types";
|
||||
import {
|
||||
deploy_collection,
|
||||
deploy_token,
|
||||
@@ -65,8 +69,44 @@ import {
|
||||
fetchPythPriceFeedID,
|
||||
flashOpenTrade,
|
||||
flashCloseTrade,
|
||||
} from "../tools/";
|
||||
createCollection,
|
||||
createSingle,
|
||||
multisig_transfer_from_treasury,
|
||||
create_squads_multisig,
|
||||
multisig_create_proposal,
|
||||
multisig_deposit_to_treasury,
|
||||
multisig_reject_proposal,
|
||||
multisig_approve_proposal,
|
||||
multisig_execute_proposal,
|
||||
parseTransaction,
|
||||
sendTransactionWithPriorityFee,
|
||||
getAssetsByOwner,
|
||||
getHeliusWebhook,
|
||||
create_HeliusWebhook,
|
||||
deleteHeliusWebhook,
|
||||
createDriftUserAccount,
|
||||
createVault,
|
||||
depositIntoVault,
|
||||
depositToDriftUserAccount,
|
||||
getVaultAddress,
|
||||
doesUserHaveDriftAccount,
|
||||
driftUserAccountInfo,
|
||||
requestWithdrawalFromVault,
|
||||
tradeDriftVault,
|
||||
driftPerpTrade,
|
||||
updateVault,
|
||||
getVaultInfo,
|
||||
withdrawFromDriftUserAccount,
|
||||
withdrawFromDriftVault,
|
||||
updateVaultDelegate,
|
||||
get_token_balance,
|
||||
voltrGetPositionValues,
|
||||
voltrDepositStrategy,
|
||||
voltrWithdrawStrategy,
|
||||
} from "../tools";
|
||||
import {
|
||||
Config,
|
||||
TokenCheck,
|
||||
CollectionDeployment,
|
||||
CollectionOptions,
|
||||
GibworkCreateTaskReponse,
|
||||
@@ -77,23 +117,9 @@ import {
|
||||
OrderParams,
|
||||
FlashTradeParams,
|
||||
FlashCloseTradeParams,
|
||||
HeliusWebhookIdResponse,
|
||||
HeliusWebhookResponse,
|
||||
} from "../types";
|
||||
import {
|
||||
createCollection,
|
||||
createSingle,
|
||||
} from "../tools/3land/create_3land_collectible";
|
||||
import {
|
||||
CreateCollectionOptions,
|
||||
CreateSingleOptions,
|
||||
StoreInitOptions,
|
||||
} from "@3land/listings-sdk/dist/types/implementation/implementationTypes";
|
||||
import { create_squads_multisig } from "../tools/squads_multisig/create_multisig";
|
||||
import { deposit_to_multisig } from "../tools/squads_multisig/deposit_to_multisig";
|
||||
import { transfer_from_multisig } from "../tools/squads_multisig/transfer_from_multisig";
|
||||
import { create_proposal } from "../tools/squads_multisig/create_proposal";
|
||||
import { approve_proposal } from "../tools/squads_multisig/approve_proposal";
|
||||
import { execute_transaction } from "../tools/squads_multisig/execute_proposal";
|
||||
import { reject_proposal } from "../tools/squads_multisig/reject_proposal";
|
||||
|
||||
/**
|
||||
* Main class for interacting with Solana blockchain
|
||||
@@ -169,6 +195,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,
|
||||
@@ -597,29 +636,68 @@ export class SolanaAgentKit {
|
||||
async flashCloseTrade(params: FlashCloseTradeParams): Promise<string> {
|
||||
return flashCloseTrade(this, params);
|
||||
}
|
||||
async heliusParseTransactions(transactionId: string): Promise<any> {
|
||||
return parseTransaction(this, transactionId);
|
||||
}
|
||||
async getAllAssetsbyOwner(owner: PublicKey, limit: number): Promise<any> {
|
||||
return getAssetsByOwner(this, owner, limit);
|
||||
}
|
||||
|
||||
async create3LandCollection(
|
||||
optionsWithBase58: StoreInitOptions,
|
||||
collectionOpts: CreateCollectionOptions,
|
||||
isDevnet: boolean = false,
|
||||
): Promise<string> {
|
||||
let 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> {
|
||||
let 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}`;
|
||||
}
|
||||
async sendTranctionWithPriority(
|
||||
priorityLevel: string,
|
||||
amount: number,
|
||||
to: PublicKey,
|
||||
splmintAddress?: PublicKey,
|
||||
): Promise<{ transactionId: string; fee: number }> {
|
||||
return sendTransactionWithPriorityFee(
|
||||
this,
|
||||
priorityLevel,
|
||||
amount,
|
||||
to,
|
||||
splmintAddress,
|
||||
);
|
||||
}
|
||||
|
||||
async createSquadsMultisig(creator: PublicKey): Promise<string> {
|
||||
return create_squads_multisig(this, creator);
|
||||
@@ -630,7 +708,7 @@ export class SolanaAgentKit {
|
||||
vaultIndex: number = 0,
|
||||
mint?: PublicKey,
|
||||
): Promise<string> {
|
||||
return deposit_to_multisig(this, amount, vaultIndex, mint);
|
||||
return multisig_deposit_to_treasury(this, amount, vaultIndex, mint);
|
||||
}
|
||||
|
||||
async transferFromMultisig(
|
||||
@@ -639,30 +717,160 @@ export class SolanaAgentKit {
|
||||
vaultIndex: number = 0,
|
||||
mint?: PublicKey,
|
||||
): Promise<string> {
|
||||
return transfer_from_multisig(this, amount, to, vaultIndex, mint);
|
||||
return multisig_transfer_from_treasury(this, amount, to, vaultIndex, mint);
|
||||
}
|
||||
|
||||
async createMultisigProposal(
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
return create_proposal(this, transactionIndex);
|
||||
return multisig_create_proposal(this, transactionIndex);
|
||||
}
|
||||
|
||||
async approveMultisigProposal(
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
return approve_proposal(this, transactionIndex);
|
||||
return multisig_approve_proposal(this, transactionIndex);
|
||||
}
|
||||
|
||||
async rejectMultisigProposal(
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
return reject_proposal(this, transactionIndex);
|
||||
return multisig_reject_proposal(this, transactionIndex);
|
||||
}
|
||||
|
||||
async executeMultisigTransaction(
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
return execute_transaction(this, transactionIndex);
|
||||
return multisig_execute_proposal(this, transactionIndex);
|
||||
}
|
||||
async CreateWebhook(
|
||||
accountAddresses: string[],
|
||||
webhookURL: string,
|
||||
): Promise<HeliusWebhookResponse> {
|
||||
return create_HeliusWebhook(this, accountAddresses, webhookURL);
|
||||
}
|
||||
async getWebhook(id: string): Promise<HeliusWebhookIdResponse> {
|
||||
return getHeliusWebhook(this, id);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/langchain/drift/index.ts
Normal file
15
src/langchain/drift/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
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";
|
||||
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",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
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",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
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",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/langchain/helius/create_webhook.ts
Normal file
65
src/langchain/helius/create_webhook.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaHeliusWebhookTool extends Tool {
|
||||
name = "create_helius_webhook";
|
||||
description = `Creates a Helius Webhook that listens to specified account addresses.
|
||||
Inputs (input is a JSON string):
|
||||
accountAddresses: string[] | string,
|
||||
e.g. ["BVdNLvyG2DNiWAXBE9qAmc4MTQXymd5Bzfo9xrQSUzVP","Eo2ciguhMLmcTWXELuEQPdu7DWZt67LHXb2rdHZUbot7"]
|
||||
or "BVdNLvyG2DNiWAXBE9qAmc4MTQXymd5Bzfo9xrQSUzVP,Eo2ciguhMLmcTWXELuEQPdu7DWZt67LHXb2rdHZUbot7"
|
||||
webhookURL: string, e.g. "https://TestServer.test.repl.co/webhooks"`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
let accountAddresses: string[] = [];
|
||||
|
||||
if (!parsedInput.accountAddresses) {
|
||||
throw new Error('Missing "accountAddresses" property in input JSON.');
|
||||
}
|
||||
if (Array.isArray(parsedInput.accountAddresses)) {
|
||||
accountAddresses = parsedInput.accountAddresses.map((addr: string) =>
|
||||
addr.trim(),
|
||||
);
|
||||
} else if (typeof parsedInput.accountAddresses === "string") {
|
||||
accountAddresses = parsedInput.accountAddresses
|
||||
.split(",")
|
||||
.map((addr: string) => addr.trim());
|
||||
} else {
|
||||
throw new Error(
|
||||
'Invalid type for "accountAddresses". Expected array or comma-separated string.',
|
||||
);
|
||||
}
|
||||
|
||||
const webhookURL = parsedInput.webhookURL;
|
||||
if (!webhookURL) {
|
||||
throw new Error(
|
||||
'Invalid input. Expected a "webhookURL" property in the JSON.',
|
||||
);
|
||||
}
|
||||
const result = await this.solanaKit.CreateWebhook(
|
||||
accountAddresses,
|
||||
webhookURL,
|
||||
);
|
||||
|
||||
// Return success in JSON
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Helius Webhook created successfully",
|
||||
webhookURL: result.webhookURL,
|
||||
webhookID: result.webhookID,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/langchain/helius/delete_webhook.ts
Normal file
39
src/langchain/helius/delete_webhook.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaDeleteHeliusWebhookTool extends Tool {
|
||||
name = "delete_helius_webhook";
|
||||
description = `Deletes a Helius Webhook by its ID.
|
||||
Inputs (input is a JSON string):
|
||||
webhookID: string, e.g. "1ed4244d-a591-4854-ac31-cc28d40b8255"`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
|
||||
const webhookID = parsedInput.webhookID;
|
||||
if (!webhookID || typeof webhookID !== "string") {
|
||||
throw new Error(
|
||||
'Invalid input. Expected a "webhookID" property in the JSON.',
|
||||
);
|
||||
}
|
||||
const result = await this.solanaKit.deleteWebhook(webhookID);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Helius Webhook deleted successfully",
|
||||
data: result,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/langchain/helius/get_all_assets.ts
Normal file
38
src/langchain/helius/get_all_assets.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
export class SolanaGetAllAssetsByOwner extends Tool {
|
||||
name = "solana_get_all_assets_by_owner";
|
||||
description = `Get all assets owned by a specific wallet address.
|
||||
Inputs:
|
||||
- owner: string, the wallet address of the owner, e.g., "4Be9CvxqHW6BYiRAxW9Q3xu1ycTMWaL5z8NX4HR3ha7t" (required)
|
||||
- limit: number, the maximum number of assets to retrieve (optional)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const { owner, limit } = JSON.parse(input);
|
||||
const ownerPubkey = new PublicKey(owner);
|
||||
|
||||
const assets = await this.solanaKit.getAllAssetsbyOwner(
|
||||
ownerPubkey,
|
||||
limit,
|
||||
);
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Assets retrieved successfully",
|
||||
assets: assets,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/langchain/helius/get_webhook.ts
Normal file
43
src/langchain/helius/get_webhook.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaGetHeliusWebhookTool extends Tool {
|
||||
name = "get_helius_webhook";
|
||||
description = `Retrieves a Helius Webhook by its ID.
|
||||
Inputs (input is a JSON string):
|
||||
webhookID: string, e.g. "1ed4244d-a591-4854-ac31-cc28d40b8255"`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
|
||||
const webhookID = parsedInput.webhookID;
|
||||
if (!webhookID || typeof webhookID !== "string") {
|
||||
throw new Error(
|
||||
'Invalid input. Expected a "webhookID" property in the JSON.',
|
||||
);
|
||||
}
|
||||
|
||||
const result = await this.solanaKit.getWebhook(webhookID);
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Helius Webhook retrieved successfully",
|
||||
wallet: result.wallet,
|
||||
webhookURL: result.webhookURL,
|
||||
transactionTypes: result.transactionTypes,
|
||||
accountAddresses: result.accountAddresses,
|
||||
webhookType: result.webhookType,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/langchain/helius/index.ts
Normal file
6
src/langchain/helius/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from "./create_webhook";
|
||||
export * from "./delete_webhook";
|
||||
export * from "./get_all_assets";
|
||||
export * from "./get_webhook";
|
||||
export * from "./parse_transaction";
|
||||
export * from "./send_transaction_priority";
|
||||
32
src/langchain/helius/parse_transaction.ts
Normal file
32
src/langchain/helius/parse_transaction.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
|
||||
export class SolanaParseTransactionHeliusTool extends Tool {
|
||||
name = "solana_parse_transaction_helius";
|
||||
description = `Parse a Solana transaction using Helius API.
|
||||
Inputs:
|
||||
- transactionId: string, the ID of the transaction to parse, e.g., "5h3k...9d2k" (required).`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<any> {
|
||||
try {
|
||||
const transactionId = input.trim();
|
||||
const parsedTransaction =
|
||||
await this.solanaKit.heliusParseTransactions(transactionId);
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "transaction parsed successfully",
|
||||
transaction: parsedTransaction,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "NOt able to Parse transaction",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
63
src/langchain/helius/send_transaction_priority.ts
Normal file
63
src/langchain/helius/send_transaction_priority.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Tool } from "langchain/tools";
|
||||
import { SolanaAgentKit } from "../../agent";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
export class SolanaSendTransactionWithPriorityFee extends Tool {
|
||||
name = "solana_send_transaction_with_priority_fee";
|
||||
description = `Sends a Solana transaction with a user-defined priority fee.
|
||||
**Inputs (JSON-encoded string)**:
|
||||
- priorityLevel: string — the priority level ("NONE", "Min", "Low", "Medium", "High", "VeryHigh", or "UnsafeMax")
|
||||
- amount: number — the amount of SOL to send
|
||||
- to: string — the recipient's wallet address (public key in base58);`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const { priorityLevel, amount, to, splmintAddress } = JSON.parse(input);
|
||||
|
||||
const validPriorityLevels = [
|
||||
"NONE",
|
||||
"Min",
|
||||
"Low",
|
||||
"Medium",
|
||||
"High",
|
||||
"VeryHigh",
|
||||
"UnsafeMax",
|
||||
];
|
||||
if (!validPriorityLevels.includes(priorityLevel)) {
|
||||
throw new Error(
|
||||
`Invalid priority level. Must be one of: ${validPriorityLevels.join(", ")}. Received: ${priorityLevel}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!amount || !to) {
|
||||
throw new Error(
|
||||
`Missing required fields. Received: priorityLevel=${priorityLevel}, amount=${amount}, to=${to}`,
|
||||
);
|
||||
}
|
||||
|
||||
const toPubkey = new PublicKey(to);
|
||||
const priorityFeeTx = await this.solanaKit.sendTranctionWithPriority(
|
||||
priorityLevel,
|
||||
amount,
|
||||
toPubkey,
|
||||
splmintAddress,
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "Transaction sent successfully",
|
||||
priorityFeeTx,
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,10 @@ export * from "./3land";
|
||||
export * from "./tiplink";
|
||||
export * from "./sns";
|
||||
export * from "./lightprotocol";
|
||||
export * from "./squads";
|
||||
export * from "./helius";
|
||||
export * from "./drift";
|
||||
export * from "./voltr";
|
||||
|
||||
import { SolanaAgentKit } from "../agent";
|
||||
import {
|
||||
@@ -85,6 +89,37 @@ import {
|
||||
SolanaPerpCloseTradeTool,
|
||||
SolanaFlashOpenTrade,
|
||||
SolanaFlashCloseTrade,
|
||||
SolanaCreate2by2Multisig,
|
||||
SolanaDepositTo2by2Multisig,
|
||||
SolanaTransferFrom2by2Multisig,
|
||||
SolanaCreateProposal2by2Multisig,
|
||||
SolanaApproveProposal2by2Multisig,
|
||||
SolanaExecuteProposal2by2Multisig,
|
||||
SolanaRejectProposal2by2Multisig,
|
||||
SolanaSendTransactionWithPriorityFee,
|
||||
SolanaHeliusWebhookTool,
|
||||
SolanaGetHeliusWebhookTool,
|
||||
SolanaDeleteHeliusWebhookTool,
|
||||
SolanaParseTransactionHeliusTool,
|
||||
SolanaGetAllAssetsByOwner,
|
||||
SolanaCheckDriftAccountTool,
|
||||
SolanaCreateDriftUserAccountTool,
|
||||
SolanaCreateDriftVaultTool,
|
||||
SolanaDepositIntoDriftVaultTool,
|
||||
SolanaDepositToDriftUserAccountTool,
|
||||
SolanaDeriveVaultAddressTool,
|
||||
SolanaDriftUserAccountInfoTool,
|
||||
SolanaDriftVaultInfoTool,
|
||||
SolanaRequestDriftWithdrawalTool,
|
||||
SolanaTradeDelegatedDriftVaultTool,
|
||||
SolanaTradeDriftPerpAccountTool,
|
||||
SolanaUpdateDriftVaultDelegateTool,
|
||||
SolanaUpdateDriftVaultTool,
|
||||
SolanaWithdrawFromDriftAccountTool,
|
||||
SolanaWithdrawFromDriftVaultTool,
|
||||
SolanaVoltrGetPositionValues,
|
||||
SolanaVoltrDepositStrategy,
|
||||
SolanaVoltrWithdrawStrategy,
|
||||
} from "./index";
|
||||
|
||||
export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
@@ -148,5 +183,41 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaPerpCloseTradeTool(solanaKit),
|
||||
new SolanaFlashOpenTrade(solanaKit),
|
||||
new SolanaFlashCloseTrade(solanaKit),
|
||||
new SolanaCreate2by2Multisig(solanaKit),
|
||||
new SolanaCreateProposal2by2Multisig(solanaKit),
|
||||
new SolanaApproveProposal2by2Multisig(solanaKit),
|
||||
new SolanaRejectProposal2by2Multisig(solanaKit),
|
||||
new SolanaExecuteProposal2by2Multisig(solanaKit),
|
||||
new SolanaDepositTo2by2Multisig(solanaKit),
|
||||
new SolanaTransferFrom2by2Multisig(solanaKit),
|
||||
new SolanaSendTransactionWithPriorityFee(solanaKit),
|
||||
new SolanaHeliusWebhookTool(solanaKit),
|
||||
new SolanaGetHeliusWebhookTool(solanaKit),
|
||||
new SolanaDeleteHeliusWebhookTool(solanaKit),
|
||||
new SolanaParseTransactionHeliusTool(solanaKit),
|
||||
new SolanaGetAllAssetsByOwner(solanaKit),
|
||||
new Solana3LandCreateSingle(solanaKit),
|
||||
new SolanaSendTransactionWithPriorityFee(solanaKit),
|
||||
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 SolanaVoltrGetPositionValues(solanaKit),
|
||||
new SolanaVoltrDepositStrategy(solanaKit),
|
||||
new SolanaVoltrWithdrawStrategy(solanaKit),
|
||||
];
|
||||
}
|
||||
|
||||
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,21 +50,11 @@ export async function createSingle(
|
||||
landStore,
|
||||
collectionAccount,
|
||||
createItemOptions,
|
||||
true, //isAI
|
||||
withPool,
|
||||
);
|
||||
return singleEditionTx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Single edition creation failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Buy a single edition on 3Land
|
||||
* @param
|
||||
* @returns
|
||||
*/
|
||||
// export async function buySingle() {
|
||||
// try {
|
||||
// } catch (error: any) {
|
||||
// throw new Error(`Buying single edition failed: ${error.message}`);
|
||||
// }
|
||||
// }
|
||||
|
||||
460
src/tools/drift/drift.ts
Normal file
460
src/tools/drift/drift.ts
Normal file
@@ -0,0 +1,460 @@
|
||||
import {
|
||||
BASE_PRECISION,
|
||||
convertToNumber,
|
||||
DRIFT_PROGRAM_ID,
|
||||
DriftClient,
|
||||
FastSingleTxSender,
|
||||
getLimitOrderParams,
|
||||
getMarketOrderParams,
|
||||
getUserAccountPublicKeySync,
|
||||
MainnetSpotMarkets,
|
||||
numberToSafeBN,
|
||||
PositionDirection,
|
||||
PostOnlyParams,
|
||||
PRICE_PRECISION,
|
||||
QUOTE_PRECISION,
|
||||
User,
|
||||
type IWallet,
|
||||
} from "@drift-labs/sdk";
|
||||
import type { SolanaAgentKit } from "../../agent";
|
||||
import * as anchor from "@coral-xyz/anchor";
|
||||
import { IDL, VAULT_PROGRAM_ID, VaultClient } from "@drift-labs/vaults-sdk";
|
||||
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { Transaction } from "@solana/web3.js";
|
||||
import { ComputeBudgetProgram } from "@solana/web3.js";
|
||||
|
||||
export async function initClients(
|
||||
agent: SolanaAgentKit,
|
||||
params?: {
|
||||
authority: PublicKey;
|
||||
activeSubAccountId: number;
|
||||
subAccountIds: number[];
|
||||
},
|
||||
) {
|
||||
const wallet: IWallet = {
|
||||
publicKey: agent.wallet.publicKey,
|
||||
payer: agent.wallet,
|
||||
signAllTransactions: async (txs) => {
|
||||
for (const tx of txs) {
|
||||
tx.sign(agent.wallet);
|
||||
}
|
||||
return txs;
|
||||
},
|
||||
signTransaction: async (tx) => {
|
||||
tx.sign(agent.wallet);
|
||||
return tx;
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-error - false undefined type conflict
|
||||
const driftClient = new DriftClient({
|
||||
connection: agent.connection,
|
||||
wallet,
|
||||
env: "mainnet-beta",
|
||||
authority: params?.authority,
|
||||
activeSubAccountId: params?.activeSubAccountId,
|
||||
subAccountIds: params?.subAccountIds,
|
||||
txParams: {
|
||||
computeUnitsPrice: 0.000001 * 1000000 * 1000000,
|
||||
},
|
||||
txSender: new FastSingleTxSender({
|
||||
connection: agent.connection,
|
||||
wallet,
|
||||
timeout: 30000,
|
||||
blockhashRefreshInterval: 1000,
|
||||
opts: {
|
||||
commitment: agent.connection.commitment ?? "confirmed",
|
||||
skipPreflight: false,
|
||||
preflightCommitment: agent.connection.commitment ?? "confirmed",
|
||||
},
|
||||
}),
|
||||
});
|
||||
const vaultProgram = new anchor.Program(
|
||||
IDL,
|
||||
VAULT_PROGRAM_ID,
|
||||
driftClient.provider,
|
||||
);
|
||||
const vaultClient = new VaultClient({
|
||||
driftClient,
|
||||
// @ts-expect-error - type mismatch due to different dep versions
|
||||
program: vaultProgram,
|
||||
cliMode: false,
|
||||
});
|
||||
await driftClient.subscribe();
|
||||
|
||||
async function cleanUp() {
|
||||
await driftClient.unsubscribe();
|
||||
}
|
||||
|
||||
return { driftClient, vaultClient, cleanUp };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a drift user account provided an amount
|
||||
* @param amount amount of the token to deposit
|
||||
* @param symbol symbol of the token to deposit
|
||||
*/
|
||||
export async function createDriftUserAccount(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
symbol: string,
|
||||
) {
|
||||
try {
|
||||
const { driftClient, cleanUp } = await initClients(agent);
|
||||
const user = new User({
|
||||
driftClient,
|
||||
userAccountPublicKey: getUserAccountPublicKeySync(
|
||||
new PublicKey(DRIFT_PROGRAM_ID),
|
||||
agent.wallet.publicKey,
|
||||
),
|
||||
});
|
||||
const userAccountExists = await user.exists();
|
||||
const token = MainnetSpotMarkets.find(
|
||||
(v) => v.symbol === symbol.toUpperCase(),
|
||||
);
|
||||
|
||||
if (!token) {
|
||||
throw new Error(`Token with symbol ${symbol} not found`);
|
||||
}
|
||||
|
||||
if (!userAccountExists) {
|
||||
const depositAmount = numberToSafeBN(amount, token.precision);
|
||||
const [txSignature, account] =
|
||||
await driftClient.initializeUserAccountAndDepositCollateral(
|
||||
depositAmount,
|
||||
getAssociatedTokenAddressSync(token.mint, agent.wallet.publicKey),
|
||||
);
|
||||
|
||||
await cleanUp();
|
||||
return { txSignature, account };
|
||||
}
|
||||
|
||||
await cleanUp();
|
||||
return {
|
||||
message: "User account already exists",
|
||||
account: user.userAccountPublicKey,
|
||||
};
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to create user account: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deposit to your drift user account
|
||||
* @param agent
|
||||
* @param amount
|
||||
* @param symbol
|
||||
* @param isRepay
|
||||
* @returns
|
||||
*/
|
||||
export async function depositToDriftUserAccount(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
symbol: string,
|
||||
isRepay = false,
|
||||
) {
|
||||
try {
|
||||
const { driftClient, cleanUp } = await initClients(agent);
|
||||
const publicKey = agent.wallet.publicKey;
|
||||
const user = new User({
|
||||
driftClient,
|
||||
userAccountPublicKey: getUserAccountPublicKeySync(
|
||||
new PublicKey(DRIFT_PROGRAM_ID),
|
||||
publicKey,
|
||||
),
|
||||
});
|
||||
const userAccountExists = await user.exists();
|
||||
const token = MainnetSpotMarkets.find(
|
||||
(v) => v.symbol === symbol.toUpperCase(),
|
||||
);
|
||||
|
||||
if (!token) {
|
||||
throw new Error(`Token with symbol ${symbol} not found`);
|
||||
}
|
||||
|
||||
if (!userAccountExists) {
|
||||
throw new Error("You need to create a Drift user account first.");
|
||||
}
|
||||
|
||||
const depositAmount = numberToSafeBN(amount, token.precision);
|
||||
|
||||
const [depInstruction, latestBlockhash] = await Promise.all([
|
||||
driftClient.getDepositTxnIx(
|
||||
depositAmount,
|
||||
token.marketIndex,
|
||||
getAssociatedTokenAddressSync(token.mint, publicKey),
|
||||
undefined,
|
||||
isRepay,
|
||||
),
|
||||
driftClient.connection.getLatestBlockhash(),
|
||||
]);
|
||||
|
||||
const tx = new Transaction().add(...depInstruction).add(
|
||||
ComputeBudgetProgram.setComputeUnitPrice({
|
||||
microLamports: 0.000001 * 1000000 * 1000000,
|
||||
}),
|
||||
);
|
||||
tx.recentBlockhash = latestBlockhash.blockhash;
|
||||
tx.sign(agent.wallet);
|
||||
const txSignature = await driftClient.txSender.sendRawTransaction(
|
||||
tx.serialize(),
|
||||
{ ...driftClient.opts },
|
||||
);
|
||||
|
||||
await cleanUp();
|
||||
return txSignature;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to deposit to user account: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function withdrawFromDriftUserAccount(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
symbol: string,
|
||||
isBorrow = false,
|
||||
) {
|
||||
try {
|
||||
const { driftClient, cleanUp } = await initClients(agent);
|
||||
const user = new User({
|
||||
driftClient,
|
||||
userAccountPublicKey: getUserAccountPublicKeySync(
|
||||
new PublicKey(DRIFT_PROGRAM_ID),
|
||||
agent.wallet.publicKey,
|
||||
),
|
||||
});
|
||||
const userAccountExists = await user.exists();
|
||||
|
||||
if (!userAccountExists) {
|
||||
throw new Error("You need to create a Drift user account first.");
|
||||
}
|
||||
|
||||
const token = MainnetSpotMarkets.find(
|
||||
(v) => v.symbol === symbol.toUpperCase(),
|
||||
);
|
||||
|
||||
if (!token) {
|
||||
throw new Error(`Token with symbol ${symbol} not found`);
|
||||
}
|
||||
|
||||
const withdrawAmount = numberToSafeBN(amount, token.precision);
|
||||
|
||||
const [withdrawInstruction, latestBlockhash] = await Promise.all([
|
||||
driftClient.getWithdrawalIxs(
|
||||
withdrawAmount,
|
||||
token.marketIndex,
|
||||
getAssociatedTokenAddressSync(token.mint, agent.wallet.publicKey),
|
||||
!isBorrow,
|
||||
),
|
||||
driftClient.connection.getLatestBlockhash(),
|
||||
]);
|
||||
|
||||
const tx = new Transaction().add(...withdrawInstruction).add(
|
||||
ComputeBudgetProgram.setComputeUnitPrice({
|
||||
microLamports: 0.000001 * 1000000 * 1000000,
|
||||
}),
|
||||
);
|
||||
tx.recentBlockhash = latestBlockhash.blockhash;
|
||||
tx.sign(agent.wallet);
|
||||
|
||||
const txSignature = await driftClient.txSender.sendRawTransaction(
|
||||
tx.serialize(),
|
||||
{ ...driftClient.opts },
|
||||
);
|
||||
|
||||
await cleanUp();
|
||||
return txSignature;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to withdraw from user account: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a perpetual trade on drift
|
||||
* @param agent
|
||||
* @param params.amount
|
||||
* @param params.symbol
|
||||
* @param params.action
|
||||
* @param params.type
|
||||
* @param params.price this should only be supplied if type is limit
|
||||
* @param params.reduceOnly
|
||||
*/
|
||||
export async function driftPerpTrade(
|
||||
agent: SolanaAgentKit,
|
||||
params: {
|
||||
amount: number;
|
||||
symbol: string;
|
||||
action: "long" | "short";
|
||||
type: "market" | "limit";
|
||||
price?: number | undefined;
|
||||
},
|
||||
) {
|
||||
try {
|
||||
const { driftClient, cleanUp } = await initClients(agent);
|
||||
const user = new User({
|
||||
driftClient,
|
||||
userAccountPublicKey: getUserAccountPublicKeySync(
|
||||
new PublicKey(DRIFT_PROGRAM_ID),
|
||||
agent.wallet.publicKey,
|
||||
),
|
||||
});
|
||||
const userAccountExists = await user.exists();
|
||||
|
||||
if (!userAccountExists) {
|
||||
throw new Error("You need to create a Drift user account first.");
|
||||
}
|
||||
|
||||
const market = driftClient.getMarketIndexAndType(
|
||||
`${params.symbol.toUpperCase()}-PERP`,
|
||||
);
|
||||
|
||||
if (!market) {
|
||||
throw new Error(`Token with symbol ${params.symbol} not found`);
|
||||
}
|
||||
|
||||
const baseAssetPrice = driftClient.getOracleDataForPerpMarket(
|
||||
market.marketIndex,
|
||||
);
|
||||
const convertedAmount =
|
||||
params.amount / convertToNumber(baseAssetPrice.price, PRICE_PRECISION);
|
||||
|
||||
let signature: anchor.web3.TransactionSignature;
|
||||
|
||||
if (params.type === "limit") {
|
||||
if (!params.price) {
|
||||
throw new Error("Price is required for limit orders");
|
||||
}
|
||||
|
||||
signature = await driftClient.placePerpOrder(
|
||||
getLimitOrderParams({
|
||||
baseAssetAmount: numberToSafeBN(convertedAmount, BASE_PRECISION),
|
||||
reduceOnly: false,
|
||||
direction:
|
||||
params.action === "long"
|
||||
? PositionDirection.LONG
|
||||
: PositionDirection.SHORT,
|
||||
marketIndex: market.marketIndex,
|
||||
price: numberToSafeBN(params.price, PRICE_PRECISION),
|
||||
postOnly: PostOnlyParams.SLIDE,
|
||||
}),
|
||||
{
|
||||
computeUnitsPrice: 0.000001 * 1000000 * 1000000,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
signature = await driftClient.placePerpOrder(
|
||||
getMarketOrderParams({
|
||||
baseAssetAmount: numberToSafeBN(convertedAmount, BASE_PRECISION),
|
||||
reduceOnly: false,
|
||||
direction:
|
||||
params.action === "long"
|
||||
? PositionDirection.LONG
|
||||
: PositionDirection.SHORT,
|
||||
marketIndex: market.marketIndex,
|
||||
}),
|
||||
{
|
||||
computeUnitsPrice: 0.000001 * 1000000 * 1000000,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (!signature) {
|
||||
throw new Error("Failed to place order. Please make sure ");
|
||||
}
|
||||
|
||||
await cleanUp();
|
||||
return signature;
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to place order: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user has a drift account
|
||||
* @param agent
|
||||
*/
|
||||
export async function doesUserHaveDriftAccount(agent: SolanaAgentKit) {
|
||||
try {
|
||||
const { driftClient, cleanUp } = await initClients(agent);
|
||||
const user = new User({
|
||||
driftClient,
|
||||
userAccountPublicKey: getUserAccountPublicKeySync(
|
||||
new PublicKey(DRIFT_PROGRAM_ID),
|
||||
agent.wallet.publicKey,
|
||||
),
|
||||
});
|
||||
user.getActivePerpPositions();
|
||||
const userAccountExists = await user.exists();
|
||||
await cleanUp();
|
||||
return {
|
||||
hasAccount: userAccountExists,
|
||||
account: user.userAccountPublicKey,
|
||||
};
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to check user account: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get account info for a drift User
|
||||
* @param agent
|
||||
* @returns
|
||||
*/
|
||||
export async function driftUserAccountInfo(agent: SolanaAgentKit) {
|
||||
try {
|
||||
const { driftClient, cleanUp } = await initClients(agent);
|
||||
const user = new User({
|
||||
driftClient,
|
||||
userAccountPublicKey: getUserAccountPublicKeySync(
|
||||
new PublicKey(DRIFT_PROGRAM_ID),
|
||||
agent.wallet.publicKey,
|
||||
),
|
||||
});
|
||||
const userAccountExists = await user.exists();
|
||||
|
||||
if (!userAccountExists) {
|
||||
throw new Error("User account does not exist");
|
||||
}
|
||||
await user.subscribe();
|
||||
const account = user.getUserAccount();
|
||||
await user.unsubscribe();
|
||||
|
||||
await cleanUp();
|
||||
const perpPositions = account.perpPositions.map((pos) => ({
|
||||
...pos,
|
||||
baseAssetAmount: convertToNumber(pos.baseAssetAmount, BASE_PRECISION),
|
||||
settledPnl: convertToNumber(pos.settledPnl, QUOTE_PRECISION),
|
||||
}));
|
||||
const spotPositions = account.spotPositions.map((pos) => ({
|
||||
...pos,
|
||||
scaledBalance: convertToNumber(pos.scaledBalance, BASE_PRECISION),
|
||||
cumulativeDeposits: convertToNumber(
|
||||
pos.cumulativeDeposits,
|
||||
BASE_PRECISION,
|
||||
),
|
||||
symbol: MainnetSpotMarkets.find((v) => v.marketIndex === pos.marketIndex)
|
||||
?.symbol,
|
||||
}));
|
||||
|
||||
return {
|
||||
...account,
|
||||
name: account.name,
|
||||
authority: account.authority,
|
||||
totalDeposits: `$${convertToNumber(account.totalDeposits, QUOTE_PRECISION)}`,
|
||||
totalWithdraws: `$${convertToNumber(account.totalWithdraws, QUOTE_PRECISION)}`,
|
||||
settledPerpPnl: `$${convertToNumber(account.settledPerpPnl, QUOTE_PRECISION)}`,
|
||||
lastActiveSlot: account.lastActiveSlot.toNumber(),
|
||||
perpPositions,
|
||||
spotPositions,
|
||||
};
|
||||
} catch (e) {
|
||||
// @ts-expect-error - error message is a string
|
||||
throw new Error(`Failed to check user account: ${e.message}`);
|
||||
}
|
||||
}
|
||||
641
src/tools/drift/drift_vault.ts
Normal file
641
src/tools/drift/drift_vault.ts
Normal file
@@ -0,0 +1,641 @@
|
||||
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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
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);
|
||||
|
||||
if (!marketIndexAndType) {
|
||||
throw new Error("Invalid market name");
|
||||
}
|
||||
|
||||
const spotMarket = driftClient.getSpotMarketAccount(
|
||||
marketIndexAndType.marketIndex,
|
||||
);
|
||||
|
||||
if (!spotMarket) {
|
||||
throw new Error("Market not found");
|
||||
}
|
||||
|
||||
const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
|
||||
|
||||
if (marketIndexAndType.marketType === MarketType.PERP) {
|
||||
throw new Error("Only SPOT market names are supported");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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 by someone else, so 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";
|
||||
57
src/tools/helius/get_assets_by_owner.ts
Normal file
57
src/tools/helius/get_assets_by_owner.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
/**
|
||||
* Fetch assets by owner using the Helius Digital Asset Standard (DAS) API
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param ownerPublicKey Owner's Solana wallet PublicKey
|
||||
* @param limit Number of assets to retrieve per request
|
||||
* @returns Assets owned by the specified address
|
||||
*/
|
||||
export async function getAssetsByOwner(
|
||||
agent: SolanaAgentKit,
|
||||
ownerPublicKey: PublicKey,
|
||||
limit: number,
|
||||
): Promise<any> {
|
||||
try {
|
||||
const apiKey = agent.config.HELIUS_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("HELIUS_API_KEY not found in environment variables");
|
||||
}
|
||||
|
||||
const url = `https://mainnet.helius-rpc.com/?api-key=${apiKey}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: "get-assets",
|
||||
method: "getAssetsByOwner",
|
||||
params: {
|
||||
ownerAddress: ownerPublicKey.toString(),
|
||||
page: 3,
|
||||
limit: limit,
|
||||
displayOptions: {
|
||||
showFungible: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch: ${response.status} - ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return data.result.items;
|
||||
} catch (error: any) {
|
||||
console.error("Error retrieving assets: ", error.message);
|
||||
throw new Error(`Assets retrieval failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
44
src/tools/helius/helius_transaction_parsing.ts
Normal file
44
src/tools/helius/helius_transaction_parsing.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
|
||||
/**
|
||||
* Parse a Solana transaction using the Helius Enhanced Transactions API
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param transactionId The transaction ID to parse
|
||||
* @returns Parsed transaction data
|
||||
*/
|
||||
export async function parseTransaction(
|
||||
agent: SolanaAgentKit,
|
||||
transactionId: string,
|
||||
): Promise<any> {
|
||||
try {
|
||||
const apiKey = agent.config.HELIUS_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("HELIUS_API_KEY not found in environment variables");
|
||||
}
|
||||
|
||||
const url = `https://api.helius.xyz/v0/transactions/?api-key=${apiKey}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
transactions: [transactionId],
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch: ${response.status} - ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return data;
|
||||
} catch (error: any) {
|
||||
console.error("Error parsing transaction: ", error.message);
|
||||
throw new Error(`Transaction parsing failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
132
src/tools/helius/helius_webhooks.ts
Normal file
132
src/tools/helius/helius_webhooks.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import { HeliusWebhookResponse, HeliusWebhookIdResponse } from "../../index";
|
||||
|
||||
export async function create_HeliusWebhook(
|
||||
agent: SolanaAgentKit,
|
||||
accountAddresses: string[],
|
||||
webhookURL: string,
|
||||
): Promise<HeliusWebhookResponse> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://api.helius.xyz/v0/webhooks?api-key=${agent.config.HELIUS_API_KEY}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
webhookURL,
|
||||
transactionTypes: ["Any"],
|
||||
accountAddresses,
|
||||
webhookType: "enhanced",
|
||||
txnStatus: "all",
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
webhookURL: data.webhookURL,
|
||||
webhookID: data.webhookID,
|
||||
};
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to create Webhook: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a Helius Webhook by ID, returning only the specified fields.
|
||||
*
|
||||
* @param agent - An instance of SolanaAgentKit (with .config.HELIUS_API_KEY)
|
||||
* @param webhookID - The unique ID of the webhook to retrieve
|
||||
*
|
||||
* @returns A HeliusWebhook object containing { wallet, webhookURL, transactionTypes, accountAddresses, webhookType }
|
||||
*/
|
||||
export async function getHeliusWebhook(
|
||||
agent: SolanaAgentKit,
|
||||
webhookID: string,
|
||||
): Promise<HeliusWebhookIdResponse> {
|
||||
try {
|
||||
const apiKey = agent.config.HELIUS_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("HELIUS_API_KEY is missing in agent.config");
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`https://api.helius.xyz/v0/webhooks/${webhookID}?api-key=${apiKey}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch webhook with ID ${webhookID}. ` +
|
||||
`Status Code: ${response.status}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return {
|
||||
wallet: data.wallet,
|
||||
webhookURL: data.webhookURL,
|
||||
transactionTypes: data.transactionTypes,
|
||||
accountAddresses: data.accountAddresses,
|
||||
webhookType: data.webhookType,
|
||||
};
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to get webhook by ID: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a Helius Webhook by its ID.
|
||||
*
|
||||
* @param agent - An instance of SolanaAgentKit (with .config.HELIUS_API_KEY)
|
||||
* @param webhookID - The unique ID of the webhook to delete
|
||||
*
|
||||
* @returns The response body from the Helius API (which may contain status or other info)
|
||||
*/
|
||||
export async function deleteHeliusWebhook(
|
||||
agent: SolanaAgentKit,
|
||||
webhookID: string,
|
||||
): Promise<any> {
|
||||
try {
|
||||
const apiKey = agent.config.HELIUS_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("Missing Helius API key in agent.config.HELIUS_API_KEY");
|
||||
}
|
||||
|
||||
const url = `https://api.helius.xyz/v0/webhooks/${webhookID}?api-key=${apiKey}`;
|
||||
const response = await fetch(url, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to delete webhook: ${response.status} ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
if (response.status === 204) {
|
||||
return { message: "Webhook deleted successfully (no content returned)" };
|
||||
}
|
||||
const contentLength = response.headers.get("Content-Length");
|
||||
if (contentLength === "0" || !contentLength) {
|
||||
return { message: "Webhook deleted successfully (empty body)" };
|
||||
}
|
||||
|
||||
// Otherwise, parse as JSON
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error: any) {
|
||||
console.error("Error deleting Helius Webhook:", error.message);
|
||||
throw new Error(`Failed to delete Helius Webhook: ${error.message}`);
|
||||
}
|
||||
}
|
||||
4
src/tools/helius/index.ts
Normal file
4
src/tools/helius/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./get_assets_by_owner";
|
||||
export * from "./helius_transaction_parsing";
|
||||
export * from "./helius_webhooks";
|
||||
export * from "./send_transaction_with_priority";
|
||||
174
src/tools/helius/send_transaction_with_priority.ts
Normal file
174
src/tools/helius/send_transaction_with_priority.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { SolanaAgentKit, PriorityFeeResponse } from "../../index";
|
||||
import {
|
||||
SystemProgram,
|
||||
Transaction,
|
||||
sendAndConfirmTransaction,
|
||||
ComputeBudgetProgram,
|
||||
PublicKey,
|
||||
LAMPORTS_PER_SOL,
|
||||
} from "@solana/web3.js";
|
||||
import {
|
||||
getAssociatedTokenAddress,
|
||||
createTransferInstruction,
|
||||
getMint,
|
||||
createAssociatedTokenAccountInstruction,
|
||||
} from "@solana/spl-token";
|
||||
import bs58 from "bs58";
|
||||
|
||||
/**
|
||||
* Sends a transaction with an estimated priority fee using the provided SolanaAgentKit.
|
||||
*
|
||||
* @param agent An instance of SolanaAgentKit containing connection, wallet, etc.
|
||||
* @param priorityLevel The priority level (e.g., "Min", "Low", "Medium", "High", "VeryHigh", or "UnsafeMax").
|
||||
* @param amount The amount of SOL to send (in SOL, not lamports).
|
||||
* @param to The recipient's PublicKey.
|
||||
* @returns The transaction signature (string) once confirmed along with the fee used.
|
||||
*/
|
||||
export async function sendTransactionWithPriorityFee(
|
||||
agent: SolanaAgentKit,
|
||||
priorityLevel: string,
|
||||
amount: number,
|
||||
to: PublicKey,
|
||||
splmintAddress?: PublicKey,
|
||||
): Promise<{ transactionId: string; fee: number }> {
|
||||
try {
|
||||
if (!splmintAddress) {
|
||||
const transaction = new Transaction();
|
||||
const { blockhash, lastValidBlockHeight } =
|
||||
await agent.connection.getLatestBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.lastValidBlockHeight = lastValidBlockHeight;
|
||||
transaction.feePayer = agent.wallet_address;
|
||||
|
||||
const transferIx = SystemProgram.transfer({
|
||||
fromPubkey: agent.wallet_address,
|
||||
toPubkey: to,
|
||||
lamports: amount * LAMPORTS_PER_SOL,
|
||||
});
|
||||
|
||||
transaction.add(transferIx);
|
||||
transaction.sign(agent.wallet);
|
||||
|
||||
const response = await fetch(
|
||||
`https://mainnet.helius-rpc.com/?api-key=${agent.config.HELIUS_API_KEY}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: "1",
|
||||
method: "getPriorityFeeEstimate",
|
||||
params: [
|
||||
{
|
||||
transaction: bs58.encode(transaction.serialize()),
|
||||
options: { priorityLevel: priorityLevel },
|
||||
},
|
||||
],
|
||||
} as PriorityFeeResponse),
|
||||
},
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
throw new Error("Error fetching priority fee:");
|
||||
}
|
||||
const feeEstimate: number = data.result.priorityFeeEstimate;
|
||||
|
||||
// Set the priority fee if applicable
|
||||
const computePriceIx = ComputeBudgetProgram.setComputeUnitPrice({
|
||||
microLamports: feeEstimate,
|
||||
});
|
||||
transaction.add(computePriceIx);
|
||||
|
||||
// Send the transaction and confirm
|
||||
const txSignature = await sendAndConfirmTransaction(
|
||||
agent.connection,
|
||||
transaction,
|
||||
[agent.wallet],
|
||||
);
|
||||
|
||||
return {
|
||||
transactionId: txSignature,
|
||||
fee: feeEstimate,
|
||||
};
|
||||
} else {
|
||||
const fromAta = await getAssociatedTokenAddress(
|
||||
splmintAddress,
|
||||
agent.wallet_address,
|
||||
);
|
||||
const toAta = await getAssociatedTokenAddress(splmintAddress, to);
|
||||
|
||||
const mintInfo = await getMint(agent.connection, splmintAddress);
|
||||
const adjustedAmount = amount * Math.pow(10, mintInfo.decimals);
|
||||
|
||||
const transaction = new Transaction();
|
||||
const { blockhash, lastValidBlockHeight } =
|
||||
await agent.connection.getLatestBlockhash();
|
||||
transaction.recentBlockhash = blockhash;
|
||||
transaction.lastValidBlockHeight = lastValidBlockHeight;
|
||||
transaction.feePayer = agent.wallet_address;
|
||||
|
||||
const response = await fetch(
|
||||
`https://mainnet.helius-rpc.com/?api-key=${agent.config.HELIUS_API_KEY}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: "1",
|
||||
method: "getPriorityFeeEstimate",
|
||||
params: [
|
||||
{
|
||||
transaction: bs58.encode(transaction.serialize()),
|
||||
options: { priorityLevel: priorityLevel },
|
||||
},
|
||||
],
|
||||
} as PriorityFeeResponse),
|
||||
},
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
throw new Error("Error fetching priority fee:");
|
||||
}
|
||||
const feeEstimate: number = data.result.priorityFeeEstimate;
|
||||
|
||||
transaction.add(
|
||||
ComputeBudgetProgram.setComputeUnitPrice({
|
||||
microLamports: feeEstimate,
|
||||
}),
|
||||
);
|
||||
|
||||
transaction.add(
|
||||
createAssociatedTokenAccountInstruction(
|
||||
agent.wallet_address,
|
||||
toAta,
|
||||
to,
|
||||
splmintAddress,
|
||||
),
|
||||
);
|
||||
|
||||
transaction.add(
|
||||
createTransferInstruction(
|
||||
fromAta,
|
||||
toAta,
|
||||
agent.wallet_address,
|
||||
adjustedAmount,
|
||||
),
|
||||
);
|
||||
|
||||
const txSignature = await sendAndConfirmTransaction(
|
||||
agent.connection,
|
||||
transaction,
|
||||
[agent.wallet],
|
||||
);
|
||||
|
||||
return {
|
||||
transactionId: txSignature,
|
||||
fee: feeEstimate,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to process transaction: ${error.message}`);
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,13 @@ export * from "./pumpfun";
|
||||
export * from "./pyth";
|
||||
export * from "./raydium";
|
||||
export * from "./rugcheck";
|
||||
export * from "./drift";
|
||||
export * from "./sendarcade";
|
||||
export * from "./solayer";
|
||||
export * from "./tensor";
|
||||
export * from "./3land";
|
||||
export * from "./tiplink";
|
||||
export * from "./lightprotocol";
|
||||
export * from "./squads_multisig";
|
||||
export * from "./squads";
|
||||
export * from "./helius";
|
||||
export * from "./voltr";
|
||||
|
||||
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";
|
||||
|
||||
@@ -10,7 +10,7 @@ const { Multisig } = multisig.accounts;
|
||||
* @returns {Promise<string>} - A promise that resolves to the transaction ID of the approved proposal.
|
||||
* @throws {Error} - Throws an error if the approval process fails.
|
||||
*/
|
||||
export async function approve_proposal(
|
||||
export async function multisig_approve_proposal(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
@@ -10,7 +10,7 @@ const { Multisig } = multisig.accounts;
|
||||
* @returns {Promise<string>} - The transaction ID of the created proposal.
|
||||
* @throws {Error} - Throws an error if the proposal creation fails.
|
||||
*/
|
||||
export async function create_proposal(
|
||||
export async function multisig_create_proposal(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
@@ -17,7 +17,7 @@ import * as multisig from "@sqds/multisig";
|
||||
* @param mint Optional mint address for SPL tokens
|
||||
* @returns Transaction signature
|
||||
*/
|
||||
export async function deposit_to_multisig(
|
||||
export async function multisig_deposit_to_treasury(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
vaultIndex?: number,
|
||||
@@ -10,7 +10,7 @@ const { Multisig } = multisig.accounts;
|
||||
* @returns {Promise<string>} - A promise that resolves to the transaction signature string.
|
||||
* @throws {Error} - Throws an error if the transaction execution fails.
|
||||
*/
|
||||
export async function execute_transaction(
|
||||
export async function multisig_execute_proposal(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from "./approve_proposal";
|
||||
export * from "./create_multisig";
|
||||
export * from "./create_proposal";
|
||||
export * from "./deposit_to_multisig";
|
||||
export * from "./approve_proposal";
|
||||
export * from "./deposit_to_treasury";
|
||||
export * from "./execute_proposal";
|
||||
export * from "./reject_proposal";
|
||||
export * from "./transfer_from_multisig";
|
||||
export * from "./transfer_from_treasury";
|
||||
@@ -10,7 +10,7 @@ const { Multisig } = multisig.accounts;
|
||||
* @returns A promise that resolves to the transaction ID of the rejection transaction.
|
||||
* @throws Will throw an error if the transaction fails.
|
||||
*/
|
||||
export async function reject_proposal(
|
||||
export async function multisig_reject_proposal(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
@@ -23,7 +23,7 @@ const { Multisig } = multisig.accounts;
|
||||
* @param mint - Optional mint address for SPL tokens.
|
||||
* @returns Transaction signature.
|
||||
*/
|
||||
export async function transfer_from_multisig(
|
||||
export async function multisig_transfer_from_treasury(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
to: PublicKey,
|
||||
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;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ export interface Config {
|
||||
JUPITER_FEE_BPS?: number;
|
||||
FLASH_PRIVILEGE?: string;
|
||||
FLEXLEND_API_KEY?: string;
|
||||
HELIUS_API_KEY?: string;
|
||||
}
|
||||
|
||||
export interface Creator {
|
||||
@@ -238,3 +239,25 @@ export interface FlashCloseTradeParams {
|
||||
token: string;
|
||||
side: "long" | "short";
|
||||
}
|
||||
|
||||
export interface HeliusWebhookResponse {
|
||||
webhookURL: string;
|
||||
webhookID: string;
|
||||
}
|
||||
export interface HeliusWebhookIdResponse {
|
||||
wallet: string;
|
||||
webhookURL: string;
|
||||
transactionTypes: string[];
|
||||
accountAddresses: string[];
|
||||
webhookType: string;
|
||||
}
|
||||
|
||||
export interface PriorityFeeResponse {
|
||||
jsonrpc: string;
|
||||
id: string;
|
||||
method: string;
|
||||
params: Array<{
|
||||
transaction: string;
|
||||
options: { priorityLevel: string };
|
||||
}>;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ import {
|
||||
TransactionInstruction,
|
||||
TransactionMessage,
|
||||
VersionedTransaction,
|
||||
Transaction,
|
||||
} from "@solana/web3.js";
|
||||
import { ComputeBudgetProgram } from "@solana/web3.js";
|
||||
import bs58 from "bs58";
|
||||
import { PriorityFeeResponse } from "../types/index";
|
||||
|
||||
const feeTiers = {
|
||||
min: 0.01,
|
||||
@@ -28,7 +31,8 @@ export async function getComputeBudgetInstructions(
|
||||
computeBudgetLimitInstruction: TransactionInstruction;
|
||||
computeBudgetPriorityFeeInstructions: TransactionInstruction;
|
||||
}> {
|
||||
const blockhash = (await agent.connection.getLatestBlockhash()).blockhash;
|
||||
const { blockhash, lastValidBlockHeight } =
|
||||
await agent.connection.getLatestBlockhash();
|
||||
const messageV0 = new TransactionMessage({
|
||||
payerKey: agent.wallet_address,
|
||||
recentBlockhash: blockhash,
|
||||
@@ -47,15 +51,65 @@ export async function getComputeBudgetInstructions(
|
||||
units: safeComputeUnits,
|
||||
});
|
||||
|
||||
const priorityFee = await agent.connection
|
||||
.getRecentPrioritizationFees()
|
||||
.then(
|
||||
(fees) =>
|
||||
fees.sort((a, b) => a.prioritizationFee - b.prioritizationFee)[
|
||||
Math.floor(fees.length * feeTiers[feeTier])
|
||||
].prioritizationFee,
|
||||
let priorityFee: number;
|
||||
|
||||
if (agent.config.HELIUS_API_KEY) {
|
||||
// Create and set up a legacy transaction for Helius fee estimation
|
||||
const legacyTransaction = new Transaction();
|
||||
legacyTransaction.recentBlockhash = blockhash;
|
||||
legacyTransaction.lastValidBlockHeight = lastValidBlockHeight;
|
||||
legacyTransaction.feePayer = agent.wallet_address;
|
||||
|
||||
// Add the compute budget instruction and original instructions
|
||||
legacyTransaction.add(computeBudgetLimitInstruction, ...instructions);
|
||||
|
||||
// Sign the transaction
|
||||
legacyTransaction.sign(agent.wallet);
|
||||
|
||||
// Use Helius API for priority fee calculation
|
||||
const response = await fetch(
|
||||
`https://mainnet.helius-rpc.com/?api-key=${agent.config.HELIUS_API_KEY}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: "1",
|
||||
method: "getPriorityFeeEstimate",
|
||||
params: [
|
||||
{
|
||||
transaction: bs58.encode(legacyTransaction.serialize()),
|
||||
options: {
|
||||
priorityLevel:
|
||||
feeTier === "min"
|
||||
? "Min"
|
||||
: feeTier === "mid"
|
||||
? "Medium"
|
||||
: "High",
|
||||
},
|
||||
},
|
||||
],
|
||||
} as PriorityFeeResponse),
|
||||
},
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
throw new Error("Error fetching priority fee from Helius API");
|
||||
}
|
||||
priorityFee = data.result.priorityFeeEstimate;
|
||||
} else {
|
||||
// Use default implementation for priority fee calculation
|
||||
priorityFee = await agent.connection
|
||||
.getRecentPrioritizationFees()
|
||||
.then(
|
||||
(fees) =>
|
||||
fees.sort((a, b) => a.prioritizationFee - b.prioritizationFee)[
|
||||
Math.floor(fees.length * feeTiers[feeTier])
|
||||
].prioritizationFee,
|
||||
);
|
||||
}
|
||||
|
||||
const computeBudgetPriorityFeeInstructions =
|
||||
ComputeBudgetProgram.setComputeUnitPrice({
|
||||
microLamports: priorityFee,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user