@drift-labs/vaults-sdk 0.5.19 → 0.5.21

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
@@ -9,6 +9,7 @@ import {
9
9
  managerCancelWithdraw,
10
10
  managerWithdraw,
11
11
  managerUpdateVault,
12
+ managerUpdateVaultManager,
12
13
  managerUpdateVaultDelegate,
13
14
  applyProfitShare,
14
15
  initVaultDepositor,
@@ -25,6 +26,8 @@ import {
25
26
 
26
27
  import { Command, Option } from 'commander';
27
28
  import { viewVaultDepositor } from "./commands/viewVaultDepositor";
29
+ import { managerUpdatePoolId } from "./commands/managerUpdatePoolId";
30
+ import { managerApplyProfitShare } from "./commands/managerApplyProfitShare";
28
31
 
29
32
  const program = new Command();
30
33
  program
@@ -44,6 +47,8 @@ program
44
47
  .option("-p, --permissioned", "Provide this flag to make the vault permissioned, vault-depositors will need to be initialized by the manager", false)
45
48
  .option("-a, --min-deposit-amount <number", "The minimum token amount allowed to deposit", "0")
46
49
  .option("-d, --delegate <publicKey>", "The address to make the delegate of the vault")
50
+ .addOption(new Option("--manager <publickey>", "The manager for the vault").makeOptionMandatory(true))
51
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
47
52
  .action((opts) => initVault(program, opts));
48
53
  program
49
54
  .command("view-vault")
@@ -72,6 +77,7 @@ program
72
77
  .description("Make a deposit to your vault")
73
78
  .addOption(new Option("--vault-address <address>", "Address of the vault to deposit to").makeOptionMandatory(true))
74
79
  .addOption(new Option("--amount <amount>", "Amount to deposit (human format, 5 for 5 USDC)").makeOptionMandatory(true))
80
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
75
81
  .action((opts) => managerDeposit(program, opts));
76
82
  program
77
83
  .command("manager-request-withdraw")
@@ -79,6 +85,7 @@ program
79
85
  .addOption(new Option("--vault-address <address>", "Address of the vault to withdraw from").makeOptionMandatory(true))
80
86
  .addOption(new Option("--shares <shares>", "Amount of shares to withdraw (raw precision, as expected by contract)").makeOptionMandatory(false))
81
87
  .addOption(new Option("--amount <amount>", "Amount of spot asset to withdraw (human format, 5 for 5 USDC)").makeOptionMandatory(false))
88
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
82
89
  .action((opts) => managerRequestWithdraw(program, opts));
83
90
  program
84
91
  .command("manager-update-vault")
@@ -90,28 +97,54 @@ program
90
97
  .option("-m, --management-fee <percent>", "The new management fee (can only be lowered)")
91
98
  .option("-s, --profit-share <percent>", "The new profit share percentage (can only be lowered)")
92
99
  .option("-p, --permissioned <boolean>", "Set the vault as permissioned (true) or open (false)")
100
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
93
101
  .action((opts) => managerUpdateVault(program, opts));
102
+ program
103
+ .command("manager-update-vault-manager")
104
+ .description("Update the manager of a vault")
105
+ .addOption(new Option("--vault-address <address>", "Address of the vault to update ").makeOptionMandatory(true))
106
+ .addOption(new Option("--new-manager <publickey>", "The new manager for the vault").makeOptionMandatory(true))
107
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
108
+ .action((opts) => managerUpdateVaultManager(program, opts));
94
109
  program
95
110
  .command("manager-update-delegate")
96
111
  .description("Update vault params for a manager")
97
112
  .addOption(new Option("--vault-address <address>", "Address of the vault to update ").makeOptionMandatory(true))
98
113
  .addOption(new Option("-d, --delegate <publickey>", "The new delegate authority for the vault").makeOptionMandatory(true))
114
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
99
115
  .action((opts) => managerUpdateVaultDelegate(program, opts));
100
116
  program
101
117
  .command("manager-update-margin-trading-enabled")
102
118
  .description("Update vault margin trading permissiones a manager")
103
119
  .addOption(new Option("--vault-address <address>", "Address of the vault to view").makeOptionMandatory(true))
104
120
  .addOption(new Option("--enabled <enabled>", "true to enable, false to disable").makeOptionMandatory(true))
121
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
105
122
  .action((opts) => managerUpdateMarginTradingEnabled(program, opts));
123
+ program
124
+ .command("manager-update-pool-id")
125
+ .description("Update the pool id for a vault")
126
+ .addOption(new Option("--vault-address <address>", "Address of the vault to view").makeOptionMandatory(true))
127
+ .addOption(new Option("--pool-id <pool-id>", "New pool id for the vault").makeOptionMandatory(true))
128
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
129
+ .action((opts) => managerUpdatePoolId(program, opts));
130
+ program
131
+ .command("manager-apply-profit-share")
132
+ .description("Update the pool id for a vault")
133
+ .addOption(new Option("--vault-address <address>", "Address of the vault to view").makeOptionMandatory(true))
134
+ .addOption(new Option("--vault-depositor <address>", "Address of the vault depositor to apply profit share for").makeOptionMandatory(true))
135
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
136
+ .action((opts) => managerApplyProfitShare(program, opts));
106
137
  program
107
138
  .command("manager-withdraw")
108
139
  .description("Make a withdraw from your vault")
109
140
  .addOption(new Option("--vault-address <address>", "Address of the vault to view").makeOptionMandatory(true))
141
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
110
142
  .action((opts) => managerWithdraw(program, opts));
111
143
  program
112
144
  .command("manager-cancel-withdraw")
113
145
  .description("Cancel a pending manager withdraw withdraw from your vault")
114
146
  .addOption(new Option("--vault-address <address>", "Address of the vault to view").makeOptionMandatory(true))
147
+ .addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
115
148
  .action((opts) => managerCancelWithdraw(program, opts));
116
149
  program
117
150
  .command("apply-profit-share-all")
@@ -6,6 +6,7 @@ export * from './managerRequestWithdraw';
6
6
  export * from './managerCancelWithdraw';
7
7
  export * from './managerWithdraw';
8
8
  export * from './managerUpdateVault';
9
+ export * from './managerUpdateVaultManager';
9
10
  export * from './managerUpdateVaultDelegate';
10
11
  export * from './applyProfitShare';
11
12
  export * from './initVaultDepositor';
@@ -14,7 +14,7 @@ import {
14
14
  encodeName,
15
15
  getVaultAddressSync,
16
16
  } from "../../src";
17
- import { getCommandContext } from "../utils";
17
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
18
18
  import { VAULT_PROGRAM_ID } from "../../src/types/types";
19
19
 
20
20
  export const initVault = async (program: Command, cmdOpts: OptionValues) => {
@@ -101,6 +101,7 @@ export const initVault = async (program: Command, cmdOpts: OptionValues) => {
101
101
  console.log(` ProfitShare: ${convertToNumber(profitShareBN, PERCENTAGE_PRECISION) * 100.0}%`);
102
102
  console.log(` Permissioned: ${permissioned}`);
103
103
  console.log(` Delegate: ${delegate.toBase58()}`);
104
+ console.log(` Manager: ${cmdOpts.manager ? cmdOpts.manager : driftClient.wallet.publicKey.toBase58()}`);
104
105
 
105
106
  const readline = require('readline').createInterface({
106
107
  input: process.stdin,
@@ -118,25 +119,49 @@ export const initVault = async (program: Command, cmdOpts: OptionValues) => {
118
119
  readline.close();
119
120
  process.exit(0);
120
121
  }
121
- console.log('Creating vault...');
122
-
123
- const initTx = await driftVault.initializeVault({
124
- name: vaultNameBytes,
125
- spotMarketIndex,
126
- redeemPeriod: new BN(redeemPeriodSec),
127
- maxTokens: maxTokensBN,
128
- managementFee: managementFeeBN,
129
- profitShare: profitShareBN.toNumber(),
130
- hurdleRate: 0,
131
- permissioned,
132
- minDepositAmount: minDepositAmountBN,
133
- });
134
- console.log(`Initialized vault, tx: https://solscan.io/tx/${initTx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
135
122
 
136
123
  const vaultAddress = getVaultAddressSync(VAULT_PROGRAM_ID, vaultNameBytes);
137
- console.log(`\nNew vault address: ${vaultAddress}\n`);
138
124
 
139
- console.log(`Updating the drift account delegate to: ${delegate}...`);
140
- const updateDelegateTx = await driftVault.updateDelegate(vaultAddress, delegate);
141
- console.log(`update delegate tx: https://solscan.io/tx/${updateDelegateTx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
125
+ if (cmdOpts.dumpTransactionMessage) {
126
+ const initIx = await driftVault.getInitializeVaultIx({
127
+ name: vaultNameBytes,
128
+ spotMarketIndex,
129
+ redeemPeriod: new BN(redeemPeriodSec),
130
+ maxTokens: maxTokensBN,
131
+ managementFee: managementFeeBN,
132
+ profitShare: profitShareBN.toNumber(),
133
+ hurdleRate: 0,
134
+ permissioned,
135
+ minDepositAmount: minDepositAmountBN,
136
+ manager: cmdOpts.manager,
137
+ });
138
+ const updateDelegateIx = await driftVault.getUpdateDelegateIx(vaultAddress, delegate);
139
+
140
+ console.log(`New vault address will be: ${vaultAddress.toBase58()}`);
141
+ console.log(`Setting trading delegate to: ${delegate.toBase58()}`);
142
+
143
+ console.log('');
144
+ console.log(`Base 58 encoded transaction:`);
145
+ console.log(dumpTransactionMessage(cmdOpts.manager ? new PublicKey(cmdOpts.manager) : driftClient.wallet.publicKey, [initIx, updateDelegateIx]));
146
+ } else {
147
+ const initTx = await driftVault.initializeVault({
148
+ name: vaultNameBytes,
149
+ spotMarketIndex,
150
+ redeemPeriod: new BN(redeemPeriodSec),
151
+ maxTokens: maxTokensBN,
152
+ managementFee: managementFeeBN,
153
+ profitShare: profitShareBN.toNumber(),
154
+ hurdleRate: 0,
155
+ permissioned,
156
+ minDepositAmount: minDepositAmountBN,
157
+ manager: cmdOpts.manager,
158
+ });
159
+ console.log(`Initialized vault, tx: https://solscan.io/tx/${initTx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
160
+
161
+ console.log(`\nNew vault address: ${vaultAddress}\n`);
162
+
163
+ console.log(`Updating the drift account delegate to: ${delegate}...`);
164
+ const updateDelegateTx = await driftVault.updateDelegate(vaultAddress, delegate);
165
+ console.log(`update delegate tx: https://solscan.io/tx/${updateDelegateTx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
166
+ }
142
167
  };
@@ -0,0 +1,32 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import {
3
+ OptionValues,
4
+ Command
5
+ } from "commander";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
+
8
+ export const managerApplyProfitShare = async (program: Command, cmdOpts: OptionValues) => {
9
+
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
+ const vaultDepositorAddress = new PublicKey(cmdOpts.vaultDepositor as string);
24
+
25
+ if (cmdOpts.dumpTransactionMessage) {
26
+ const tx = await driftVault.getApplyProfitShareIx(vaultAddress, vaultDepositorAddress);
27
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
28
+ } else {
29
+ const tx = await driftVault.applyProfitShare(vaultAddress, vaultDepositorAddress);
30
+ console.log(`Applied profit share: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
31
+ }
32
+ };
@@ -3,7 +3,7 @@ import {
3
3
  OptionValues,
4
4
  Command
5
5
  } from "commander";
6
- import { getCommandContext } from "../utils";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
7
 
8
8
  export const managerCancelWithdraw = async (program: Command, cmdOpts: OptionValues) => {
9
9
 
@@ -20,6 +20,11 @@ export const managerCancelWithdraw = async (program: Command, cmdOpts: OptionVal
20
20
  driftClient
21
21
  } = await getCommandContext(program, true);
22
22
 
23
- const tx = await driftVault.managerCancelWithdrawRequest(vaultAddress);
24
- console.log(`Canceled withdraw as vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
23
+ if (cmdOpts.dumpTransactionMessage) {
24
+ const tx = await driftVault.getManagerCancelWithdrawRequestIx(vaultAddress);
25
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
26
+ } else {
27
+ const tx = await driftVault.managerCancelWithdrawRequest(vaultAddress);
28
+ console.log(`Canceled withdraw as vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
29
+ }
25
30
  };
@@ -4,7 +4,7 @@ import {
4
4
  OptionValues,
5
5
  Command
6
6
  } from "commander";
7
- import { getCommandContext } from "../utils";
7
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
8
8
 
9
9
  export const managerDeposit = async (program: Command, cmdOpts: OptionValues) => {
10
10
 
@@ -29,6 +29,11 @@ export const managerDeposit = async (program: Command, cmdOpts: OptionValues) =>
29
29
  const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
30
30
  const depositBN = new BN(cmdOpts.amount * spotPrecision.toNumber());
31
31
 
32
- const tx = await driftVault.managerDeposit(vaultAddress, depositBN);
33
- console.log(`Deposited ${cmdOpts.amount} to vault as manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
32
+ if (cmdOpts.dumpTransactionMessage) {
33
+ const txs = await driftVault.getManagerDepositIx(vaultAddress, depositBN);
34
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, txs));
35
+ } else {
36
+ const tx = await driftVault.managerDeposit(vaultAddress, depositBN);
37
+ console.log(`Deposited ${cmdOpts.amount} to vault as manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
38
+ }
34
39
  };
@@ -4,7 +4,7 @@ import {
4
4
  OptionValues,
5
5
  Command
6
6
  } from "commander";
7
- import { getCommandContext } from "../utils";
7
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
8
8
  import { WithdrawUnit } from "../../src/types/types";
9
9
 
10
10
  export const managerRequestWithdraw = async (program: Command, cmdOpts: OptionValues) => {
@@ -27,8 +27,13 @@ export const managerRequestWithdraw = async (program: Command, cmdOpts: OptionVa
27
27
  }
28
28
 
29
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}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
30
+ if (cmdOpts.dumpTransactionMessage) {
31
+ const tx = await driftVault.getManagerRequestWithdrawIx(vaultAddress, new BN(cmdOpts.shares), WithdrawUnit.SHARES);
32
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
33
+ } else {
34
+ const tx = await driftVault.managerRequestWithdraw(vaultAddress, new BN(cmdOpts.shares), WithdrawUnit.SHARES);
35
+ console.log(`Requested to withraw ${cmdOpts.shares} shares as vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
36
+ }
32
37
  } else if (cmdOpts.amount && !cmdOpts.shares) {
33
38
  const vault = await driftVault.getVault(vaultAddress);
34
39
  const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
@@ -39,8 +44,15 @@ export const managerRequestWithdraw = async (program: Command, cmdOpts: OptionVa
39
44
  const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
40
45
  const amount = parseFloat(cmdOpts.amount);
41
46
  const amountBN = numberToSafeBN(amount, spotPrecision);
42
- const tx = await driftVault.managerRequestWithdraw(vaultAddress, amountBN, WithdrawUnit.TOKEN);
43
- console.log(`Requested to withdraw ${amount} ${decodeName(spotMarket.name)} as vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
47
+
48
+ if (cmdOpts.dumpTransactionMessage) {
49
+ const tx = await driftVault.getManagerRequestWithdrawIx(vaultAddress, amountBN, WithdrawUnit.TOKEN);
50
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
51
+ } else {
52
+ const tx = await driftVault.managerRequestWithdraw(vaultAddress, amountBN, WithdrawUnit.TOKEN);
53
+ console.log(`Requested to withdraw ${amount} ${decodeName(spotMarket.name)} as vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
54
+ }
55
+
44
56
 
45
57
  } else {
46
58
  console.error("Error: Either shares or amount must be provided, but not both.");
@@ -3,9 +3,9 @@ import {
3
3
  OptionValues,
4
4
  Command
5
5
  } from "commander";
6
- import { getCommandContext } from "../utils";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
7
 
8
- export const managerUpdateMarginTradingEnabled= async (program: Command, cmdOpts: OptionValues) => {
8
+ export const managerUpdateMarginTradingEnabled = async (program: Command, cmdOpts: OptionValues) => {
9
9
 
10
10
  let vaultAddress: PublicKey;
11
11
  try {
@@ -22,6 +22,11 @@ export const managerUpdateMarginTradingEnabled= async (program: Command, cmdOpts
22
22
 
23
23
  const enabled = cmdOpts.enabled ? (cmdOpts.enabled as string).toLowerCase() === "true" : false;
24
24
 
25
- const tx = await driftVault.updateMarginTradingEnabled(vaultAddress, enabled);
26
- console.log(`Updated margin trading vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
25
+ if (cmdOpts.dumpTransactionMessage) {
26
+ const tx = await driftVault.getUpdateMarginTradingEnabledIx(vaultAddress, enabled);
27
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
28
+ } else {
29
+ const tx = await driftVault.updateMarginTradingEnabled(vaultAddress, enabled);
30
+ console.log(`Updated margin trading vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
31
+ }
27
32
  };
@@ -0,0 +1,36 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import {
3
+ OptionValues,
4
+ Command
5
+ } from "commander";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
+
8
+ export const managerUpdatePoolId = async (program: Command, cmdOpts: OptionValues) => {
9
+
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
+ const poolId = cmdOpts.poolId ? Number(cmdOpts.poolId) : null;
24
+ if (poolId === null) {
25
+ console.error("Invalid pool id");
26
+ process.exit(1);
27
+ }
28
+
29
+ if (cmdOpts.dumpTransactionMessage) {
30
+ const tx = await driftVault.getUpdatePoolIdIx(vaultAddress, poolId);
31
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
32
+ } else {
33
+ const tx = await driftVault.updateUserPoolId(vaultAddress, poolId);
34
+ console.log(`Updated pool id vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
35
+ }
36
+ };
@@ -3,7 +3,7 @@ import {
3
3
  OptionValues,
4
4
  Command
5
5
  } from "commander";
6
- import { getCommandContext } from "../utils";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
7
  import { BN, PERCENTAGE_PRECISION, TEN, convertToNumber, decodeName } from "@drift-labs/sdk";
8
8
 
9
9
  export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues) => {
@@ -122,9 +122,14 @@ export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues
122
122
  let done = false;
123
123
  while (!done) {
124
124
  try {
125
- const tx = await driftVault.managerUpdateVault(vaultAddress, newParams);
126
- console.log(`Updated vault params as vault manager: https://solana.fm/tx/${tx}`);
127
- done = true;
125
+ if (cmdOpts.dumpTransactionMessage) {
126
+ const tx = await driftVault.getManagerUpdateVaultIx(vaultAddress, newParams);
127
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
128
+ } else {
129
+ const tx = await driftVault.managerUpdateVault(vaultAddress, newParams);
130
+ console.log(`Updated vault params as vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
131
+ done = true;
132
+ }
128
133
  break;
129
134
  } catch (e) {
130
135
  const err = e as Error;
@@ -3,7 +3,7 @@ import {
3
3
  OptionValues,
4
4
  Command
5
5
  } from "commander";
6
- import { getCommandContext } from "../utils";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
7
 
8
8
  export const managerUpdateVaultDelegate = async (program: Command, cmdOpts: OptionValues) => {
9
9
 
@@ -31,6 +31,12 @@ export const managerUpdateVaultDelegate = async (program: Command, cmdOpts: Opti
31
31
  }
32
32
  }
33
33
 
34
- const tx = await driftVault.updateDelegate(vaultAddress, delegate);
35
- console.log(`Updated vault delegate to ${delegate.toBase58()}: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
34
+ if (cmdOpts.dumpTransactionMessage) {
35
+ const tx = await driftVault.getUpdateDelegateIx(vaultAddress, delegate);
36
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
37
+ } else {
38
+ const tx = await driftVault.updateDelegate(vaultAddress, delegate);
39
+ console.log(`Updated vault delegate to ${delegate.toBase58()}: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
40
+ }
41
+
36
42
  };
@@ -0,0 +1,77 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ import {
3
+ OptionValues,
4
+ Command
5
+ } from "commander";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
+
8
+ export const managerUpdateVaultManager = async (program: Command, cmdOpts: OptionValues) => {
9
+
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
+ let manager: PublicKey;
19
+ try {
20
+ manager = new PublicKey(cmdOpts.newManager as string);
21
+ } catch (err) {
22
+ console.error("Invalid manager address");
23
+ process.exit(1);
24
+ }
25
+
26
+ const {
27
+ driftVault,
28
+ driftClient,
29
+ } = await getCommandContext(program, true);
30
+
31
+ const vault = await driftVault.getVault(vaultAddress);
32
+
33
+ console.log(`Updating vault manager:`);
34
+ console.log(` Current manager: ${vault.manager.toString()}`);
35
+ console.log(` New manager: ${manager.toString()}`);
36
+
37
+ const readline = require('readline').createInterface({
38
+ input: process.stdin,
39
+ output: process.stdout
40
+ });
41
+ console.log('');
42
+ const answer = await new Promise(resolve => {
43
+ readline.question('Is the above information correct? (yes/no) ', (answer: string) => {
44
+ readline.close();
45
+ resolve(answer);
46
+ });
47
+ });
48
+ if ((answer as string).toLowerCase() !== 'yes') {
49
+ console.log('Vault manager update canceled.');
50
+ process.exit(0);
51
+ }
52
+ console.log('Updating vault manager...');
53
+
54
+ let done = false;
55
+ while (!done) {
56
+ try {
57
+ if (cmdOpts.dumpTransactionMessage) {
58
+ const tx = await driftVault.getManagerUpdateVaultManagerIx(vaultAddress, manager);
59
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
60
+ } else {
61
+ const tx = await driftVault.managerUpdateVaultManager(vaultAddress, manager);
62
+ console.log(`Updated vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
63
+ done = true;
64
+ }
65
+ break;
66
+ } catch (e) {
67
+ const err = e as Error;
68
+ if (err.message.includes('TransactionExpiredTimeoutError')) {
69
+ console.log(err.message);
70
+ console.log('Transaction timeout. Retrying...');
71
+ await new Promise(resolve => setTimeout(resolve, 5000));
72
+ } else {
73
+ throw err;
74
+ }
75
+ }
76
+ }
77
+ };
@@ -3,7 +3,7 @@ import {
3
3
  OptionValues,
4
4
  Command
5
5
  } from "commander";
6
- import { getCommandContext } from "../utils";
6
+ import { dumpTransactionMessage, getCommandContext } from "../utils";
7
7
 
8
8
  export const managerWithdraw = async (program: Command, cmdOpts: OptionValues) => {
9
9
 
@@ -20,6 +20,11 @@ export const managerWithdraw = async (program: Command, cmdOpts: OptionValues) =
20
20
  driftClient
21
21
  } = await getCommandContext(program, true);
22
22
 
23
- const tx = await driftVault.managerWithdraw(vaultAddress);
24
- console.log(`Withrew as vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
23
+ if (cmdOpts.dumpTransactionMessage) {
24
+ const tx = await driftVault.getManagerWithdrawIx(vaultAddress);
25
+ console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
26
+ } else {
27
+ const tx = await driftVault.managerWithdraw(vaultAddress);
28
+ console.log(`Withrew as vault manager: https://solscan.io/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
29
+ }
25
30
  };
package/cli/utils.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { BASE_PRECISION, BN, DriftClient, DriftEnv, OraclePriceData, PRICE_PRECISION, QUOTE_PRECISION, SpotMarketAccount, TEN, User, Wallet, WhileValidTxSender, 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
- import { Connection, Keypair } from "@solana/web3.js";
4
+ import { Connection, Keypair, PublicKey, Transaction, TransactionInstruction } from "@solana/web3.js";
5
5
  import { AnchorProvider, Wallet as AnchorWallet } from "@coral-xyz/anchor";
6
6
  import * as anchor from '@coral-xyz/anchor';
7
7
  import { IDL } from "../src/types/drift_vaults";
8
8
  import { getLedgerWallet } from "./ledgerWallet";
9
9
  import fs from 'fs';
10
+ import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
10
11
 
11
12
 
12
13
  export async function printVault(slot: number, driftClient: DriftClient, vault: Vault, vaultEquity: BN, spotMarket: SpotMarketAccount, spotOracle: OraclePriceData) {
@@ -202,3 +203,15 @@ export async function getCommandContext(program: Command, needToSign: boolean):
202
203
  wallet,
203
204
  };
204
205
  }
206
+
207
+ /// a valid blockhash to allow tx simulation
208
+ export const BLOCKHASH_PLACEHOLDER = 'CHNfFRxxeCTyy1RRnKGsV2dkrJfKwVEa8zE7cZgK4TSe';
209
+
210
+ export function dumpTransactionMessage(payer: PublicKey, ixs: Array<TransactionInstruction>): string {
211
+ const tx = new Transaction();
212
+ tx.add(...ixs);
213
+ tx.feePayer = payer;
214
+ tx.recentBlockhash = BLOCKHASH_PLACEHOLDER;
215
+
216
+ return bs58.encode(tx.serialize({ requireAllSignatures: false }));
217
+ }
@@ -307,6 +307,27 @@ export type DriftVaults = {
307
307
  }
308
308
  ];
309
309
  },
310
+ {
311
+ name: 'updateVaultManager';
312
+ accounts: [
313
+ {
314
+ name: 'vault';
315
+ isMut: true;
316
+ isSigner: false;
317
+ },
318
+ {
319
+ name: 'manager';
320
+ isMut: false;
321
+ isSigner: true;
322
+ }
323
+ ];
324
+ args: [
325
+ {
326
+ name: 'manager';
327
+ type: 'publicKey';
328
+ }
329
+ ];
330
+ },
310
331
  {
311
332
  name: 'updateCumulativeFuelAmount';
312
333
  accounts: [
@@ -310,6 +310,27 @@ exports.IDL = {
310
310
  },
311
311
  ],
312
312
  },
313
+ {
314
+ name: 'updateVaultManager',
315
+ accounts: [
316
+ {
317
+ name: 'vault',
318
+ isMut: true,
319
+ isSigner: false,
320
+ },
321
+ {
322
+ name: 'manager',
323
+ isMut: false,
324
+ isSigner: true,
325
+ },
326
+ ],
327
+ args: [
328
+ {
329
+ name: 'manager',
330
+ type: 'publicKey',
331
+ },
332
+ ],
333
+ },
313
334
  {
314
335
  name: 'updateCumulativeFuelAmount',
315
336
  accounts: [