@velocity-exchange/vaults-sdk 0.0.1

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.
Files changed (65) hide show
  1. package/.env.example +3 -0
  2. package/README.md +152 -0
  3. package/cli/cli.ts +751 -0
  4. package/cli/commands/adminDeleteFeeUpdate.ts +73 -0
  5. package/cli/commands/adminInitFeeUpdate.ts +73 -0
  6. package/cli/commands/adminUpdateVaultClass.ts +49 -0
  7. package/cli/commands/applyProfitShare.ts +139 -0
  8. package/cli/commands/decodeLogs.ts +98 -0
  9. package/cli/commands/deposit.ts +98 -0
  10. package/cli/commands/deriveVaultAddress.ts +14 -0
  11. package/cli/commands/forceWithdraw.ts +56 -0
  12. package/cli/commands/forceWithdrawAll.ts +142 -0
  13. package/cli/commands/index.ts +28 -0
  14. package/cli/commands/initVault.ts +227 -0
  15. package/cli/commands/initVaultDepositor.ts +42 -0
  16. package/cli/commands/listDepositorsForVault.ts +32 -0
  17. package/cli/commands/managerApplyProfitShare.ts +32 -0
  18. package/cli/commands/managerBorrow.ts +77 -0
  19. package/cli/commands/managerCancelWithdraw.ts +30 -0
  20. package/cli/commands/managerDeposit.ts +45 -0
  21. package/cli/commands/managerRepay.ts +94 -0
  22. package/cli/commands/managerRequestWithdraw.ts +86 -0
  23. package/cli/commands/managerUpdateBorrow.ts +56 -0
  24. package/cli/commands/managerUpdateFees.ts +156 -0
  25. package/cli/commands/managerUpdateMarginTradingEnabled.ts +32 -0
  26. package/cli/commands/managerUpdatePoolId.ts +36 -0
  27. package/cli/commands/managerUpdateVault.ts +210 -0
  28. package/cli/commands/managerUpdateVaultDelegate.ts +43 -0
  29. package/cli/commands/managerUpdateVaultManager.ts +77 -0
  30. package/cli/commands/managerWithdraw.ts +30 -0
  31. package/cli/commands/requestWithdraw.ts +58 -0
  32. package/cli/commands/vaultDeposit.ts +42 -0
  33. package/cli/commands/vaultInvariantChecks.ts +407 -0
  34. package/cli/commands/vaultWithdraw.ts +42 -0
  35. package/cli/commands/viewVault.ts +50 -0
  36. package/cli/commands/viewVaultDepositor.ts +36 -0
  37. package/cli/commands/withdraw.ts +40 -0
  38. package/cli/ledgerWallet.test.ts +49 -0
  39. package/cli/ledgerWallet.ts +111 -0
  40. package/cli/utils.ts +389 -0
  41. package/package.json +48 -0
  42. package/src/accountSubscribers/index.ts +2 -0
  43. package/src/accountSubscribers/pollingVaultDepositorSubscriber.ts +69 -0
  44. package/src/accountSubscribers/pollingVaultSubscriber.ts +63 -0
  45. package/src/accountSubscribers/pollingVaultsProgramAccountSubscriber.ts +114 -0
  46. package/src/accounts/index.ts +2 -0
  47. package/src/accounts/vaultAccount.ts +255 -0
  48. package/src/accounts/vaultDepositorAccount.ts +77 -0
  49. package/src/accounts/vaultsProgramAccount.ts +38 -0
  50. package/src/addresses.ts +114 -0
  51. package/src/constants/index.ts +15 -0
  52. package/src/idl/drift_vaults.json +5698 -0
  53. package/src/index.ts +11 -0
  54. package/src/math/index.ts +2 -0
  55. package/src/math/vault.ts +71 -0
  56. package/src/math/vaultDepositor.ts +90 -0
  57. package/src/name.ts +18 -0
  58. package/src/parsers/index.ts +1 -0
  59. package/src/parsers/logParser.ts +28 -0
  60. package/src/types/drift_vaults.ts +6211 -0
  61. package/src/types/types.ts +336 -0
  62. package/src/utils.ts +74 -0
  63. package/src/vaultClient.ts +3666 -0
  64. package/tsconfig.json +24 -0
  65. package/velocity-exchange-vaults-sdk-0.0.1.tgz +0 -0
@@ -0,0 +1,73 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import {
3
+ OptionValues,
4
+ Command
5
+ } from "commander";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
+ import { VAULT_ADMIN_KEY } from "../../src";
8
+
9
+ export const adminDeleteFeeUpdate = async (program: Command, cmdOpts: OptionValues) => {
10
+ let vaultAddress: PublicKey;
11
+ try {
12
+ vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
13
+ } catch (err) {
14
+ console.error("Invalid vault address");
15
+ process.exit(1);
16
+ }
17
+
18
+ const {
19
+ driftVault,
20
+ driftClient,
21
+ } = await getCommandContext(program, true);
22
+
23
+ if (!driftClient.wallet.publicKey.equals(VAULT_ADMIN_KEY)) {
24
+ console.error("Only vault admin can delete fee update");
25
+ process.exit(1);
26
+ }
27
+
28
+ const vault = await driftVault.getVault(vaultAddress);
29
+
30
+ console.log(`Deleting fee update for vault:`);
31
+ console.log(` Vault: ${vault.pubkey.toBase58()}`);
32
+
33
+ const readline = require('readline').createInterface({
34
+ input: process.stdin,
35
+ output: process.stdout
36
+ });
37
+ console.log('');
38
+ const answer = await new Promise(resolve => {
39
+ readline.question('Are you sure you want to delete the fee update? (yes/no) ', (answer: string) => {
40
+ readline.close();
41
+ resolve(answer);
42
+ });
43
+ });
44
+ if ((answer as string).toLowerCase() !== 'yes') {
45
+ console.log('Fee update deletion canceled.');
46
+ process.exit(0);
47
+ }
48
+ console.log('Deleting fee update...');
49
+
50
+ let done = false;
51
+ while (!done) {
52
+ try {
53
+ if (cmdOpts.dumpTransactionMessage) {
54
+ const tx = await driftVault.getAdminDeleteFeeUpdateIx(vaultAddress);
55
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
56
+ } else {
57
+ const tx = await driftVault.adminDeleteFeeUpdate(vaultAddress);
58
+ console.log(`Deleted fee update as admin: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
59
+ done = true;
60
+ }
61
+ break;
62
+ } catch (e) {
63
+ const err = e as Error;
64
+ if (err.message.includes('TransactionExpiredTimeoutError')) {
65
+ console.log(err.message);
66
+ console.log('Transaction timeout. Retrying...');
67
+ await new Promise(resolve => setTimeout(resolve, 5000));
68
+ } else {
69
+ throw err;
70
+ }
71
+ }
72
+ }
73
+ };
@@ -0,0 +1,73 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import {
3
+ OptionValues,
4
+ Command
5
+ } from "commander";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
+ import { VAULT_ADMIN_KEY } from "../../src";
8
+
9
+ export const adminInitFeeUpdate = async (program: Command, cmdOpts: OptionValues) => {
10
+ let vaultAddress: PublicKey;
11
+ try {
12
+ vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
13
+ } catch (err) {
14
+ console.error("Invalid vault address");
15
+ process.exit(1);
16
+ }
17
+
18
+ const {
19
+ driftVault,
20
+ driftClient,
21
+ } = await getCommandContext(program, true);
22
+
23
+ if (!driftClient.wallet.publicKey.equals(VAULT_ADMIN_KEY)) {
24
+ console.error("Only vault admin can initialize fee update");
25
+ process.exit(1);
26
+ }
27
+
28
+ const vault = await driftVault.getVault(vaultAddress);
29
+
30
+ console.log(`Initializing fee update for vault:`);
31
+ console.log(` Vault: ${vault.pubkey.toBase58()}`);
32
+
33
+ const readline = require('readline').createInterface({
34
+ input: process.stdin,
35
+ output: process.stdout
36
+ });
37
+ console.log('');
38
+ const answer = await new Promise(resolve => {
39
+ readline.question('Is the above information correct? (yes/no) ', (answer: string) => {
40
+ readline.close();
41
+ resolve(answer);
42
+ });
43
+ });
44
+ if ((answer as string).toLowerCase() !== 'yes') {
45
+ console.log('Fee update initialization canceled.');
46
+ process.exit(0);
47
+ }
48
+ console.log('Initializing fee update...');
49
+
50
+ let done = false;
51
+ while (!done) {
52
+ try {
53
+ if (cmdOpts.dumpTransactionMessage) {
54
+ const tx = await driftVault.getAdminInitFeeUpdateIx(vaultAddress);
55
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
56
+ } else {
57
+ const tx = await driftVault.adminInitFeeUpdate(vaultAddress);
58
+ console.log(`Initialized fee update as admin: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
59
+ done = true;
60
+ }
61
+ break;
62
+ } catch (e) {
63
+ const err = e as Error;
64
+ if (err.message.includes('TransactionExpiredTimeoutError')) {
65
+ console.log(err.message);
66
+ console.log('Transaction timeout. Retrying...');
67
+ await new Promise(resolve => setTimeout(resolve, 5000));
68
+ } else {
69
+ throw err;
70
+ }
71
+ }
72
+ }
73
+ };
@@ -0,0 +1,49 @@
1
+ import { Command, OptionValues } from "commander";
2
+ import { PublicKey } from "@solana/web3.js";
3
+ import { VaultClass } from "../../src";
4
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
5
+
6
+ export async function adminUpdateVaultClass(program: Command, cmdOpts: OptionValues): Promise<void> {
7
+ const { vaultAddress, vaultClass, dumpTransactionMessage: dumpTx } = cmdOpts;
8
+
9
+ const {
10
+ driftClient,
11
+ driftVault
12
+ } = await getCommandContext(program, true);
13
+
14
+ if (!vaultAddress) {
15
+ throw new Error("Must provide vault address with --vault-address");
16
+ }
17
+
18
+ if (!vaultClass) {
19
+ throw new Error("Must provide vault class with --vault-class");
20
+ }
21
+
22
+ const vault = new PublicKey(vaultAddress);
23
+
24
+ // Parse vault class from string input
25
+ let newVaultClass: VaultClass;
26
+ switch (vaultClass.toLowerCase()) {
27
+ case 'trusted':
28
+ newVaultClass = VaultClass.TRUSTED;
29
+ break;
30
+ default:
31
+ throw new Error(`Invalid vault class: ${vaultClass}. Must be 'trusted'`);
32
+ }
33
+
34
+ try {
35
+ if (dumpTx) {
36
+ const ix = await driftVault.getAdminUpdateVaultClassIx(vault, newVaultClass);
37
+ console.log("Transaction Instruction:");
38
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [ix]));
39
+ return;
40
+ }
41
+
42
+ const txSig = await driftVault.adminUpdateVaultClass(vault, newVaultClass);
43
+ console.log(`Admin update vault class transaction signature: ${txSig}`);
44
+ console.log(`Transaction: https://solana.fm/tx/${txSig}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
45
+ } catch (error) {
46
+ console.error("Error updating vault class:", error);
47
+ throw error;
48
+ }
49
+ }
@@ -0,0 +1,139 @@
1
+ import {
2
+ ComputeBudgetProgram,
3
+ PublicKey,
4
+ SendTransactionError,
5
+ TransactionInstruction,
6
+ TransactionMessage,
7
+ VersionedTransaction,
8
+ } from '@solana/web3.js';
9
+ import { OptionValues, Command } from 'commander';
10
+ import { getCommandContext } from '../utils';
11
+ import { VaultDepositor, calculateApplyProfitShare } from '../../src';
12
+ import { BN, TEN, ZERO, numberToSafeBN } from '@velocity-exchange/sdk';
13
+ import { ProgramAccount } from '@coral-xyz/anchor';
14
+
15
+ export const applyProfitShare = async (
16
+ program: Command,
17
+ cmdOpts: OptionValues
18
+ ) => {
19
+ let vaultAddress: PublicKey;
20
+ try {
21
+ vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
22
+ } catch (err) {
23
+ console.error('Invalid vault address');
24
+ process.exit(1);
25
+ }
26
+
27
+ const { driftVault, driftClient, wallet } = await getCommandContext(
28
+ program,
29
+ true
30
+ );
31
+
32
+ const vault = await driftVault.getVault(vaultAddress);
33
+ const vdWithNoWithdrawRequests =
34
+ await driftVault.getAllVaultDepositorsWithNoWithdrawRequest(vaultAddress);
35
+ const vaultEquitySpot = await driftVault.calculateVaultEquityInDepositAsset({
36
+ vault,
37
+ });
38
+
39
+ const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
40
+ if (!spotMarket) {
41
+ throw new Error(
42
+ `Spot market account ${vault.spotMarketIndex} has not been loaded`
43
+ );
44
+ }
45
+ const spotMarketPrecision = TEN.pow(new BN(spotMarket.decimals));
46
+ const thresholdNumber = parseFloat(cmdOpts.threshold);
47
+ const thresholdBN = numberToSafeBN(thresholdNumber, spotMarketPrecision);
48
+ let pendingProfitShareToRealize = ZERO;
49
+ const vdWithPendingProfitShare = vdWithNoWithdrawRequests.filter(
50
+ (vd: ProgramAccount<VaultDepositor>) => {
51
+ if (vault.managementFee.gt(ZERO)) {
52
+ return true;
53
+ }
54
+ const pendingProfitShares = calculateApplyProfitShare(
55
+ vd.account,
56
+ vaultEquitySpot,
57
+ vault
58
+ );
59
+ const doRealize = pendingProfitShares.profitShareAmount.gte(thresholdBN);
60
+ if (doRealize) {
61
+ pendingProfitShareToRealize = pendingProfitShareToRealize.add(
62
+ pendingProfitShares.profitShareAmount
63
+ );
64
+ return true;
65
+ } else {
66
+ return false;
67
+ }
68
+ }
69
+ );
70
+
71
+ console.log(
72
+ `${vdWithPendingProfitShare.length}/${
73
+ vdWithNoWithdrawRequests.length
74
+ } depositors have pending profit shares above threshold ${
75
+ cmdOpts.threshold
76
+ } (${thresholdBN.toString()})`
77
+ );
78
+ console.log(
79
+ `Applying profit share for ${vdWithPendingProfitShare.length} depositors.`
80
+ );
81
+
82
+ const chunkSize = 1;
83
+ const ixChunks: Array<Array<TransactionInstruction>> = [];
84
+ for (let i = 0; i < vdWithPendingProfitShare.length; i += chunkSize) {
85
+ const chunk = vdWithPendingProfitShare.slice(i, i + chunkSize);
86
+ const ixs = await Promise.all(
87
+ chunk.map((vd: ProgramAccount<VaultDepositor>) => {
88
+ return driftVault.getApplyProfitShareIx(vaultAddress, vd.publicKey);
89
+ })
90
+ );
91
+
92
+ ixChunks.push(ixs);
93
+ }
94
+ console.log(`Sending ${ixChunks.length} transactions...`);
95
+
96
+ for (let i = 0; i < ixChunks.length; i++) {
97
+ const ixs = ixChunks[i];
98
+ console.log(`Sending chunk ${i + 1}/${ixChunks.length}`);
99
+ try {
100
+ ixs.unshift(
101
+ ComputeBudgetProgram.setComputeUnitPrice({
102
+ microLamports: 10000,
103
+ })
104
+ );
105
+ ixs.unshift(
106
+ ComputeBudgetProgram.setComputeUnitLimit({
107
+ units: 170_000,
108
+ })
109
+ );
110
+
111
+ const message = new TransactionMessage({
112
+ payerKey: driftClient.wallet.publicKey,
113
+ recentBlockhash: (
114
+ await driftClient.connection.getLatestBlockhash('finalized')
115
+ ).blockhash,
116
+ instructions: ixs,
117
+ }).compileToV0Message();
118
+
119
+ const tx = await wallet.signVersionedTransaction(
120
+ new VersionedTransaction(message)
121
+ );
122
+
123
+ try {
124
+ const txid = await driftClient.connection.sendTransaction(tx);
125
+ console.log(
126
+ `Sent chunk: https://solana.fm/tx/${txid}${
127
+ driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
128
+ }`
129
+ );
130
+ } catch (e) {
131
+ console.error(`Error sending chunk: ${e}`);
132
+ console.log((e as SendTransactionError).logs);
133
+ }
134
+ } catch (e) {
135
+ console.error(e);
136
+ continue;
137
+ }
138
+ }
139
+ };
@@ -0,0 +1,98 @@
1
+ import { OptionValues, Command } from 'commander';
2
+ import { getCommandContext } from '../utils';
3
+ import { VaultDepositorRecord } from '../../src';
4
+ import { BN, TEN, convertToNumber, getVariant } from '@velocity-exchange/sdk';
5
+
6
+ export const decodeLogs = async (program: Command, cmdOpts: OptionValues) => {
7
+ let txId: string;
8
+ try {
9
+ txId = cmdOpts.tx as string;
10
+ } catch (err) {
11
+ console.error('Invalid transaction hash');
12
+ process.exit(1);
13
+ }
14
+ if (!txId) {
15
+ console.error('Invalid transaction hash');
16
+ process.exit(1);
17
+ }
18
+
19
+ const { driftVault, driftClient } = await getCommandContext(program, false);
20
+
21
+ const tx = await driftClient.connection.getParsedTransaction(txId, {
22
+ commitment: 'confirmed',
23
+ maxSupportedTransactionVersion: 0,
24
+ });
25
+
26
+ let i = 0;
27
+ // @ts-ignore
28
+ for (const event of driftVault.program._events._eventParser.parseLogs(
29
+ tx!.meta!.logMessages
30
+ )) {
31
+ console.log(`--------------- Event: ${i} ${event.name} -----------------`);
32
+ i++;
33
+
34
+ /* eslint-disable no-case-declarations */
35
+ switch (event.name) {
36
+ case 'VaultDepositorRecord':
37
+ const data: VaultDepositorRecord = event.data;
38
+ const spotMarket = driftClient.getSpotMarketAccount(
39
+ data.spotMarketIndex
40
+ );
41
+ const spotPrecision = TEN.pow(new BN(spotMarket!.decimals));
42
+ const date = new Date(data.ts.toNumber() * 1000);
43
+
44
+ console.log(event.name);
45
+ console.log(` ts: ${date.toISOString()} (${data.ts.toNumber()})`);
46
+ console.log(` vault: ${data.vault.toBase58()}`);
47
+ console.log(
48
+ ` depositorAuthority: ${data.depositorAuthority.toBase58()}`
49
+ );
50
+ console.log(` action: ${getVariant(data.action)}`);
51
+ console.log(` amount: ${convertToNumber(data.amount, spotPrecision)}`);
52
+ console.log(` vaultSharesBefore: ${data.vaultSharesBefore.toNumber()}`);
53
+ console.log(
54
+ ` vaultSharesAfter: ${data.vaultSharesAfter.toNumber()} (${
55
+ data.vaultSharesAfter.toNumber() - data.vaultSharesBefore.toNumber()
56
+ })`
57
+ );
58
+ console.log(
59
+ ` vaultEquityBefore: ${convertToNumber(
60
+ data.vaultEquityBefore,
61
+ spotPrecision
62
+ )}`
63
+ );
64
+ console.log(
65
+ ` userVaultSharesBefore: ${data.userVaultSharesBefore.toNumber()}`
66
+ );
67
+ console.log(
68
+ ` userVaultSharesAfter: ${data.userVaultSharesAfter.toNumber()} (${
69
+ data.userVaultSharesAfter.toNumber() -
70
+ data.userVaultSharesBefore.toNumber()
71
+ })`
72
+ );
73
+ console.log(
74
+ ` totalVaultSharesBefore: ${data.totalVaultSharesBefore.toNumber()}`
75
+ );
76
+ console.log(
77
+ ` totalVaultSharesAfter: ${data.totalVaultSharesAfter.toNumber()} (${
78
+ data.totalVaultSharesAfter.toNumber() -
79
+ data.totalVaultSharesBefore.toNumber()
80
+ })`
81
+ );
82
+ console.log(` profitShare: ${data.profitShare.toNumber()}`);
83
+ console.log(` managementFee: ${data.managementFee.toNumber()}`);
84
+ console.log(
85
+ ` managementFeeShares: ${data.managementFeeShares.toNumber()}`
86
+ );
87
+ // @ts-ignore
88
+ console.log(
89
+ ` depositOraclePrice: ${data.depositOraclePrice?.toNumber()}`
90
+ );
91
+ break;
92
+ default:
93
+ }
94
+
95
+ console.log('----------Raw Event-------------');
96
+ console.log(event);
97
+ }
98
+ };
@@ -0,0 +1,98 @@
1
+ import { BN, TEN } from '@velocity-exchange/sdk';
2
+ import { PublicKey } from '@solana/web3.js';
3
+ import { OptionValues, Command } from 'commander';
4
+ import { getCommandContext } from '../utils';
5
+ import { getVaultDepositorAddressSync, VAULT_PROGRAM_ID } from '../../src';
6
+
7
+ export const deposit = async (program: Command, cmdOpts: OptionValues) => {
8
+ // verify correct args provided
9
+ if (!cmdOpts.vaultDepositorAddress) {
10
+ if (!cmdOpts.vaultAddress || !cmdOpts.depositAuthority) {
11
+ console.error(
12
+ 'Must provide --vault-address and --deposit-authority if not providing --vault-depositor-address'
13
+ );
14
+ process.exit(1);
15
+ }
16
+ }
17
+
18
+ const { driftClient, driftVault } = await getCommandContext(program, true);
19
+
20
+ let vaultDepositorAddress: PublicKey;
21
+ let vaultAddress: PublicKey | undefined;
22
+ let depositAuthority: PublicKey | undefined;
23
+ if (cmdOpts.vaultDepositorAddress) {
24
+ vaultDepositorAddress = new PublicKey(
25
+ cmdOpts.vaultDepositorAddress as string
26
+ );
27
+ } else {
28
+ vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
29
+ depositAuthority = new PublicKey(cmdOpts.depositAuthority as string);
30
+ vaultDepositorAddress = getVaultDepositorAddressSync(
31
+ VAULT_PROGRAM_ID,
32
+ vaultAddress,
33
+ depositAuthority
34
+ );
35
+ }
36
+
37
+ const vaultDepositorAccount =
38
+ await driftVault.program.account.vaultDepositor.fetchNullable(
39
+ vaultDepositorAddress
40
+ );
41
+ if (!vaultDepositorAccount) {
42
+ if (!vaultAddress || !depositAuthority) {
43
+ console.error(
44
+ 'Must provide --vault-address and --deposit-authority if not providing --vault-depositor-address, and VaultDepositor account does not exist'
45
+ );
46
+ process.exit(1);
47
+ }
48
+
49
+ const vaultAccount = await driftVault.program.account.vault.fetch(
50
+ vaultAddress
51
+ );
52
+ const spotMarket = driftClient.getSpotMarketAccount(
53
+ vaultAccount.spotMarketIndex
54
+ );
55
+ if (!spotMarket) {
56
+ throw new Error('No spot market found');
57
+ }
58
+ const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
59
+ const depositBN = new BN(cmdOpts.amount * spotPrecision.toNumber());
60
+
61
+ console.log(
62
+ `depositing (initializing VaultDepositor account): ${depositBN.toString()}`
63
+ );
64
+ const tx = await driftVault.deposit(vaultDepositorAddress, depositBN, {
65
+ authority: depositAuthority,
66
+ vault: vaultAddress,
67
+ });
68
+ console.log(
69
+ `Deposited ${cmdOpts.amount} to vault: https://solana.fm/tx/${tx}${
70
+ driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
71
+ }`
72
+ );
73
+ } else {
74
+ // VaultDepositor exists
75
+ const vaultAddress = vaultDepositorAccount.vault;
76
+ const vaultAccount = await driftVault.program.account.vault.fetch(
77
+ vaultAddress
78
+ );
79
+ const spotMarket = driftClient.getSpotMarketAccount(
80
+ vaultAccount.spotMarketIndex
81
+ );
82
+ if (!spotMarket) {
83
+ throw new Error('No spot market found');
84
+ }
85
+ const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
86
+ const depositBN = new BN(cmdOpts.amount * spotPrecision.toNumber());
87
+
88
+ console.log(
89
+ `depositing (existing VaultDepositor account): ${depositBN.toString()}`
90
+ );
91
+ const tx = await driftVault.deposit(vaultDepositorAddress, depositBN);
92
+ console.log(
93
+ `Deposited ${cmdOpts.amount} to vault: https://solana.fm/tx/${tx}${
94
+ driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
95
+ }`
96
+ );
97
+ }
98
+ };
@@ -0,0 +1,14 @@
1
+ import { OptionValues, Command } from 'commander';
2
+ import { encodeName } from '@velocity-exchange/sdk';
3
+ import { VAULT_PROGRAM_ID, getVaultAddressSync } from '../../src';
4
+
5
+ export const deriveVaultAddress = async (
6
+ _program: Command,
7
+ cmdOpts: OptionValues
8
+ ) => {
9
+ const vaultName = cmdOpts.vaultName;
10
+ const vaultNameBytes = encodeName(vaultName!);
11
+ const vaultAddress = getVaultAddressSync(VAULT_PROGRAM_ID, vaultNameBytes);
12
+
13
+ console.log(`Vault address: ${vaultAddress.toBase58()}`);
14
+ };
@@ -0,0 +1,56 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import {
3
+ OptionValues,
4
+ Command
5
+ } from "commander";
6
+ import { getCommandContext } from "../utils";
7
+ import { getVaultDepositorAddressSync } from "../../src/addresses";
8
+ import { VAULT_PROGRAM_ID } from "../../src";
9
+
10
+ export const forceWithdraw = async (program: Command, cmdOpts: OptionValues) => {
11
+
12
+ let vaultDepositorAddress: PublicKey | undefined;
13
+ try {
14
+ vaultDepositorAddress = new PublicKey(cmdOpts.vaultDepositorAddress as string);
15
+ } catch (err) {
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");
45
+ }
46
+
47
+ const {
48
+ driftVault,
49
+ driftClient,
50
+ } = await getCommandContext(program, true);
51
+
52
+ const tx = await driftVault.forceWithdraw(vaultDepositorAddress, {
53
+ lookupTables: await driftClient.fetchAllLookupTableAccounts()
54
+ });
55
+ console.log(`Forced withdraw from vault: ${tx}`);
56
+ };