@drift-labs/vaults-sdk 0.1.211 → 0.1.212

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli/cli.ts CHANGED
@@ -74,7 +74,8 @@ program
74
74
  .command("manager-request-withdraw")
75
75
  .description("Make a withdraw request from your vault")
76
76
  .addOption(new Option("--vault-address <address>", "Address of the vault to withdraw from").makeOptionMandatory(true))
77
- .addOption(new Option("--shares <shares>", "Amount of shares to withdraw (raw precision, as expected by contract)").makeOptionMandatory(true))
77
+ .addOption(new Option("--shares <shares>", "Amount of shares to withdraw (raw precision, as expected by contract)").makeOptionMandatory(false))
78
+ .addOption(new Option("--amount <amount>", "Amount of spot asset to withdraw (human format, 5 for 5 USDC)").makeOptionMandatory(false))
78
79
  .action((opts) => managerRequestWithdraw(program, opts));
79
80
  program
80
81
  .command("manager-update-vault")
@@ -113,6 +114,7 @@ program
113
114
  .command("apply-profit-share-all")
114
115
  .description("Turn the profit share crank for all depositors")
115
116
  .addOption(new Option("--vault-address <address>", "Address of the vault to view").makeOptionMandatory(true))
117
+ .addOption(new Option("--threshold <amount>", "Minimum threshold (in spot tokens) before profit share is applied").default("1000", "default is 1000"))
116
118
  .action((opts) => applyProfitShare(program, opts));
117
119
  program
118
120
  .command("init-vault-depositor")
@@ -142,6 +144,8 @@ program
142
144
  .command("force-withdraw")
143
145
  .description("Forces the vault to send out a withdraw after the redeem period has passed")
144
146
  .addOption(new Option("--vault-depositor-address <vaultDepositorAddress>", "VaultDepositor address").makeOptionMandatory(false))
147
+ .addOption(new Option("--vault-depositor-authority <vaultDepositorAuthority>", "Authority address of VaultDepositor, must also provide --vault-address").makeOptionMandatory(false))
148
+ .addOption(new Option("--vault-address <vaultAddress>", "Address of vault, must required if only --vault-deposit-authority is provided").makeOptionMandatory(false))
145
149
  .action((opts) => forceWithdraw(program, opts));
146
150
  program
147
151
  .command("decode-logs")
@@ -152,6 +156,8 @@ program
152
156
  .command("check-invariants")
153
157
  .description("Perform sanity checks on vault/depositor invariants")
154
158
  .addOption(new Option("--vault-address <address>", "Vault address").makeOptionMandatory(true))
159
+ .addOption(new Option("--csv", "Output to csv"))
160
+
155
161
  .action((opts) => vaultInvariantChecks(program, opts));
156
162
 
157
163
  program.parseAsync().then(() => {
@@ -4,6 +4,9 @@ import {
4
4
  Command
5
5
  } from "commander";
6
6
  import { getCommandContext } from "../utils";
7
+ import { VaultDepositor, calculateApplyProfitShare } from "../../src";
8
+ import { BN, TEN, ZERO, numberToSafeBN } from "@drift-labs/sdk";
9
+ import { ProgramAccount } from "@coral-xyz/anchor";
7
10
 
8
11
  export const applyProfitShare = async (program: Command, cmdOpts: OptionValues) => {
9
12
 
@@ -16,18 +19,42 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
16
19
  }
17
20
 
18
21
  const {
19
- driftVault
22
+ driftVault,
23
+ driftClient,
20
24
  } = await getCommandContext(program, true);
21
25
 
22
- const vdToRealizeProfit = await driftVault.getAllVaultDepositorsWithNoWithdrawRequest(vaultAddress);
23
- console.log(`Applying profit share for ${vdToRealizeProfit.length} depositors...`);
26
+ const vault = await driftVault.getVault(vaultAddress);
27
+ const vdWithNoWithdrawRequests = await driftVault.getAllVaultDepositorsWithNoWithdrawRequest(vaultAddress);
28
+ const vaultEquity = await driftVault.calculateVaultEquity({ vault });
24
29
 
25
- const chunkSize = 6;
30
+ const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
31
+ if (!spotMarket) {
32
+ throw new Error(`Spot market account ${vault.spotMarketIndex} has not been loaded`);
33
+ }
34
+ const spotMarketPrecision = TEN.pow(new BN(spotMarket.decimals));
35
+ const thresholdNumber = parseFloat(cmdOpts.threshold);
36
+ const thresholdBN = numberToSafeBN(thresholdNumber, spotMarketPrecision);
37
+ let pendingProfitShareToRealize = ZERO;
38
+ const vdWithPendingProfitShare = vdWithNoWithdrawRequests.filter((vd: ProgramAccount<VaultDepositor>) => {
39
+ const pendingProfitShares = calculateApplyProfitShare(vd.account, vaultEquity, vault);
40
+ const doRealize = pendingProfitShares.profitShareAmount.gt(thresholdBN);
41
+ if (doRealize) {
42
+ pendingProfitShareToRealize = pendingProfitShareToRealize.add(pendingProfitShares.profitShareAmount);
43
+ return true;
44
+ } else {
45
+ return false;
46
+ }
47
+ });
48
+
49
+ console.log(`${vdWithPendingProfitShare.length}/${vdWithNoWithdrawRequests.length} depositors have pending profit shares above threshold ${cmdOpts.threshold} (${thresholdBN.toString()})`);
50
+ console.log(`Applying profit share for ${vdWithPendingProfitShare.length} depositors.`);
51
+
52
+ const chunkSize = 5;
26
53
  const ixChunks: Array<Array<TransactionInstruction>> = [];
27
- for (let i = 0; i < vdToRealizeProfit.length; i += chunkSize) {
28
- const chunk = vdToRealizeProfit.slice(i, i + chunkSize);
29
- const ixs = await Promise.all(chunk.map((vaultDepositor) => {
30
- return driftVault.getApplyProfitShareIx(vaultAddress, vaultDepositor.publicKey);
54
+ for (let i = 0; i < vdWithPendingProfitShare.length; i += chunkSize) {
55
+ const chunk = vdWithPendingProfitShare.slice(i, i + chunkSize);
56
+ const ixs = await Promise.all(chunk.map((vd: ProgramAccount<VaultDepositor>) => {
57
+ return driftVault.getApplyProfitShareIx(vaultAddress, vd.publicKey);
31
58
  }));
32
59
 
33
60
  ixChunks.push(ixs);
@@ -36,6 +63,7 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
36
63
 
37
64
  for (let i = 0; i < ixChunks.length; i++) {
38
65
  const ixs = ixChunks[i];
66
+ console.log(`Sending chunk ${i + 1}/${ixChunks.length}`);
39
67
  try {
40
68
  ixs.unshift(ComputeBudgetProgram.setComputeUnitLimit({
41
69
  units: 1_400_000,
@@ -4,21 +4,50 @@ import {
4
4
  Command
5
5
  } from "commander";
6
6
  import { getCommandContext } from "../utils";
7
+ import { getVaultDepositorAddressSync } from "../../src/addresses";
8
+ import { VAULT_PROGRAM_ID } from "../../src";
7
9
 
8
10
  export const forceWithdraw = async (program: Command, cmdOpts: OptionValues) => {
9
11
 
10
- let vaultDepositorAddress: PublicKey;
12
+ let vaultDepositorAddress: PublicKey | undefined;
11
13
  try {
12
14
  vaultDepositorAddress = new PublicKey(cmdOpts.vaultDepositorAddress as string);
13
15
  } catch (err) {
14
- console.error("Invalid vault depositor address");
15
- process.exit(1);
16
+ console.error("Failed to parse vaultDepositorAddress trying vaultDepositorAuthority");
17
+ }
18
+
19
+ let vaultDepositorAuthority: PublicKey | undefined;
20
+ try {
21
+ vaultDepositorAuthority = new PublicKey(cmdOpts.vaultDepositorAuthority as string);
22
+ } catch (err) {
23
+ console.error("Failed to parse vaultDepositorAuthority");
24
+ }
25
+
26
+ if (!vaultDepositorAuthority && !vaultDepositorAddress) {
27
+ throw new Error("VaultDepositor address or authority must be provided");
28
+ }
29
+
30
+ let vaultAddress: PublicKey | undefined;
31
+ if (vaultDepositorAuthority && !vaultDepositorAddress) {
32
+ try {
33
+ vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
34
+ } catch (err) {
35
+ throw new Error("Must provide --vault-address if only --vault-depositor-authority is provided");
36
+ }
37
+ vaultDepositorAddress = getVaultDepositorAddressSync(
38
+ VAULT_PROGRAM_ID,
39
+ vaultAddress,
40
+ vaultDepositorAuthority);
41
+ }
42
+
43
+ if (!vaultDepositorAddress) {
44
+ throw new Error("Failed to derive vault depositor address");
16
45
  }
17
46
 
18
47
  const {
19
48
  driftVault
20
49
  } = await getCommandContext(program, true);
21
50
 
22
- const tx = await driftVault.forceWithdraw(vaultDepositorAddress);
51
+ const tx = await driftVault.forceWithdraw(vaultDepositorAddress, false);
23
52
  console.log(`Forced withdraw from vault: ${tx}`);
24
53
  };
@@ -1,4 +1,4 @@
1
- import { BN } from "@drift-labs/sdk";
1
+ import { BN, TEN, decodeName, numberToSafeBN } from "@drift-labs/sdk";
2
2
  import { PublicKey } from "@solana/web3.js";
3
3
  import {
4
4
  OptionValues,
@@ -18,9 +18,35 @@ export const managerRequestWithdraw = async (program: Command, cmdOpts: OptionVa
18
18
  }
19
19
 
20
20
  const {
21
- driftVault
21
+ driftClient, driftVault
22
22
  } = await getCommandContext(program, true);
23
23
 
24
- const tx = await driftVault.managerRequestWithdraw(vaultAddress, new BN(cmdOpts.shares), WithdrawUnit.SHARES);
25
- console.log(`Requested to withraw ${cmdOpts.shares} shares as vault manager: https://solscan.io/tx/${tx}`);
24
+ if (!cmdOpts.shares && !cmdOpts.amount) {
25
+ console.error("One of --shares or --amount must be provided.");
26
+ process.exit(1);
27
+ }
28
+
29
+ if (cmdOpts.shares && !cmdOpts.amount) {
30
+ const tx = await driftVault.managerRequestWithdraw(vaultAddress, new BN(cmdOpts.shares), WithdrawUnit.SHARES);
31
+ console.log(`Requested to withraw ${cmdOpts.shares} shares as vault manager: https://solscan.io/tx/${tx}`);
32
+ } else if (cmdOpts.amount && !cmdOpts.shares) {
33
+ const vault = await driftVault.getVault(vaultAddress);
34
+ const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
35
+ if (!spotMarket) {
36
+ console.error("Error: Spot market not found");
37
+ process.exit(1);
38
+ }
39
+ const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
40
+ const amount = parseFloat(cmdOpts.amount);
41
+ const amountBN = numberToSafeBN(amount, spotPrecision);
42
+ console.log(amount);
43
+ console.log(amountBN.toString());
44
+ const tx = await driftVault.managerRequestWithdraw(vaultAddress, amountBN, WithdrawUnit.TOKEN);
45
+ console.log(`Requested to withdraw ${amount} ${decodeName(spotMarket.name)} as vault manager: https://solscan.io/tx/${tx}`);
46
+
47
+ } else {
48
+ console.error("Error: Either shares or amount must be provided, but not both.");
49
+ process.exit(1);
50
+ }
51
+
26
52
  };
@@ -1,4 +1,4 @@
1
- import { PublicKey } from "@solana/web3.js";
1
+ import { ComputeBudgetProgram, PublicKey } from "@solana/web3.js";
2
2
  import {
3
3
  OptionValues,
4
4
  Command
@@ -119,6 +119,31 @@ export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues
119
119
  permissioned,
120
120
  };
121
121
 
122
- const tx = await driftVault.managerUpdateVault(vaultAddress, newParams);
123
- console.log(`Updated vault params as vault manager: https://solscan.io/tx/${tx}`);
122
+ const preIxs = [
123
+ ComputeBudgetProgram.setComputeUnitLimit({
124
+ units: 600_000,
125
+ }),
126
+ ComputeBudgetProgram.setComputeUnitPrice({
127
+ microLamports: 100_000,
128
+ }),
129
+ ];
130
+
131
+ let done = false;
132
+ while (!done) {
133
+ try {
134
+ const tx = await driftVault.managerUpdateVault(vaultAddress, newParams, preIxs, { maxRetries: 0 });
135
+ console.log(`Updated vault params as vault manager: https://solana.fm/tx/${tx}`);
136
+ done = true;
137
+ break;
138
+ } catch (e) {
139
+ const err = e as Error;
140
+ if (err.message.includes('TransactionExpiredTimeoutError')) {
141
+ console.log(err.message);
142
+ console.log('Transaction timeout. Retrying...');
143
+ await new Promise(resolve => setTimeout(resolve, 5000));
144
+ } else {
145
+ throw err;
146
+ }
147
+ }
148
+ }
124
149
  };
@@ -4,10 +4,11 @@ import {
4
4
  Command
5
5
  } from "commander";
6
6
  import { getCommandContext } from "../utils";
7
- import { BN, convertToNumber } from "@drift-labs/sdk";
7
+ import { BN, QUOTE_PRECISION, ZERO, convertToNumber } from "@drift-labs/sdk";
8
8
  import {
9
9
  calculateApplyProfitShare,
10
10
  } from "../../src/math";
11
+ import { VaultDepositor } from "../../src";
11
12
 
12
13
  export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValues) => {
13
14
 
@@ -37,42 +38,51 @@ export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValu
37
38
  const spotMarket = driftVault.driftClient.getSpotMarketAccount(vault.spotMarketIndex);
38
39
  const spotPrecision = new BN(10).pow(new BN(spotMarket!.decimals));
39
40
 
40
- let allVaultDepositors = await driftVault.getAllVaultDepositors(vaultAddress);
41
+ const allVaultDepositors = await driftVault.getAllVaultDepositors(vaultAddress);
42
+ const approxSlot = await driftVault.driftClient.connection.getSlot();
43
+ const now = Date.now();
41
44
 
42
- // Sort allVaultDepositors by vaultShares in descending order
43
- allVaultDepositors = allVaultDepositors.sort((a, b) => b.account.vaultShares.cmp(a.account.vaultShares));
45
+ let nonZeroDepositors = allVaultDepositors.filter(vd => vd.account.vaultShares.gt(new BN(0)));
46
+ nonZeroDepositors = nonZeroDepositors.sort((a, b) => b.account.vaultShares.cmp(a.account.vaultShares));
44
47
 
45
48
  let totalUserShares = new BN(0);
46
49
  let totalUserProfitSharePaid = new BN(0);
47
50
  let totalUserProfitShareSharesPaid = new BN(0);
48
51
  let totalPendingProfitShareAmount = new BN(0);
52
+ let totalPendingProfitShareShares = new BN(0);
49
53
 
50
- for (const vd of allVaultDepositors) {
51
- totalUserShares = totalUserShares.add(vd.account.vaultShares);
52
- if (!vd.account.lastWithdrawRequest.shares.eq(new BN(0))) {
53
- const withdrawRequested = vd.account.lastWithdrawRequest.ts.toNumber();
54
+ console.log(`Vault ${vaultAddress} vd and invariant check at approx slot: ${approxSlot}, date: ${new Date(now).toLocaleString()}`);
55
+ console.log(`Depositors with 0 shares: ${allVaultDepositors.length - nonZeroDepositors.length}/${allVaultDepositors.length}`);
56
+ for (const vd of nonZeroDepositors) {
57
+ const vdAccount = vd.account as VaultDepositor;
58
+
59
+ totalUserShares = totalUserShares.add(vdAccount.vaultShares);
60
+ const vdAuth = vdAccount.authority.toBase58();
61
+ const vdPct = vdAccount.vaultShares.toNumber() / vault.totalShares.toNumber();
62
+ console.log(`- ${vdAuth} has ${vdAccount.vaultShares.toNumber()} shares (${(vdPct * 100.0).toFixed(2)}% of vault)`);
63
+
64
+ if (!vdAccount.lastWithdrawRequest.shares.eq(new BN(0))) {
65
+ const withdrawRequested = vdAccount.lastWithdrawRequest.ts.toNumber();
54
66
  const secToWithdrawal = withdrawRequested + vault.redeemPeriod.toNumber() - Date.now() / 1000;
55
67
  const withdrawAvailable = secToWithdrawal < 0;
56
-
57
- const pct = vd.account.lastWithdrawRequest.shares.toNumber() / vd.account.vaultShares.toNumber();
58
- console.log(`Vd has withdrawal ${vd.publicKey.toBase58()} (auth: ${vd.account.authority.toBase58()}): ${vd.account.lastWithdrawRequest.shares.toString()} ($${convertToNumber(vd.account.lastWithdrawRequest.value, spotPrecision)}), ${(pct * 100.00).toFixed(2)}%`);
59
- console.log(` - requested at: ${new Date(withdrawRequested * 1000).toISOString()}`);
68
+ const pct = vdAccount.lastWithdrawRequest.shares.toNumber() / vd.account.vaultShares.toNumber();
60
69
  const daysUntilWithdraw = Math.floor(secToWithdrawal / 86400);
61
70
  const hoursUntilWithdraw = Math.floor((secToWithdrawal % 86400) / 3600);
62
- console.log(` - can withdraw in: ${daysUntilWithdraw} days and ${hoursUntilWithdraw} hours ${withdrawAvailable ? "<--- WITHDRAWABLE" : ""}`);
63
- }
64
71
 
65
- if (!vd.account.cumulativeProfitShareAmount.eq(new BN(0))) {
66
- // const profitSharePaid = vd.account.profitShareFeePaid.toNumber() / vd.account.cumulativeProfitShareAmount.toNumber();
67
- // console.log(`Profit share paid: ${vd.publicKey.toBase58()} (auth: ${vd.account.authority.toBase58()}): ${Math.ceil(profitSharePaid * 100.0)}%`);
72
+ console.log(` - pending withdrawal: ${vdAccount.lastWithdrawRequest.shares.toString()} ($${convertToNumber(vd.account.lastWithdrawRequest.value, spotPrecision)}), ${(pct * 100.00).toFixed(2)}% of their deposit ${withdrawAvailable ? "<--- WITHDRAWABLE" : ""}`);
73
+ console.log(` - requested at: ${new Date(withdrawRequested * 1000).toISOString()}`);
74
+ console.log(` - can withdraw in: ${daysUntilWithdraw} days and ${hoursUntilWithdraw} hours`);
68
75
  }
69
- totalUserProfitSharePaid = totalUserProfitSharePaid.add(vd.account.profitShareFeePaid);
70
- totalUserProfitShareSharesPaid = totalUserProfitShareSharesPaid.add(vd.account.cumulativeProfitShareAmount);
71
76
 
72
- const pendingProfitShares = calculateApplyProfitShare(vd.account, vaultEquity, vault);
73
- totalPendingProfitShareAmount = totalPendingProfitShareAmount.add(pendingProfitShares.profitShareAmount);
77
+ totalUserProfitSharePaid = totalUserProfitSharePaid.add(vdAccount.profitShareFeePaid);
78
+ totalUserProfitShareSharesPaid = totalUserProfitShareSharesPaid.add(vdAccount.cumulativeProfitShareAmount);
74
79
 
75
- console.log(`Pending profit shares: ${vd.publicKey.toBase58()} (auth: ${vd.account.authority.toBase58()}): $${convertToNumber(pendingProfitShares.profitShareAmount, spotPrecision)}`);
80
+ const pendingProfitShares = calculateApplyProfitShare(vdAccount, vaultEquity, vault);
81
+ if (pendingProfitShares.profitShareAmount.gt(ZERO)) {
82
+ totalPendingProfitShareAmount = totalPendingProfitShareAmount.add(pendingProfitShares.profitShareAmount);
83
+ totalPendingProfitShareShares = totalPendingProfitShareShares.add(pendingProfitShares.profitShareShares);
84
+ console.log(` - pending profit share amount: $${convertToNumber(pendingProfitShares.profitShareAmount, spotPrecision)}`);
85
+ }
76
86
  }
77
87
  console.log(`==== Vault Depositor Shares == vault.user_shares ====`);
78
88
  console.log(`total vd shares: ${totalUserShares.toString()}`);
@@ -88,4 +98,17 @@ export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValu
88
98
  console.log(``);
89
99
  console.log(`==== Pending profit shares to realize ====`);
90
100
  console.log(`${convertToNumber(totalPendingProfitShareAmount, spotPrecision)}`);
101
+ console.log(`csv: ${cmdOpts.csv}`);
102
+
103
+ console.log(``);
104
+ console.log(`==== Manager share ====`);
105
+ console.log(` Vault total shares: ${vault.totalShares.toNumber()}`);
106
+ const managerShares = vault.totalShares.sub(vault.userShares);
107
+ const managerSharePct = managerShares.toNumber() / vault.totalShares.toNumber();
108
+ const managerShareWithPendingPct = managerShares.add(totalPendingProfitShareShares).toNumber() / vault.totalShares.toNumber();
109
+ console.log(` Manager shares: ${managerShares.toString()} (${(managerSharePct * 100.0).toFixed(4)}%)`);
110
+ const vaultEquityNum = convertToNumber(vaultEquity, QUOTE_PRECISION);
111
+ console.log(`vaultEquity (USDC): $${vaultEquityNum}`);
112
+ console.log(`manager share (w/o pending) (USDC): $${managerSharePct * vaultEquityNum}`);
113
+ console.log(`manager share (with pending) (USDC): $${managerShareWithPendingPct * vaultEquityNum}`);
91
114
  };
@@ -4,7 +4,6 @@ import {
4
4
  Command
5
5
  } from "commander";
6
6
  import { getCommandContext, printVault } from "../utils";
7
- import { BN, PRICE_PRECISION, QUOTE_PRECISION, TEN, convertToNumber, decodeName } from "@drift-labs/sdk";
8
7
 
9
8
  export const viewVault = async (program: Command, cmdOpts: OptionValues) => {
10
9
 
@@ -22,12 +21,8 @@ export const viewVault = async (program: Command, cmdOpts: OptionValues) => {
22
21
  } = await getCommandContext(program, false);
23
22
 
24
23
 
25
- const vault = await driftVault.getVault(address);
26
- const { managerSharePct } = printVault(vault);
27
- const vaultEquity = await driftVault.calculateVaultEquity({
28
- vault,
29
- });
30
-
24
+ const vaultAndSlot = await driftVault.getVaultAndSlot(address);
25
+ const vault = vaultAndSlot.vault;
31
26
  const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
32
27
  if (!spotMarket) {
33
28
  throw new Error(`Spot market ${vault.spotMarketIndex} not found`);
@@ -36,19 +31,9 @@ export const viewVault = async (program: Command, cmdOpts: OptionValues) => {
36
31
  if (!spotOracle) {
37
32
  throw new Error(`Spot oracle ${vault.spotMarketIndex} not found`);
38
33
  }
39
- const oraclePriceNum = convertToNumber(spotOracle.price, PRICE_PRECISION);
40
- const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
41
- const spotSymbol = decodeName(spotMarket.name);
42
-
43
- const vaultEquityNum = convertToNumber(vaultEquity, QUOTE_PRECISION);
44
- const netDepositsNum = convertToNumber(vault.netDeposits, spotPrecision);
45
- console.log(`vaultEquity (USDC): $${vaultEquityNum}`);
46
- console.log(`manager share (USDC): $${managerSharePct * vaultEquityNum}`);
47
- console.log(`vault PnL (USDC): $${vaultEquityNum - netDepositsNum}`);
48
-
49
- const vaultEquitySpot = vaultEquityNum / oraclePriceNum;
34
+ const vaultEquity = await driftVault.calculateVaultEquity({
35
+ vault,
36
+ });
37
+ await printVault(vaultAndSlot.slot, driftClient, vault, vaultEquity, spotMarket, spotOracle);
38
+ };
50
39
 
51
- console.log(`vaultEquity (${spotSymbol}): ${vaultEquitySpot}`);
52
- console.log(`manager share (${spotSymbol}): ${managerSharePct * vaultEquitySpot}`);
53
- console.log(`vault PnL (${spotSymbol}): ${vaultEquitySpot - netDepositsNum}`);
54
- };
package/cli/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { DriftClient, Wallet, loadKeypair } from "@drift-labs/sdk";
1
+ import { BASE_PRECISION, BN, DriftClient, OraclePriceData, PRICE_PRECISION, QUOTE_PRECISION, SpotMarketAccount, TEN, User, Wallet, convertToNumber, getSignedTokenAmount, getTokenAmount, loadKeypair } from "@drift-labs/sdk";
2
2
  import { VAULT_PROGRAM_ID, Vault, VaultClient, VaultDepositor, decodeName } from "../src";
3
3
  import { Command } from "commander";
4
4
  import { Connection, Keypair } from "@solana/web3.js";
@@ -6,7 +6,13 @@ import { AnchorProvider } from "@coral-xyz/anchor";
6
6
  import * as anchor from '@coral-xyz/anchor';
7
7
  import { IDL } from "../src/types/drift_vaults";
8
8
 
9
- export function printVault(vault: Vault) {
9
+ export async function printVault(slot: number, driftClient: DriftClient, vault: Vault, vaultEquity: BN, spotMarket: SpotMarketAccount, spotOracle: OraclePriceData) {
10
+
11
+ const oraclePriceNum = convertToNumber(spotOracle.price, PRICE_PRECISION);
12
+ const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
13
+ const spotSymbol = decodeName(spotMarket.name);
14
+
15
+ console.log(`slot: ${slot}`);
10
16
  console.log(`vault: ${decodeName(vault.name)}`);
11
17
  console.log(`pubkey: ${vault.pubkey.toBase58()}`);
12
18
  console.log(`manager: ${vault.manager.toBase58()}`);
@@ -25,21 +31,21 @@ export function printVault(vault: Vault) {
25
31
  console.log(`liquidationStartTs: ${vault.liquidationStartTs.toString()}`);
26
32
  console.log(`redeemPeriod: ${vault.redeemPeriod.toString()}`);
27
33
  console.log(`totalWithdrawRequested: ${vault.totalWithdrawRequested.toString()}`);
28
- console.log(`maxTokens: ${vault.maxTokens.toString()}`);
34
+ console.log(`maxTokens: ${convertToNumber(vault.maxTokens, spotPrecision)} ${spotSymbol} (${vault.maxTokens.toString()})`);
29
35
  console.log(`sharesBase: ${vault.sharesBase}`);
30
36
  console.log(`managementFee: ${vault.managementFee.toString()}`);
31
37
  console.log(`initTs: ${vault.initTs.toString()}`);
32
- console.log(`netDeposits: ${vault.netDeposits.toString()}`);
33
- console.log(`managerNetDeposits: ${vault.managerNetDeposits.toString()}`);
34
- console.log(`totalDeposits: ${vault.totalDeposits.toString()}`);
35
- console.log(`totalWithdraws: ${vault.totalWithdraws.toString()}`);
36
- console.log(`managerTotalDeposits: ${vault.managerTotalDeposits.toString()}`);
37
- console.log(`managerTotalWithdraws: ${vault.managerTotalWithdraws.toString()}`);
38
- console.log(`managerTotalFee: ${vault.managerTotalFee.toString()}`);
39
- console.log(`managerTotalProfitShare: ${vault.managerTotalProfitShare.toString()}`);
38
+ console.log(`netDeposits: ${convertToNumber(vault.netDeposits, spotPrecision)} ${spotSymbol} (${vault.netDeposits.toString()})`);
39
+ console.log(`totalDeposits: ${convertToNumber(vault.totalDeposits, spotPrecision)} ${spotSymbol} (${vault.totalDeposits.toString()})`);
40
+ console.log(`totalWithdraws: ${convertToNumber(vault.totalWithdraws, spotPrecision)} ${spotSymbol} (${vault.totalWithdraws.toString()})`);
41
+ console.log(`managerNetDeposits: ${convertToNumber(vault.managerNetDeposits, spotPrecision)} ${spotSymbol} (${vault.managerNetDeposits.toString()})`);
42
+ console.log(`managerTotalDeposits: ${convertToNumber(vault.managerTotalDeposits, spotPrecision)} ${spotSymbol} (${vault.managerTotalDeposits.toString()})`);
43
+ console.log(`managerTotalWithdraws: ${convertToNumber(vault.managerTotalWithdraws, spotPrecision)} ${spotSymbol} (${vault.managerTotalWithdraws.toString()})`);
44
+ console.log(`managerTotalFee: ${convertToNumber(vault.managerTotalFee, spotPrecision)} ${spotSymbol} (${vault.managerTotalFee.toString()})`);
45
+ console.log(`managerTotalProfitShare: ${convertToNumber(vault.managerTotalProfitShare, spotPrecision)} ${spotSymbol} (${vault.managerTotalProfitShare.toString()})`);
40
46
  console.log(`lastManagerWithdrawRequest:`);
41
47
  console.log(` shares: ${vault.lastManagerWithdrawRequest.shares.toString()}`);
42
- console.log(` values: ${vault.lastManagerWithdrawRequest.value.toString()}`);
48
+ console.log(` values: ${convertToNumber(vault.lastManagerWithdrawRequest.value, spotPrecision)} ${spotSymbol} (${vault.lastManagerWithdrawRequest.value.toString()})`);
43
49
  console.log(` ts: ${vault.lastManagerWithdrawRequest.ts.toString()}`);
44
50
 
45
51
  console.log(`minDepositAmount: ${vault.minDepositAmount.toString()}`);
@@ -48,6 +54,36 @@ export function printVault(vault: Vault) {
48
54
  console.log(`spotMarketIndex: ${vault.spotMarketIndex}`);
49
55
  console.log(`permissioned: ${vault.permissioned}`);
50
56
 
57
+ const vaultEquityNum = convertToNumber(vaultEquity, QUOTE_PRECISION);
58
+ const netDepositsNum = convertToNumber(vault.netDeposits, spotPrecision);
59
+ console.log(`vaultEquity (USDC): $${vaultEquityNum}`);
60
+ console.log(`manager share (USDC): $${managerSharePct * vaultEquityNum}`);
61
+
62
+ const vaultEquitySpot = vaultEquityNum / oraclePriceNum;
63
+
64
+ const user = new User({
65
+ // accountSubscription,
66
+ driftClient,
67
+ userAccountPublicKey: vault.user,
68
+ });
69
+ await user.subscribe();
70
+ for (const spotPos of user.getActiveSpotPositions()) {
71
+ const sm = driftClient.getSpotMarketAccount(spotPos.marketIndex)!;
72
+ const prec = TEN.pow(new BN(sm.decimals));
73
+ const sym = decodeName(sm.name);
74
+ const bal = getSignedTokenAmount(getTokenAmount(spotPos.scaledBalance, sm, spotPos.balanceType), spotPos.balanceType);
75
+ console.log(`Spot Position: ${spotPos.marketIndex}, ${convertToNumber(bal, prec)} ${sym}`);
76
+ }
77
+ for (const perpPos of user.getActivePerpPositions()) {
78
+ console.log(`Perp Position: ${perpPos.marketIndex}, base: ${convertToNumber(perpPos.baseAssetAmount, BASE_PRECISION)}, quote: ${convertToNumber(perpPos.quoteAssetAmount, QUOTE_PRECISION)}`);
79
+ const upnl = user.getUnrealizedPNL(true, perpPos.marketIndex);
80
+ console.log(` upnl: ${convertToNumber(upnl, QUOTE_PRECISION)}`);
81
+ }
82
+
83
+ console.log(`vaultEquity (${spotSymbol}): ${vaultEquitySpot}`);
84
+ console.log(`manager share (${spotSymbol}): ${managerSharePct * vaultEquitySpot}`);
85
+ console.log(`vault PnL (${spotSymbol}): ${vaultEquitySpot - netDepositsNum}`);
86
+
51
87
  return {
52
88
  managerShares,
53
89
  managerSharePct,
@@ -5,7 +5,7 @@ import { BN, DriftClient, UserMap } from '@drift-labs/sdk';
5
5
  import { Program, ProgramAccount } from '@coral-xyz/anchor';
6
6
  import { DriftVaults } from './types/drift_vaults';
7
7
  import { CompetitionsClient } from '@drift-labs/competitions-sdk';
8
- import { PublicKey, TransactionInstruction, TransactionSignature } from '@solana/web3.js';
8
+ import { ConfirmOptions, PublicKey, TransactionInstruction, TransactionSignature } from '@solana/web3.js';
9
9
  import { Vault, VaultDepositor, WithdrawUnit } from './types/types';
10
10
  import { UserMapConfig } from '@drift-labs/sdk/lib/userMap/userMapConfig';
11
11
  export type TxParams = {
@@ -93,7 +93,7 @@ export declare class VaultClient {
93
93
  profitShare: number | null;
94
94
  hurdleRate: number | null;
95
95
  permissioned: boolean | null;
96
- }): Promise<TransactionSignature>;
96
+ }, preIxs?: Array<TransactionInstruction>, opts?: ConfirmOptions): Promise<TransactionSignature>;
97
97
  getApplyProfitShareIx(vault: PublicKey, vaultDepositor: PublicKey): Promise<TransactionInstruction>;
98
98
  private createInitVaultDepositorIx;
99
99
  /**
@@ -116,7 +116,7 @@ export declare class VaultClient {
116
116
  }): Promise<TransactionSignature>;
117
117
  requestWithdraw(vaultDepositor: PublicKey, amount: BN, withdrawUnit: WithdrawUnit): Promise<TransactionSignature>;
118
118
  withdraw(vaultDepositor: PublicKey, txParams?: TxParams): Promise<TransactionSignature>;
119
- forceWithdraw(vaultDepositor: PublicKey): Promise<TransactionSignature>;
119
+ forceWithdraw(vaultDepositor: PublicKey, ixOnly?: boolean, preIxs?: Array<TransactionInstruction>, simulate?: boolean, opts?: ConfirmOptions): Promise<TransactionSignature | TransactionInstruction | undefined>;
120
120
  cancelRequestWithdraw(vaultDepositor: PublicKey): Promise<TransactionSignature>;
121
121
  /**
122
122
  * Liquidates (become delegate for) a vault.
@@ -319,14 +319,15 @@ class VaultClient {
319
319
  cuLimit: 1000000,
320
320
  });
321
321
  }
322
- async managerUpdateVault(vault, params) {
323
- return await this.program.methods
324
- .updateVault(params)
325
- .accounts({
322
+ async managerUpdateVault(vault, params, preIxs, opts) {
323
+ let builder = this.program.methods.updateVault(params).accounts({
326
324
  vault,
327
325
  manager: this.driftClient.wallet.publicKey,
328
- })
329
- .rpc();
326
+ });
327
+ if (preIxs) {
328
+ builder = builder.preInstructions(preIxs);
329
+ }
330
+ return builder.rpc(opts);
330
331
  }
331
332
  async getApplyProfitShareIx(vault, vaultDepositor) {
332
333
  const vaultAccount = await this.program.account.vault.fetch(vault);
@@ -560,7 +561,7 @@ class VaultClient {
560
561
  });
561
562
  }
562
563
  }
563
- async forceWithdraw(vaultDepositor) {
564
+ async forceWithdraw(vaultDepositor, ixOnly, preIxs, simulate, opts) {
564
565
  const vaultDepositorAccount = await this.program.account.vaultDepositor.fetch(vaultDepositor);
565
566
  const vaultAccount = await this.program.account.vault.fetch(vaultDepositorAccount.vault);
566
567
  const user = await this.getSubscribedVaultUser(vaultAccount.user);
@@ -589,16 +590,52 @@ class VaultClient {
589
590
  tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
590
591
  };
591
592
  if (this.cliMode) {
592
- return await this.program.methods
593
- .forceWithdraw()
594
- .preInstructions([
595
- web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
596
- units: 400000,
597
- }),
598
- ])
599
- .accounts(accounts)
600
- .remainingAccounts(remainingAccounts)
601
- .rpc();
593
+ if (ixOnly) {
594
+ return await this.program.methods
595
+ .forceWithdraw()
596
+ .accounts(accounts)
597
+ .remainingAccounts(remainingAccounts)
598
+ .instruction();
599
+ }
600
+ else if (simulate) {
601
+ let builder = this.program.methods.forceWithdraw();
602
+ if (preIxs) {
603
+ builder = builder.preInstructions(preIxs);
604
+ }
605
+ else {
606
+ builder = builder.preInstructions([
607
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
608
+ units: 600000,
609
+ }),
610
+ ]);
611
+ }
612
+ const simResult = await builder
613
+ .accounts(accounts)
614
+ .remainingAccounts(remainingAccounts)
615
+ .simulate();
616
+ console.log(simResult);
617
+ console.log(simResult.events);
618
+ }
619
+ else {
620
+ let builder = this.program.methods.forceWithdraw();
621
+ if (preIxs) {
622
+ builder = builder.preInstructions(preIxs);
623
+ }
624
+ else {
625
+ builder = builder.preInstructions([
626
+ web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
627
+ units: 600000,
628
+ }),
629
+ web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
630
+ microLamports: 100000,
631
+ }),
632
+ ]);
633
+ }
634
+ return await builder
635
+ .accounts(accounts)
636
+ .remainingAccounts(remainingAccounts)
637
+ .rpc(opts);
638
+ }
602
639
  }
603
640
  else {
604
641
  const forceWithdrawIx = this.program.instruction.forceWithdraw({
@@ -698,7 +735,7 @@ class VaultClient {
698
735
  units: (_a = txParams === null || txParams === void 0 ? void 0 : txParams.cuLimit) !== null && _a !== void 0 ? _a : 400000,
699
736
  }),
700
737
  web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
701
- microLamports: (_b = txParams === null || txParams === void 0 ? void 0 : txParams.cuPriceMicroLamports) !== null && _b !== void 0 ? _b : 1000000,
738
+ microLamports: (_b = txParams === null || txParams === void 0 ? void 0 : txParams.cuPriceMicroLamports) !== null && _b !== void 0 ? _b : 80000,
702
739
  }),
703
740
  ...vaultIxs,
704
741
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/vaults-sdk",
3
- "version": "0.1.211",
3
+ "version": "0.1.212",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "directories": {
@@ -22,6 +22,7 @@ import {
22
22
  } from './addresses';
23
23
  import {
24
24
  ComputeBudgetProgram,
25
+ ConfirmOptions,
25
26
  PublicKey,
26
27
  SystemProgram,
27
28
  SYSVAR_RENT_PUBKEY,
@@ -524,15 +525,19 @@ export class VaultClient {
524
525
  profitShare: number | null;
525
526
  hurdleRate: number | null;
526
527
  permissioned: boolean | null;
527
- }
528
+ },
529
+ preIxs?: Array<TransactionInstruction>,
530
+ opts?: ConfirmOptions
528
531
  ): Promise<TransactionSignature> {
529
- return await this.program.methods
530
- .updateVault(params)
531
- .accounts({
532
- vault,
533
- manager: this.driftClient.wallet.publicKey,
534
- })
535
- .rpc();
532
+ let builder = this.program.methods.updateVault(params).accounts({
533
+ vault,
534
+ manager: this.driftClient.wallet.publicKey,
535
+ });
536
+ if (preIxs) {
537
+ builder = builder.preInstructions(preIxs);
538
+ }
539
+
540
+ return builder.rpc(opts);
536
541
  }
537
542
 
538
543
  public async getApplyProfitShareIx(
@@ -887,8 +892,12 @@ export class VaultClient {
887
892
  }
888
893
 
889
894
  public async forceWithdraw(
890
- vaultDepositor: PublicKey
891
- ): Promise<TransactionSignature> {
895
+ vaultDepositor: PublicKey,
896
+ ixOnly?: boolean,
897
+ preIxs?: Array<TransactionInstruction>,
898
+ simulate?: boolean,
899
+ opts?: ConfirmOptions
900
+ ): Promise<TransactionSignature | TransactionInstruction | undefined> {
892
901
  const vaultDepositorAccount =
893
902
  await this.program.account.vaultDepositor.fetch(vaultDepositor);
894
903
  const vaultAccount = await this.program.account.vault.fetch(
@@ -937,16 +946,49 @@ export class VaultClient {
937
946
  };
938
947
 
939
948
  if (this.cliMode) {
940
- return await this.program.methods
941
- .forceWithdraw()
942
- .preInstructions([
943
- ComputeBudgetProgram.setComputeUnitLimit({
944
- units: 400_000,
945
- }),
946
- ])
947
- .accounts(accounts)
948
- .remainingAccounts(remainingAccounts)
949
- .rpc();
949
+ if (ixOnly) {
950
+ return await this.program.methods
951
+ .forceWithdraw()
952
+ .accounts(accounts)
953
+ .remainingAccounts(remainingAccounts)
954
+ .instruction();
955
+ } else if (simulate) {
956
+ let builder = this.program.methods.forceWithdraw();
957
+ if (preIxs) {
958
+ builder = builder.preInstructions(preIxs);
959
+ } else {
960
+ builder = builder.preInstructions([
961
+ ComputeBudgetProgram.setComputeUnitLimit({
962
+ units: 600_000,
963
+ }),
964
+ ]);
965
+ }
966
+ const simResult = await builder
967
+ .accounts(accounts)
968
+ .remainingAccounts(remainingAccounts)
969
+ .simulate();
970
+
971
+ console.log(simResult);
972
+ console.log(simResult.events);
973
+ } else {
974
+ let builder = this.program.methods.forceWithdraw();
975
+ if (preIxs) {
976
+ builder = builder.preInstructions(preIxs);
977
+ } else {
978
+ builder = builder.preInstructions([
979
+ ComputeBudgetProgram.setComputeUnitLimit({
980
+ units: 600_000,
981
+ }),
982
+ ComputeBudgetProgram.setComputeUnitPrice({
983
+ microLamports: 100_000,
984
+ }),
985
+ ]);
986
+ }
987
+ return await builder
988
+ .accounts(accounts)
989
+ .remainingAccounts(remainingAccounts)
990
+ .rpc(opts);
991
+ }
950
992
  } else {
951
993
  const forceWithdrawIx = this.program.instruction.forceWithdraw({
952
994
  accounts: {
@@ -1076,7 +1118,7 @@ export class VaultClient {
1076
1118
  units: txParams?.cuLimit ?? 400_000,
1077
1119
  }),
1078
1120
  ComputeBudgetProgram.setComputeUnitPrice({
1079
- microLamports: txParams?.cuPriceMicroLamports ?? 1_000_000,
1121
+ microLamports: txParams?.cuPriceMicroLamports ?? 80_000,
1080
1122
  }),
1081
1123
  ...vaultIxs,
1082
1124
  ];