mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-30 07:36:44 +00:00
fix: drift vault deposits and withdrawals
This commit is contained in:
29
README.md
29
README.md
@@ -56,6 +56,7 @@ Anyone - whether an SF-based AI researcher or a crypto-native builder - can brin
|
|||||||
- Pyth Price feeds for fetching Asset Prices
|
- Pyth Price feeds for fetching Asset Prices
|
||||||
- Register/resolve Alldomains
|
- Register/resolve Alldomains
|
||||||
- Perpetuals Trading with Adrena Protocol
|
- Perpetuals Trading with Adrena Protocol
|
||||||
|
- Drift Vaults, Perps, Lending and Borrowing
|
||||||
|
|
||||||
- **Solana Blinks**
|
- **Solana Blinks**
|
||||||
- Lending by Lulo (Best APR for USDC)
|
- Lending by Lulo (Best APR for USDC)
|
||||||
@@ -309,6 +310,34 @@ const signature = await agent.closePerpTradeLong({
|
|||||||
const { signature } = await agent.closeEmptyTokenAccounts();
|
const { signature } = await agent.closeEmptyTokenAccounts();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Create a Drift account
|
||||||
|
|
||||||
|
Create a drift account with an initial token deposit.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const result = await agent.createDriftUserAccount()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create a Drift Vault
|
||||||
|
|
||||||
|
Create a drift vault.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const signature = await agent.createDriftVault({
|
||||||
|
name: "my-drift-vault",
|
||||||
|
marketName: "USDC-SPOT",
|
||||||
|
redeemPeriod: 1, // in days
|
||||||
|
maxTokens: 100000, // in token units e.g 100000 USDC
|
||||||
|
minDepositAmount: 5, // in token units e.g 5 USDC
|
||||||
|
managementFee: 1, // 1%
|
||||||
|
profitShare: 10, // 10%
|
||||||
|
hurdleRate: 5, // 5%
|
||||||
|
permissioned: false, // public vault or whitelist
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deposit into a Drift Vault
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### LangGraph Multi-Agent System
|
### LangGraph Multi-Agent System
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { z } from "zod";
|
|||||||
import type { Action } from "../../types";
|
import type { Action } from "../../types";
|
||||||
import { getVaultInfo } from "../../tools";
|
import { getVaultInfo } from "../../tools";
|
||||||
import type { SolanaAgentKit } from "../../agent";
|
import type { SolanaAgentKit } from "../../agent";
|
||||||
import { decodeName } from "@drift-labs/vaults-sdk";
|
|
||||||
import { MainnetSpotMarkets, PERCENTAGE_PRECISION } from "@drift-labs/sdk";
|
|
||||||
|
|
||||||
const vaultInfoAction: Action = {
|
const vaultInfoAction: Action = {
|
||||||
name: "DRIFT_VAULT_INFO",
|
name: "DRIFT_VAULT_INFO",
|
||||||
@@ -13,7 +11,7 @@ const vaultInfoAction: Action = {
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
input: {
|
input: {
|
||||||
vaultName: "test-vault",
|
vaultNameOrAddress: "test-vault",
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
status: "success",
|
status: "success",
|
||||||
@@ -35,11 +33,11 @@ const vaultInfoAction: Action = {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
vaultName: z.string(),
|
vaultNameOrAddress: z.string().describe("Name or address of the vault"),
|
||||||
}),
|
}),
|
||||||
handler: async (agent: SolanaAgentKit, input) => {
|
handler: async (agent: SolanaAgentKit, input) => {
|
||||||
try {
|
try {
|
||||||
const vaultInfo = await getVaultInfo(agent, input.vaultName as string);
|
const vaultInfo = await getVaultInfo(agent, input.vaultNameOrAddress);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
VaultAccount,
|
VaultAccount,
|
||||||
WithdrawUnit,
|
WithdrawUnit,
|
||||||
|
decodeName,
|
||||||
encodeName,
|
encodeName,
|
||||||
getVaultAddressSync,
|
getVaultAddressSync,
|
||||||
getVaultDepositorAddressSync,
|
getVaultDepositorAddressSync,
|
||||||
@@ -65,9 +66,13 @@ async function getOrCreateVaultDepositor(agent: SolanaAgentKit, vault: string) {
|
|||||||
return vaultDepositor;
|
return vaultDepositor;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// @ts-expect-error - error message is a string
|
// @ts-expect-error - error message is a string
|
||||||
if (e.message === "Account not found") {
|
if (e.message.includes("Account does not exist")) {
|
||||||
await vaultClient.initializeVaultDepositor(vaultDepositor);
|
await vaultClient.initializeVaultDepositor(
|
||||||
|
vaultPublicKey,
|
||||||
|
agent.wallet.publicKey,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
await cleanUp();
|
await cleanUp();
|
||||||
return vaultDepositor;
|
return vaultDepositor;
|
||||||
}
|
}
|
||||||
@@ -280,18 +285,29 @@ export async function updateVault(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
* Get information on a particular vault given its name
|
||||||
* @param agent
|
* @param agent
|
||||||
* @param vaultName
|
* @param vaultNameOrAddress
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export async function getVaultInfo(agent: SolanaAgentKit, vaultName: string) {
|
export async function getVaultInfo(
|
||||||
|
agent: SolanaAgentKit,
|
||||||
|
vaultNameOrAddress: string,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const { vaultClient, cleanUp } = await initClients(agent);
|
const { vaultClient, cleanUp } = await initClients(agent);
|
||||||
const vaultPublicKey = getVaultAddressSync(
|
const vaultPublicKey = validateAndEncodeAddress(
|
||||||
vaultClient.program.programId,
|
vaultNameOrAddress,
|
||||||
encodeName(vaultName),
|
vaultClient.program.programId.toBase58(),
|
||||||
);
|
);
|
||||||
const [vaultDetails, vaultBalance] = await Promise.all([
|
const [vaultDetails, vaultBalance] = await Promise.all([
|
||||||
vaultClient.getVault(vaultPublicKey),
|
vaultClient.getVault(vaultPublicKey),
|
||||||
@@ -302,7 +318,7 @@ export async function getVaultInfo(agent: SolanaAgentKit, vaultName: string) {
|
|||||||
|
|
||||||
const spotToken = MainnetSpotMarkets[vaultDetails.spotMarketIndex];
|
const spotToken = MainnetSpotMarkets[vaultDetails.spotMarketIndex];
|
||||||
const data = {
|
const data = {
|
||||||
name: vaultName,
|
name: decodeName(vaultDetails.name),
|
||||||
delegate: vaultDetails.delegate.toBase58(),
|
delegate: vaultDetails.delegate.toBase58(),
|
||||||
address: vaultPublicKey.toBase58(),
|
address: vaultPublicKey.toBase58(),
|
||||||
marketName: `${spotToken.symbol}-SPOT`,
|
marketName: `${spotToken.symbol}-SPOT`,
|
||||||
@@ -346,9 +362,10 @@ export async function depositIntoVault(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const vaultPublicKey = new PublicKey(vault);
|
const vaultPublicKey = new PublicKey(vault);
|
||||||
const [isOwned, vaultDetails] = await Promise.all([
|
const [isOwned, vaultDetails, vaultDepositor] = await Promise.all([
|
||||||
getIsOwned(agent, vault),
|
getIsOwned(agent, vault),
|
||||||
vaultClient.getVault(vaultPublicKey),
|
vaultClient.getVault(vaultPublicKey),
|
||||||
|
getOrCreateVaultDepositor(agent, vault),
|
||||||
]);
|
]);
|
||||||
const spotMarket = driftClient.getSpotMarketAccount(
|
const spotMarket = driftClient.getSpotMarketAccount(
|
||||||
vaultDetails.spotMarketIndex,
|
vaultDetails.spotMarketIndex,
|
||||||
@@ -365,7 +382,6 @@ export async function depositIntoVault(
|
|||||||
return await vaultClient.managerDeposit(vaultPublicKey, amountBN);
|
return await vaultClient.managerDeposit(vaultPublicKey, amountBN);
|
||||||
}
|
}
|
||||||
|
|
||||||
const vaultDepositor = await getOrCreateVaultDepositor(agent, vault);
|
|
||||||
const tx = await vaultClient.deposit(vaultDepositor, amountBN);
|
const tx = await vaultClient.deposit(vaultDepositor, amountBN);
|
||||||
|
|
||||||
await cleanUp();
|
await cleanUp();
|
||||||
@@ -396,7 +412,7 @@ export async function requestWithdrawalFromVault(
|
|||||||
if (isOwned) {
|
if (isOwned) {
|
||||||
return await vaultClient.managerRequestWithdraw(
|
return await vaultClient.managerRequestWithdraw(
|
||||||
vaultPublicKey,
|
vaultPublicKey,
|
||||||
new BN(amount.toFixed(0)),
|
numberToSafeBN(amount, QUOTE_PRECISION),
|
||||||
WithdrawUnit.TOKEN,
|
WithdrawUnit.TOKEN,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -405,7 +421,7 @@ export async function requestWithdrawalFromVault(
|
|||||||
|
|
||||||
const tx = await vaultClient.requestWithdraw(
|
const tx = await vaultClient.requestWithdraw(
|
||||||
vaultDepositor,
|
vaultDepositor,
|
||||||
new BN(amount.toFixed(0)),
|
numberToSafeBN(amount, QUOTE_PRECISION),
|
||||||
WithdrawUnit.TOKEN,
|
WithdrawUnit.TOKEN,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user