@drift-labs/vaults-sdk 0.6.30 → 0.6.32
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 +31 -2
- package/cli/commands/adminDeleteFeeUpdate.ts +73 -0
- package/cli/commands/adminInitFeeUpdate.ts +73 -0
- package/cli/commands/applyProfitShare.ts +5 -2
- package/cli/commands/decodeLogs.ts +3 -2
- package/cli/commands/deposit.ts +2 -2
- package/cli/commands/forceWithdrawAll.ts +1 -1
- package/cli/commands/index.ts +2 -0
- package/cli/commands/initVault.ts +35 -35
- package/cli/commands/managerApplyProfitShare.ts +1 -1
- package/cli/commands/managerCancelWithdraw.ts +1 -1
- package/cli/commands/managerDeposit.ts +1 -1
- package/cli/commands/managerRequestWithdraw.ts +2 -2
- package/cli/commands/managerUpdateFees.ts +121 -0
- package/cli/commands/managerUpdateMarginTradingEnabled.ts +1 -1
- package/cli/commands/managerUpdatePoolId.ts +1 -1
- package/cli/commands/managerUpdateVault.ts +13 -2
- package/cli/commands/managerUpdateVaultDelegate.ts +1 -1
- package/cli/commands/managerUpdateVaultManager.ts +1 -1
- package/cli/commands/managerWithdraw.ts +1 -1
- package/cli/commands/requestWithdraw.ts +1 -1
- package/cli/commands/viewVault.ts +12 -1
- package/cli/commands/withdraw.ts +1 -1
- package/cli/utils.ts +12 -3
- package/lib/addresses.d.ts +1 -0
- package/lib/addresses.d.ts.map +1 -1
- package/lib/addresses.js +7 -0
- package/lib/constants/index.d.ts +2 -0
- package/lib/constants/index.d.ts.map +1 -1
- package/lib/constants/index.js +3 -1
- package/lib/types/drift_vaults.d.ts +275 -1
- package/lib/types/drift_vaults.d.ts.map +1 -1
- package/lib/types/drift_vaults.js +275 -1
- package/lib/types/types.d.ts +33 -0
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js +11 -1
- package/lib/vaultClient.d.ts +22 -1
- package/lib/vaultClient.d.ts.map +1 -1
- package/lib/vaultClient.js +115 -22
- package/package.json +1 -1
- package/src/addresses.ts +13 -0
- package/src/constants/index.ts +5 -0
- package/src/idl/drift_vaults.json +281 -1
- package/src/types/drift_vaults.ts +550 -2
- package/src/types/types.ts +33 -0
- package/src/vaultClient.ts +229 -22
package/cli/cli.ts
CHANGED
|
@@ -28,6 +28,9 @@ import { Command, Option } from 'commander';
|
|
|
28
28
|
import { viewVaultDepositor } from "./commands/viewVaultDepositor";
|
|
29
29
|
import { managerUpdatePoolId } from "./commands/managerUpdatePoolId";
|
|
30
30
|
import { managerApplyProfitShare } from "./commands/managerApplyProfitShare";
|
|
31
|
+
import { managerUpdateFees } from "./commands/managerUpdateFees";
|
|
32
|
+
import { adminInitFeeUpdate } from "./commands/adminInitFeeUpdate";
|
|
33
|
+
import { adminDeleteFeeUpdate } from "./commands/adminDeleteFeeUpdate";
|
|
31
34
|
|
|
32
35
|
const program = new Command();
|
|
33
36
|
program
|
|
@@ -94,8 +97,9 @@ program
|
|
|
94
97
|
.option("-r, --redeem-period <number>", "The new redeem period (can only be lowered)")
|
|
95
98
|
.option("-x, --max-tokens <number>", "The max tokens the vault can accept")
|
|
96
99
|
.option("-a, --min-deposit-amount <number", "The minimum token amount allowed to deposit")
|
|
97
|
-
.option("-m, --management-fee <percent>", "The new management fee (can only be lowered)")
|
|
98
|
-
.option("-s, --profit-share <percent>", "The new profit share percentage (can only be lowered)")
|
|
100
|
+
.option("-m, --management-fee <percent>", "The new management fee (can only be lowered, use timelocked manager-update-fees to raise)")
|
|
101
|
+
.option("-s, --profit-share <percent>", "The new profit share percentage (can only be lowered, use timelocked manager-update-fees to raise)")
|
|
102
|
+
.option("-h, --hurdle-rate <percent>", "The new hurdle rate percentage (can only be raised, use timelocked manager-update-fees to lower)")
|
|
99
103
|
.option("-p, --permissioned <boolean>", "Set the vault as permissioned (true) or open (false)")
|
|
100
104
|
.addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
|
|
101
105
|
.action((opts) => managerUpdateVault(program, opts));
|
|
@@ -206,6 +210,31 @@ program
|
|
|
206
210
|
|
|
207
211
|
.action((opts) => vaultInvariantChecks(program, opts));
|
|
208
212
|
|
|
213
|
+
program
|
|
214
|
+
.command("manager-update-fees")
|
|
215
|
+
.description("Update vault fees for a manager")
|
|
216
|
+
.addOption(new Option("--vault-address <address>", "Address of the vault to update").makeOptionMandatory(true))
|
|
217
|
+
.option("-t, --timelock-duration <number>", "The new timelock duration in seconds, must be at least the greater of 1 day, or the current redeem period (default: minimum duration)")
|
|
218
|
+
.option("-m, --management-fee <percent>", "The new management fee percentage")
|
|
219
|
+
.option("-s, --profit-share <percent>", "The new profit share percentage")
|
|
220
|
+
.option("-h, --hurdle-rate <percent>", "The new hurdle rate percentage")
|
|
221
|
+
.addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
|
|
222
|
+
.action((opts) => managerUpdateFees(program, opts));
|
|
223
|
+
|
|
224
|
+
program
|
|
225
|
+
.command("admin-init-fee-update")
|
|
226
|
+
.description("Admin initialize a fee update for a vault")
|
|
227
|
+
.addOption(new Option("--vault-address <address>", "Address of the vault to initialize fee update for").makeOptionMandatory(true))
|
|
228
|
+
.addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
|
|
229
|
+
.action((opts) => adminInitFeeUpdate(program, opts));
|
|
230
|
+
|
|
231
|
+
program
|
|
232
|
+
.command("admin-delete-fee-update")
|
|
233
|
+
.description("Admin delete a fee update for a vault")
|
|
234
|
+
.addOption(new Option("--vault-address <address>", "Address of the vault to delete fee update for").makeOptionMandatory(true))
|
|
235
|
+
.addOption(new Option("--dump-transaction-message", "Dump the transaction message to the console").makeOptionMandatory(false))
|
|
236
|
+
.action((opts) => adminDeleteFeeUpdate(program, opts));
|
|
237
|
+
|
|
209
238
|
program.parseAsync().then(() => {
|
|
210
239
|
process.exit(0);
|
|
211
240
|
});
|
|
@@ -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
|
+
};
|
|
@@ -37,8 +37,11 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
|
|
|
37
37
|
const thresholdBN = numberToSafeBN(thresholdNumber, spotMarketPrecision);
|
|
38
38
|
let pendingProfitShareToRealize = ZERO;
|
|
39
39
|
const vdWithPendingProfitShare = vdWithNoWithdrawRequests.filter((vd: ProgramAccount<VaultDepositor>) => {
|
|
40
|
+
if (vault.managementFee.gt(ZERO)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
40
43
|
const pendingProfitShares = calculateApplyProfitShare(vd.account, vaultEquitySpot, vault);
|
|
41
|
-
const doRealize = pendingProfitShares.profitShareAmount.
|
|
44
|
+
const doRealize = pendingProfitShares.profitShareAmount.gte(thresholdBN);
|
|
42
45
|
if (doRealize) {
|
|
43
46
|
pendingProfitShareToRealize = pendingProfitShareToRealize.add(pendingProfitShares.profitShareAmount);
|
|
44
47
|
return true;
|
|
@@ -83,7 +86,7 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
|
|
|
83
86
|
|
|
84
87
|
try {
|
|
85
88
|
const txid = await driftClient.connection.sendTransaction(tx);
|
|
86
|
-
console.log(`Sent chunk:
|
|
89
|
+
console.log(`Sent chunk: https://solana.fm/tx/${txid}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
87
90
|
} catch (e) {
|
|
88
91
|
console.error(`Error sending chunk: ${e}`);
|
|
89
92
|
console.log((e as SendTransactionError).logs);
|
|
@@ -30,10 +30,13 @@ export const decodeLogs = async (program: Command, cmdOpts: OptionValues) => {
|
|
|
30
30
|
maxSupportedTransactionVersion: 0,
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
let i = 0;
|
|
33
34
|
// @ts-ignore
|
|
34
35
|
for (const event of driftVault.program._events._eventParser.parseLogs(
|
|
35
36
|
tx!.meta!.logMessages
|
|
36
37
|
)) {
|
|
38
|
+
console.log(`--------------- Event: ${i} ${event.name} -----------------`);
|
|
39
|
+
i++;
|
|
37
40
|
|
|
38
41
|
/* eslint-disable no-case-declarations */
|
|
39
42
|
switch (event.name) {
|
|
@@ -63,12 +66,10 @@ export const decodeLogs = async (program: Command, cmdOpts: OptionValues) => {
|
|
|
63
66
|
console.log(` depositOraclePrice: ${data.depositOraclePrice?.toNumber()}`);
|
|
64
67
|
break;
|
|
65
68
|
default:
|
|
66
|
-
console.log(event);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
console.log("----------Raw Event-------------");
|
|
70
72
|
console.log(event);
|
|
71
|
-
console.log("--------------------------------");
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
};
|
package/cli/commands/deposit.ts
CHANGED
|
@@ -57,7 +57,7 @@ export const deposit = async (program: Command, cmdOpts: OptionValues) => {
|
|
|
57
57
|
authority: depositAuthority,
|
|
58
58
|
vault: vaultAddress
|
|
59
59
|
});
|
|
60
|
-
console.log(`Deposited ${cmdOpts.amount} to vault: https://
|
|
60
|
+
console.log(`Deposited ${cmdOpts.amount} to vault: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
61
61
|
} else {
|
|
62
62
|
// VaultDepositor exists
|
|
63
63
|
const vaultAddress = vaultDepositorAccount.vault;
|
|
@@ -71,6 +71,6 @@ export const deposit = async (program: Command, cmdOpts: OptionValues) => {
|
|
|
71
71
|
|
|
72
72
|
console.log(`depositing (existing VaultDepositor account): ${depositBN.toString()}`);
|
|
73
73
|
const tx = await driftVault.deposit(vaultDepositorAddress, depositBN);
|
|
74
|
-
console.log(`Deposited ${cmdOpts.amount} to vault: https://
|
|
74
|
+
console.log(`Deposited ${cmdOpts.amount} to vault: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
75
75
|
}
|
|
76
76
|
};
|
|
@@ -97,7 +97,7 @@ export const forceWithdrawAll = async (program: Command, cmdOpts: OptionValues)
|
|
|
97
97
|
console.log(`Sending chunk: ${bs58.encode(tx.signatures[0])}`);
|
|
98
98
|
try {
|
|
99
99
|
const txid = await driftClient.connection.sendTransaction(tx);
|
|
100
|
-
console.log(`Sent chunk: https://
|
|
100
|
+
console.log(`Sent chunk: https://solana.fm/tx/${txid}`);
|
|
101
101
|
} catch (e) {
|
|
102
102
|
console.error(`Error sending chunk: ${e}`);
|
|
103
103
|
console.log((e as SendTransactionError).logs);
|
package/cli/commands/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
TEN,
|
|
6
6
|
convertToNumber,
|
|
7
7
|
decodeName,
|
|
8
|
+
getSignedMsgUserAccountPublicKey,
|
|
8
9
|
} from "@drift-labs/sdk";
|
|
9
10
|
import {
|
|
10
11
|
OptionValues,
|
|
@@ -122,8 +123,8 @@ export const initVault = async (program: Command, cmdOpts: OptionValues) => {
|
|
|
122
123
|
|
|
123
124
|
const vaultAddress = getVaultAddressSync(VAULT_PROGRAM_ID, vaultNameBytes);
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
const ixs = [
|
|
127
|
+
await driftVault.getInitializeVaultIx({
|
|
127
128
|
name: vaultNameBytes,
|
|
128
129
|
spotMarketIndex,
|
|
129
130
|
redeemPeriod: new BN(redeemPeriodSec),
|
|
@@ -134,42 +135,41 @@ export const initVault = async (program: Command, cmdOpts: OptionValues) => {
|
|
|
134
135
|
permissioned,
|
|
135
136
|
minDepositAmount: minDepositAmountBN,
|
|
136
137
|
manager: cmdOpts.manager,
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
}),
|
|
139
|
+
await driftVault.getUpdateDelegateIx(vaultAddress, delegate)
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
const signedOrdersAccountAddress = getSignedMsgUserAccountPublicKey(
|
|
143
|
+
driftClient.program.programId,
|
|
144
|
+
vaultAddress,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
let swiftUsersAccountExists = false;
|
|
148
|
+
try {
|
|
149
|
+
const acc = await driftClient.connection.getAccountInfo(signedOrdersAccountAddress);
|
|
150
|
+
swiftUsersAccountExists = acc !== null;
|
|
151
|
+
} catch (_err) {
|
|
152
|
+
// Error getting account info is non-critical, default to false
|
|
153
|
+
}
|
|
142
154
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
8
|
|
155
|
+
if (!swiftUsersAccountExists) {
|
|
156
|
+
ixs.push(
|
|
157
|
+
await driftClient.getInitializeSignedMsgUserOrdersAccountIx(
|
|
158
|
+
vaultAddress,
|
|
159
|
+
8
|
|
160
|
+
)[1]
|
|
150
161
|
);
|
|
151
|
-
|
|
152
|
-
name: vaultNameBytes,
|
|
153
|
-
spotMarketIndex,
|
|
154
|
-
redeemPeriod: new BN(redeemPeriodSec),
|
|
155
|
-
maxTokens: maxTokensBN,
|
|
156
|
-
managementFee: managementFeeBN,
|
|
157
|
-
profitShare: profitShareBN.toNumber(),
|
|
158
|
-
hurdleRate: 0,
|
|
159
|
-
permissioned,
|
|
160
|
-
minDepositAmount: minDepositAmountBN,
|
|
161
|
-
manager: cmdOpts.manager,
|
|
162
|
-
});
|
|
163
|
-
const initTx = await driftVault.createAndSendTxn([
|
|
164
|
-
initSignedOrdersAccIx[1],
|
|
165
|
-
initIx,
|
|
166
|
-
]);
|
|
167
|
-
console.log(`Initialized vault, tx: https://solscan.io/tx/${initTx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
|
|
162
|
+
}
|
|
168
163
|
|
|
169
|
-
|
|
164
|
+
console.log(`New vault address will be: ${vaultAddress.toBase58()}`);
|
|
165
|
+
console.log(`Setting trading delegate to: ${delegate.toBase58()}`);
|
|
166
|
+
console.log('');
|
|
170
167
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
console.log(
|
|
168
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
169
|
+
console.log(`Base 58 encoded transaction:`);
|
|
170
|
+
console.log(dumpTransactionMessage(cmdOpts.manager ? new PublicKey(cmdOpts.manager) : driftClient.wallet.publicKey, ixs));
|
|
171
|
+
} else {
|
|
172
|
+
const initTx = await driftVault.createAndSendTxn(ixs);
|
|
173
|
+
console.log(`Initialized vault, tx: https://solana.fm/tx/${initTx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
174
174
|
}
|
|
175
175
|
};
|
|
@@ -27,6 +27,6 @@ export const managerApplyProfitShare = async (program: Command, cmdOpts: OptionV
|
|
|
27
27
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
28
28
|
} else {
|
|
29
29
|
const tx = await driftVault.applyProfitShare(vaultAddress, vaultDepositorAddress);
|
|
30
|
-
console.log(`Applied profit share: https://
|
|
30
|
+
console.log(`Applied profit share: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
31
31
|
}
|
|
32
32
|
};
|
|
@@ -25,6 +25,6 @@ export const managerCancelWithdraw = async (program: Command, cmdOpts: OptionVal
|
|
|
25
25
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
26
26
|
} else {
|
|
27
27
|
const tx = await driftVault.managerCancelWithdrawRequest(vaultAddress);
|
|
28
|
-
console.log(`Canceled withdraw as vault manager: https://
|
|
28
|
+
console.log(`Canceled withdraw as vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
@@ -34,6 +34,6 @@ export const managerDeposit = async (program: Command, cmdOpts: OptionValues) =>
|
|
|
34
34
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, txs));
|
|
35
35
|
} else {
|
|
36
36
|
const tx = await driftVault.managerDeposit(vaultAddress, depositBN);
|
|
37
|
-
console.log(`Deposited ${cmdOpts.amount} to vault as manager: https://
|
|
37
|
+
console.log(`Deposited ${cmdOpts.amount} to vault as manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
38
38
|
}
|
|
39
39
|
};
|
|
@@ -32,7 +32,7 @@ export const managerRequestWithdraw = async (program: Command, cmdOpts: OptionVa
|
|
|
32
32
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
33
33
|
} else {
|
|
34
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://
|
|
35
|
+
console.log(`Requested to withraw ${cmdOpts.shares} shares as vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
36
36
|
}
|
|
37
37
|
} else if (cmdOpts.amount && !cmdOpts.shares) {
|
|
38
38
|
const vault = await driftVault.getVault(vaultAddress);
|
|
@@ -50,7 +50,7 @@ export const managerRequestWithdraw = async (program: Command, cmdOpts: OptionVa
|
|
|
50
50
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
51
51
|
} else {
|
|
52
52
|
const tx = await driftVault.managerRequestWithdraw(vaultAddress, amountBN, WithdrawUnit.TOKEN);
|
|
53
|
-
console.log(`Requested to withdraw ${amount} ${decodeName(spotMarket.name)} as vault manager: https://
|
|
53
|
+
console.log(`Requested to withdraw ${amount} ${decodeName(spotMarket.name)} as vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import {
|
|
3
|
+
OptionValues,
|
|
4
|
+
Command
|
|
5
|
+
} from "commander";
|
|
6
|
+
import { dumpTransactionMessage, getCommandContext } from "../utils";
|
|
7
|
+
import { BN, PERCENTAGE_PRECISION, convertToNumber } from "@drift-labs/sdk";
|
|
8
|
+
|
|
9
|
+
export const managerUpdateFees = 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
|
+
const vault = await driftVault.getVault(vaultAddress);
|
|
24
|
+
|
|
25
|
+
const timelockDuration = cmdOpts.timelockDuration;
|
|
26
|
+
let timelockDurationBN: BN | null = null;
|
|
27
|
+
// const minTimelockDurationBN = new BN(Math.max(1 * 24 * 60 * 60, vault.redeemPeriod.toNumber()));
|
|
28
|
+
const minTimelockDurationBN = new BN(Math.max(1 * 60 * 60, vault.redeemPeriod.toNumber()));
|
|
29
|
+
if (timelockDuration !== undefined && timelockDuration !== null) {
|
|
30
|
+
timelockDurationBN = new BN(parseInt(timelockDuration));
|
|
31
|
+
if (timelockDurationBN.lt(minTimelockDurationBN)) {
|
|
32
|
+
throw new Error(`Timelock duration must be at least ${minTimelockDurationBN.toNumber()} seconds`);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
timelockDurationBN = minTimelockDurationBN;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let managementFee = cmdOpts.managementFee;
|
|
39
|
+
let managementFeeBN: BN | null = null;
|
|
40
|
+
if (managementFee !== undefined && managementFee !== null) {
|
|
41
|
+
managementFee = parseInt(managementFee);
|
|
42
|
+
managementFeeBN = new BN(managementFee).mul(PERCENTAGE_PRECISION).div(new BN(100));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let profitShare = cmdOpts.profitShare;
|
|
46
|
+
let profitShareNumber: number | null = null;
|
|
47
|
+
if (profitShare !== undefined && profitShare !== null) {
|
|
48
|
+
profitShare = parseInt(profitShare);
|
|
49
|
+
profitShareNumber = profitShare * PERCENTAGE_PRECISION.toNumber() / 100.0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let hurdleRate = cmdOpts.hurdleRate;
|
|
53
|
+
let hurdleRateNumber: number | null = null;
|
|
54
|
+
if (hurdleRate !== undefined && hurdleRate !== null) {
|
|
55
|
+
hurdleRate = parseInt(hurdleRate);
|
|
56
|
+
hurdleRateNumber = hurdleRate * PERCENTAGE_PRECISION.toNumber() / 100.0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(`Updating fees, effective in ${timelockDurationBN?.toNumber()} seconds`);
|
|
60
|
+
|
|
61
|
+
const managementFeeBefore = convertToNumber(vault.managementFee, PERCENTAGE_PRECISION) * 100.0;
|
|
62
|
+
const managementFeeAfter = managementFeeBN ? `${convertToNumber(managementFeeBN, PERCENTAGE_PRECISION) * 100.0}%` : 'unchanged';
|
|
63
|
+
console.log(` ManagementFee: ${managementFeeBefore}% -> ${managementFeeAfter}`);
|
|
64
|
+
|
|
65
|
+
const profitShareBefore = vault.profitShare / PERCENTAGE_PRECISION.toNumber() * 100.0;
|
|
66
|
+
const profitShareAfter = profitShareNumber !== null ? `${profitShareNumber / PERCENTAGE_PRECISION.toNumber() * 100.0}%` : 'unchanged';
|
|
67
|
+
console.log(` ProfitShare: ${profitShareBefore}% -> ${profitShareAfter}`);
|
|
68
|
+
|
|
69
|
+
const hurdleRateBefore = vault.hurdleRate / PERCENTAGE_PRECISION.toNumber() * 100.0;
|
|
70
|
+
const hurdleRateAfter = hurdleRateNumber !== null ? `${hurdleRateNumber / PERCENTAGE_PRECISION.toNumber() * 100.0}%` : 'unchanged';
|
|
71
|
+
console.log(` HurdleRate: ${hurdleRateBefore}% -> ${hurdleRateAfter}`);
|
|
72
|
+
|
|
73
|
+
const readline = require('readline').createInterface({
|
|
74
|
+
input: process.stdin,
|
|
75
|
+
output: process.stdout
|
|
76
|
+
});
|
|
77
|
+
console.log('');
|
|
78
|
+
const answer = await new Promise(resolve => {
|
|
79
|
+
readline.question('Is the above information correct? (yes/no) ', (answer: string) => {
|
|
80
|
+
readline.close();
|
|
81
|
+
resolve(answer);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
if ((answer as string).toLowerCase() !== 'yes') {
|
|
85
|
+
console.log('Fee update canceled.');
|
|
86
|
+
readline.close();
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
89
|
+
console.log('Updating fees...');
|
|
90
|
+
|
|
91
|
+
const newParams = {
|
|
92
|
+
timelockDuration: timelockDurationBN,
|
|
93
|
+
newManagementFee: managementFeeBN,
|
|
94
|
+
newProfitShare: profitShareNumber,
|
|
95
|
+
newHurdleRate: hurdleRateNumber,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
let done = false;
|
|
99
|
+
while (!done) {
|
|
100
|
+
try {
|
|
101
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
102
|
+
const tx = await driftVault.getManagerUpdateFeesIx(vaultAddress, newParams);
|
|
103
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
104
|
+
} else {
|
|
105
|
+
const tx = await driftVault.managerUpdateFees(vaultAddress, newParams);
|
|
106
|
+
console.log(`Updated vault fees as vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
107
|
+
done = true;
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
} catch (e) {
|
|
111
|
+
const err = e as Error;
|
|
112
|
+
if (err.message.includes('TransactionExpiredTimeoutError')) {
|
|
113
|
+
console.log(err.message);
|
|
114
|
+
console.log('Transaction timeout. Retrying...');
|
|
115
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
116
|
+
} else {
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
@@ -27,6 +27,6 @@ export const managerUpdateMarginTradingEnabled = async (program: Command, cmdOpt
|
|
|
27
27
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
28
28
|
} else {
|
|
29
29
|
const tx = await driftVault.updateMarginTradingEnabled(vaultAddress, enabled);
|
|
30
|
-
console.log(`Updated margin trading vault manager: https://
|
|
30
|
+
console.log(`Updated margin trading vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
31
31
|
}
|
|
32
32
|
};
|
|
@@ -31,6 +31,6 @@ export const managerUpdatePoolId = async (program: Command, cmdOpts: OptionValue
|
|
|
31
31
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
32
32
|
} else {
|
|
33
33
|
const tx = await driftVault.updateUserPoolId(vaultAddress, poolId);
|
|
34
|
-
console.log(`Updated pool id vault manager: https://
|
|
34
|
+
console.log(`Updated pool id vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
35
35
|
}
|
|
36
36
|
};
|
|
@@ -57,6 +57,13 @@ export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues
|
|
|
57
57
|
profitShareNumber = profitShare * PERCENTAGE_PRECISION.toNumber() / 100.0;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
let hurdleRate = cmdOpts.hurdleRate;
|
|
61
|
+
let hurdleRateNumber: number | null = null;
|
|
62
|
+
if (hurdleRate !== undefined && hurdleRate !== null) {
|
|
63
|
+
hurdleRate = parseInt(hurdleRate);
|
|
64
|
+
hurdleRateNumber = hurdleRate * PERCENTAGE_PRECISION.toNumber() / 100.0;
|
|
65
|
+
}
|
|
66
|
+
|
|
60
67
|
let minDepositAmount = cmdOpts.minDepositAmount;
|
|
61
68
|
let minDepositAmountBN: BN | null = null;
|
|
62
69
|
if (minDepositAmount !== undefined && minDepositAmount !== null) {
|
|
@@ -85,6 +92,10 @@ export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues
|
|
|
85
92
|
const profitShareAfter = profitShareNumber !== null ? `${profitShareNumber / PERCENTAGE_PRECISION.toNumber() * 100.0}%` : 'unchanged';
|
|
86
93
|
console.log(` ProfitShare: ${profitShareBefore}% -> ${profitShareAfter}`);
|
|
87
94
|
|
|
95
|
+
const hurdleRateBefore = vault.hurdleRate / PERCENTAGE_PRECISION.toNumber() * 100.0;
|
|
96
|
+
const hurdleRateAfter = hurdleRateNumber !== null ? `${hurdleRateNumber / PERCENTAGE_PRECISION.toNumber() * 100.0}%` : 'unchanged';
|
|
97
|
+
console.log(` HurdleRate: ${hurdleRateBefore}% -> ${hurdleRateAfter}`);
|
|
98
|
+
|
|
88
99
|
const permissioned: boolean | null = (cmdOpts.permissioned === null || cmdOpts.permissioned === undefined) ? null : JSON.parse(cmdOpts.permissioned);
|
|
89
100
|
const permissionedBefore = vault.permissioned;
|
|
90
101
|
const permissionedAfter = permissioned !== null ? permissioned : 'unchanged';
|
|
@@ -115,7 +126,7 @@ export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues
|
|
|
115
126
|
minDepositAmount: minDepositAmountBN,
|
|
116
127
|
managementFee: managementFeeBN,
|
|
117
128
|
profitShare: profitShareNumber,
|
|
118
|
-
hurdleRate:
|
|
129
|
+
hurdleRate: hurdleRateNumber,
|
|
119
130
|
permissioned,
|
|
120
131
|
};
|
|
121
132
|
|
|
@@ -127,7 +138,7 @@ export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues
|
|
|
127
138
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
128
139
|
} else {
|
|
129
140
|
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" : ""}`);
|
|
141
|
+
console.log(`Updated vault params as vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
131
142
|
done = true;
|
|
132
143
|
}
|
|
133
144
|
break;
|
|
@@ -36,7 +36,7 @@ export const managerUpdateVaultDelegate = async (program: Command, cmdOpts: Opti
|
|
|
36
36
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
37
37
|
} else {
|
|
38
38
|
const tx = await driftVault.updateDelegate(vaultAddress, delegate);
|
|
39
|
-
console.log(`Updated vault delegate to ${delegate.toBase58()}: https://
|
|
39
|
+
console.log(`Updated vault delegate to ${delegate.toBase58()}: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
};
|
|
@@ -59,7 +59,7 @@ export const managerUpdateVaultManager = async (program: Command, cmdOpts: Optio
|
|
|
59
59
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
60
60
|
} else {
|
|
61
61
|
const tx = await driftVault.managerUpdateVaultManager(vaultAddress, manager);
|
|
62
|
-
console.log(`Updated vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet" : ""}`);
|
|
62
|
+
console.log(`Updated vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
63
63
|
done = true;
|
|
64
64
|
}
|
|
65
65
|
break;
|
|
@@ -25,6 +25,6 @@ export const managerWithdraw = async (program: Command, cmdOpts: OptionValues) =
|
|
|
25
25
|
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
26
26
|
} else {
|
|
27
27
|
const tx = await driftVault.managerWithdraw(vaultAddress);
|
|
28
|
-
console.log(`Withrew as vault manager: https://
|
|
28
|
+
console.log(`Withrew as vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
@@ -40,5 +40,5 @@ export const requestWithdraw = async (program: Command, cmdOpts: OptionValues) =
|
|
|
40
40
|
const withdrawAmountBN = new BN(cmdOpts.amount);
|
|
41
41
|
|
|
42
42
|
const tx = await driftVault.requestWithdraw(vaultDepositorAddress, withdrawAmountBN, WithdrawUnit.SHARES);
|
|
43
|
-
console.log(`Requested to withdraw ${cmdOpts.amount} shares from the vault: https://
|
|
43
|
+
console.log(`Requested to withdraw ${cmdOpts.amount} shares from the vault: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
44
44
|
};
|