@drift-labs/vaults-sdk 0.1.290 → 0.1.292
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/commands/applyProfitShare.ts +25 -17
- package/cli/commands/forceWithdraw.ts +1 -1
- package/cli/commands/managerUpdateVault.ts +2 -11
- package/cli/commands/vaultInvariantChecks.ts +124 -18
- package/cli/utils.ts +15 -2
- package/lib/vaultClient.d.ts +10 -1
- package/lib/vaultClient.js +40 -9
- package/package.json +3 -3
- package/src/vaultClient.ts +46 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComputeBudgetProgram, PublicKey,
|
|
1
|
+
import { ComputeBudgetProgram, PublicKey, TransactionInstruction, VersionedTransactionResponse } from "@solana/web3.js";
|
|
2
2
|
import {
|
|
3
3
|
OptionValues,
|
|
4
4
|
Command
|
|
@@ -21,11 +21,11 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
|
|
|
21
21
|
const {
|
|
22
22
|
driftVault,
|
|
23
23
|
driftClient,
|
|
24
|
-
} = await getCommandContext(program, true);
|
|
24
|
+
} = await getCommandContext(program, true, true);
|
|
25
25
|
|
|
26
26
|
const vault = await driftVault.getVault(vaultAddress);
|
|
27
27
|
const vdWithNoWithdrawRequests = await driftVault.getAllVaultDepositorsWithNoWithdrawRequest(vaultAddress);
|
|
28
|
-
const
|
|
28
|
+
const vaultEquitySpot = await driftVault.calculateVaultEquityInDepositAsset({ vault });
|
|
29
29
|
|
|
30
30
|
const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
|
|
31
31
|
if (!spotMarket) {
|
|
@@ -36,7 +36,7 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
|
|
|
36
36
|
const thresholdBN = numberToSafeBN(thresholdNumber, spotMarketPrecision);
|
|
37
37
|
let pendingProfitShareToRealize = ZERO;
|
|
38
38
|
const vdWithPendingProfitShare = vdWithNoWithdrawRequests.filter((vd: ProgramAccount<VaultDepositor>) => {
|
|
39
|
-
const pendingProfitShares = calculateApplyProfitShare(vd.account,
|
|
39
|
+
const pendingProfitShares = calculateApplyProfitShare(vd.account, vaultEquitySpot, vault);
|
|
40
40
|
const doRealize = pendingProfitShares.profitShareAmount.gt(thresholdBN);
|
|
41
41
|
if (doRealize) {
|
|
42
42
|
pendingProfitShareToRealize = pendingProfitShareToRealize.add(pendingProfitShares.profitShareAmount);
|
|
@@ -49,7 +49,7 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
|
|
|
49
49
|
console.log(`${vdWithPendingProfitShare.length}/${vdWithNoWithdrawRequests.length} depositors have pending profit shares above threshold ${cmdOpts.threshold} (${thresholdBN.toString()})`);
|
|
50
50
|
console.log(`Applying profit share for ${vdWithPendingProfitShare.length} depositors.`);
|
|
51
51
|
|
|
52
|
-
const chunkSize =
|
|
52
|
+
const chunkSize = 1;
|
|
53
53
|
const ixChunks: Array<Array<TransactionInstruction>> = [];
|
|
54
54
|
for (let i = 0; i < vdWithPendingProfitShare.length; i += chunkSize) {
|
|
55
55
|
const chunk = vdWithPendingProfitShare.slice(i, i + chunkSize);
|
|
@@ -65,22 +65,30 @@ export const applyProfitShare = async (program: Command, cmdOpts: OptionValues)
|
|
|
65
65
|
const ixs = ixChunks[i];
|
|
66
66
|
console.log(`Sending chunk ${i + 1}/${ixChunks.length}`);
|
|
67
67
|
try {
|
|
68
|
-
ixs.unshift(ComputeBudgetProgram.setComputeUnitLimit({
|
|
69
|
-
units: 1_400_000,
|
|
70
|
-
}));
|
|
71
68
|
ixs.unshift(ComputeBudgetProgram.setComputeUnitPrice({
|
|
72
|
-
microLamports:
|
|
69
|
+
microLamports: 10000,
|
|
70
|
+
}));
|
|
71
|
+
ixs.unshift(ComputeBudgetProgram.setComputeUnitLimit({
|
|
72
|
+
units: 170_000,
|
|
73
73
|
}));
|
|
74
74
|
|
|
75
|
-
const tx =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
const tx = await driftClient.txSender.getVersionedTransaction(ixs, [], undefined, undefined);
|
|
76
|
+
|
|
77
|
+
let attempt = 0;
|
|
78
|
+
let txResp: VersionedTransactionResponse | null = null;
|
|
79
|
+
while (txResp === null) {
|
|
80
|
+
attempt++;
|
|
81
|
+
const { txSig } = await driftClient.txSender.sendVersionedTransaction(
|
|
82
|
+
tx,
|
|
83
|
+
);
|
|
84
|
+
console.log(`[${i}]: https://solscan.io/tx/${txSig} (attempt ${attempt})`);
|
|
85
|
+
|
|
86
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
87
|
+
|
|
88
|
+
txResp = await driftClient.connection.getTransaction(txSig, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 });
|
|
89
|
+
}
|
|
90
|
+
console.log(txResp);
|
|
82
91
|
|
|
83
|
-
console.log(`[${i}]: https://solscan.io/tx/${txSig}`);
|
|
84
92
|
|
|
85
93
|
} catch (e) {
|
|
86
94
|
console.error(e);
|
|
@@ -48,6 +48,6 @@ export const forceWithdraw = async (program: Command, cmdOpts: OptionValues) =>
|
|
|
48
48
|
driftVault
|
|
49
49
|
} = await getCommandContext(program, true);
|
|
50
50
|
|
|
51
|
-
const tx = await driftVault.forceWithdraw(vaultDepositorAddress
|
|
51
|
+
const tx = await driftVault.forceWithdraw(vaultDepositorAddress);
|
|
52
52
|
console.log(`Forced withdraw from vault: ${tx}`);
|
|
53
53
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
2
|
import {
|
|
3
3
|
OptionValues,
|
|
4
4
|
Command
|
|
@@ -119,19 +119,10 @@ export const managerUpdateVault = async (program: Command, cmdOpts: OptionValues
|
|
|
119
119
|
permissioned,
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
-
const preIxs = [
|
|
123
|
-
ComputeBudgetProgram.setComputeUnitLimit({
|
|
124
|
-
units: 600_000,
|
|
125
|
-
}),
|
|
126
|
-
ComputeBudgetProgram.setComputeUnitPrice({
|
|
127
|
-
microLamports: 100_000,
|
|
128
|
-
}),
|
|
129
|
-
];
|
|
130
|
-
|
|
131
122
|
let done = false;
|
|
132
123
|
while (!done) {
|
|
133
124
|
try {
|
|
134
|
-
const tx = await driftVault.managerUpdateVault(vaultAddress, newParams
|
|
125
|
+
const tx = await driftVault.managerUpdateVault(vaultAddress, newParams);
|
|
135
126
|
console.log(`Updated vault params as vault manager: https://solana.fm/tx/${tx}`);
|
|
136
127
|
done = true;
|
|
137
128
|
break;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
Command
|
|
5
5
|
} from "commander";
|
|
6
6
|
import { getCommandContext } from "../utils";
|
|
7
|
-
import { BN, QUOTE_PRECISION, ZERO, convertToNumber } from "@drift-labs/sdk";
|
|
7
|
+
import { BN, PERCENTAGE_PRECISION, PRICE_PRECISION, QUOTE_PRECISION, User, ZERO, convertToNumber, decodeName } from "@drift-labs/sdk";
|
|
8
8
|
import {
|
|
9
9
|
calculateApplyProfitShare,
|
|
10
10
|
} from "../../src/math";
|
|
@@ -21,7 +21,8 @@ export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValu
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const {
|
|
24
|
-
driftVault
|
|
24
|
+
driftVault,
|
|
25
|
+
driftClient,
|
|
25
26
|
} = await getCommandContext(program, true);
|
|
26
27
|
|
|
27
28
|
/*
|
|
@@ -32,34 +33,58 @@ export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValu
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
const vault = await driftVault.getVault(vaultAddress);
|
|
36
|
+
const spotMarket = driftVault.driftClient.getSpotMarketAccount(vault.spotMarketIndex);
|
|
37
|
+
const spotPrecision = new BN(10).pow(new BN(spotMarket!.decimals));
|
|
38
|
+
const spotOracle = driftVault.driftClient.getOracleDataForSpotMarket(vault.spotMarketIndex);
|
|
39
|
+
const spotOraclePriceNum = convertToNumber(spotOracle.price, PRICE_PRECISION);
|
|
40
|
+
const spotSymbol = decodeName(spotMarket!.name);
|
|
41
|
+
|
|
42
|
+
const user = new User({
|
|
43
|
+
// accountSubscription,
|
|
44
|
+
driftClient,
|
|
45
|
+
userAccountPublicKey: vault.user,
|
|
46
|
+
});
|
|
47
|
+
await user.subscribe();
|
|
48
|
+
|
|
35
49
|
const vaultEquity = await driftVault.calculateVaultEquity({
|
|
36
50
|
vault,
|
|
37
51
|
});
|
|
38
|
-
const
|
|
39
|
-
const spotPrecision = new BN(10).pow(new BN(spotMarket!.decimals));
|
|
52
|
+
const vaultEquitySpot = vaultEquity.mul(spotPrecision).div(spotOracle.price);
|
|
40
53
|
|
|
41
54
|
const allVaultDepositors = await driftVault.getAllVaultDepositors(vaultAddress);
|
|
42
55
|
const approxSlot = await driftVault.driftClient.connection.getSlot();
|
|
43
56
|
const now = Date.now();
|
|
44
57
|
|
|
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));
|
|
58
|
+
// let nonZeroDepositors = allVaultDepositors.filter(vd => vd.account.vaultShares.gt(new BN(0)));
|
|
59
|
+
// nonZeroDepositors = nonZeroDepositors.sort((a, b) => b.account.vaultShares.cmp(a.account.vaultShares));
|
|
47
60
|
|
|
48
61
|
let totalUserShares = new BN(0);
|
|
62
|
+
let totalUserProfits = 0;
|
|
63
|
+
let totalUserCumProfits = 0;
|
|
49
64
|
let totalUserProfitSharePaid = new BN(0);
|
|
50
65
|
let totalUserProfitShareSharesPaid = new BN(0);
|
|
51
66
|
let totalPendingProfitShareAmount = new BN(0);
|
|
52
67
|
let totalPendingProfitShareShares = new BN(0);
|
|
68
|
+
let totalUserNetDeposits = new BN(0);
|
|
53
69
|
|
|
54
70
|
console.log(`Vault ${vaultAddress} vd and invariant check at approx slot: ${approxSlot}, date: ${new Date(now).toLocaleString()}`);
|
|
55
|
-
|
|
56
|
-
|
|
71
|
+
let nonZero = 0;
|
|
72
|
+
let usersWithoutPendingProfitShare = 0;
|
|
73
|
+
let usersWithPendingProfitShare = 0;
|
|
74
|
+
const sortedVd = allVaultDepositors.sort((a, b) => b.account.vaultShares.cmp(a.account.vaultShares));
|
|
75
|
+
const checkAuths: Array<string> = [];
|
|
76
|
+
for (const vd of sortedVd) {
|
|
57
77
|
const vdAccount = vd.account as VaultDepositor;
|
|
58
78
|
|
|
79
|
+
if (vdAccount.vaultShares.gt(new BN(0))) {
|
|
80
|
+
nonZero++;
|
|
81
|
+
}
|
|
82
|
+
totalUserNetDeposits = totalUserNetDeposits.add(vdAccount.netDeposits);
|
|
83
|
+
|
|
59
84
|
totalUserShares = totalUserShares.add(vdAccount.vaultShares);
|
|
60
85
|
const vdAuth = vdAccount.authority.toBase58();
|
|
61
86
|
const vdPct = vdAccount.vaultShares.toNumber() / vault.totalShares.toNumber();
|
|
62
|
-
console.log(`- ${vdAuth} has ${vdAccount.vaultShares.toNumber()} shares (${(vdPct * 100.0)
|
|
87
|
+
console.log(`- ${vdAuth} has ${vdAccount.vaultShares.toNumber()} shares (${(vdPct * 100.0)}% of vault)`);
|
|
63
88
|
|
|
64
89
|
if (!vdAccount.lastWithdrawRequest.shares.eq(new BN(0))) {
|
|
65
90
|
const withdrawRequested = vdAccount.lastWithdrawRequest.ts.toNumber();
|
|
@@ -77,13 +102,47 @@ export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValu
|
|
|
77
102
|
totalUserProfitSharePaid = totalUserProfitSharePaid.add(vdAccount.profitShareFeePaid);
|
|
78
103
|
totalUserProfitShareSharesPaid = totalUserProfitShareSharesPaid.add(vdAccount.cumulativeProfitShareAmount);
|
|
79
104
|
|
|
80
|
-
const pendingProfitShares = calculateApplyProfitShare(vdAccount,
|
|
105
|
+
const pendingProfitShares = calculateApplyProfitShare(vdAccount, vaultEquitySpot, vault);
|
|
106
|
+
const pendingProfitShareAmtNum = convertToNumber(pendingProfitShares.profitShareAmount, spotPrecision);
|
|
81
107
|
if (pendingProfitShares.profitShareAmount.gt(ZERO)) {
|
|
82
108
|
totalPendingProfitShareAmount = totalPendingProfitShareAmount.add(pendingProfitShares.profitShareAmount);
|
|
83
109
|
totalPendingProfitShareShares = totalPendingProfitShareShares.add(pendingProfitShares.profitShareShares);
|
|
84
|
-
console.log(` - pending profit share amount:
|
|
110
|
+
console.log(` - pending profit share amount: ${convertToNumber(pendingProfitShares.profitShareAmount, spotPrecision)}`);
|
|
111
|
+
usersWithPendingProfitShare++;
|
|
112
|
+
} else {
|
|
113
|
+
console.log(` - no pending profit share`);
|
|
114
|
+
usersWithoutPendingProfitShare++;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const userShareValue = vaultEquitySpot.mul(vdAccount.vaultShares).div(vault.totalShares);
|
|
118
|
+
const userShareValueNum = convertToNumber(userShareValue, spotPrecision);
|
|
119
|
+
const netDepositsNum = convertToNumber(vdAccount.netDeposits, spotPrecision);
|
|
120
|
+
const vdProfits = userShareValueNum - netDepositsNum;
|
|
121
|
+
const profitSharePaid = convertToNumber(vdAccount.profitShareFeePaid, spotPrecision);
|
|
122
|
+
const cumProfitShareNum = convertToNumber(vdAccount.cumulativeProfitShareAmount, spotPrecision);
|
|
123
|
+
totalUserProfits += vdProfits;
|
|
124
|
+
totalUserCumProfits += cumProfitShareNum;
|
|
125
|
+
console.log(` - net deposits: ${netDepositsNum}`);
|
|
126
|
+
console.log(` - vd profit: ${vdProfits}`);
|
|
127
|
+
console.log(` - cumProfitshareAmt: ${cumProfitShareNum}`);
|
|
128
|
+
console.log(` - profitShareFeePaid: ${convertToNumber(vdAccount.profitShareFeePaid, spotPrecision)}`);
|
|
129
|
+
const inclProfitShare = (profitSharePaid + pendingProfitShareAmtNum) / (cumProfitShareNum + pendingProfitShareAmtNum) * 100.0;
|
|
130
|
+
console.log(` - pftSharePaidPct (excl pend): ${(profitSharePaid / cumProfitShareNum * 100.0).toFixed(2)}%`);
|
|
131
|
+
console.log(` - pftSharePaidPct (incl pend): ${(inclProfitShare).toFixed(2)}% `);
|
|
132
|
+
if (inclProfitShare < 29.9 && inclProfitShare > 0) {
|
|
133
|
+
console.log(` ^^^ weird: ${inclProfitShare}`);
|
|
134
|
+
checkAuths.push(vdAuth);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (vdAccount.vaultSharesBase !== 0) {
|
|
138
|
+
console.log(` - Nonzero vault shares base: ${vdAccount.vaultSharesBase} `);
|
|
85
139
|
}
|
|
86
140
|
}
|
|
141
|
+
console.log(`Check these auths:\n${checkAuths.join("\n")}`);
|
|
142
|
+
console.log(`Depositors with 0 shares: ${allVaultDepositors.length - nonZero} /${allVaultDepositors.length}`);
|
|
143
|
+
console.log(`Depositors with pending profit share: ${usersWithPendingProfitShare}`);
|
|
144
|
+
console.log(`Depositors without pending profit share: ${usersWithoutPendingProfitShare}`);
|
|
145
|
+
|
|
87
146
|
console.log(`==== Vault Depositor Shares == vault.user_shares ====`);
|
|
88
147
|
console.log(`total vd shares: ${totalUserShares.toString()}`);
|
|
89
148
|
console.log(`total vault usershares: ${vault.userShares.toString()}`);
|
|
@@ -97,8 +156,27 @@ export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValu
|
|
|
97
156
|
|
|
98
157
|
console.log(``);
|
|
99
158
|
console.log(`==== Pending profit shares to realize ====`);
|
|
100
|
-
|
|
101
|
-
|
|
159
|
+
const totalPendingProfitShareAmountNum = convertToNumber(totalPendingProfitShareAmount, spotPrecision);
|
|
160
|
+
const totalUserProfitSharePaidNum = convertToNumber(totalUserProfitSharePaid, spotPrecision);
|
|
161
|
+
console.log(`amount: ${totalPendingProfitShareAmountNum}`);
|
|
162
|
+
console.log(`shares: ${totalPendingProfitShareShares.toNumber()}`);
|
|
163
|
+
// console.log(`csv: ${cmdOpts.csv}`);
|
|
164
|
+
|
|
165
|
+
console.log(``);
|
|
166
|
+
console.log(`==== Agg user profit share paid ====`);
|
|
167
|
+
console.log(`vd total profit (incl unrealized profit share): ${totalUserProfits}`);
|
|
168
|
+
console.log(`vd total cum profits (before pending profit share): ${totalUserCumProfits}`);
|
|
169
|
+
console.log(`vd total profit share paid): ${totalUserProfitSharePaidNum}`);
|
|
170
|
+
console.log(`vd total pending profit share: ${totalPendingProfitShareAmountNum}`);
|
|
171
|
+
console.log(`vd total net deposits: ${convertToNumber(totalUserNetDeposits, spotPrecision)}`);
|
|
172
|
+
const driftUserDeposits = user.getUserAccount().totalDeposits;
|
|
173
|
+
const driftUserWithdraws = user.getUserAccount().totalWithdraws;
|
|
174
|
+
const driftUserSocialLoss = user.getUserAccount().totalSocialLoss;
|
|
175
|
+
console.log(`vd drift user net deposits: ${convertToNumber(driftUserDeposits.sub(driftUserWithdraws).sub(driftUserSocialLoss), spotPrecision)}`);
|
|
176
|
+
console.log(` vd drift user deps: ${convertToNumber(driftUserDeposits, spotPrecision)}`);
|
|
177
|
+
console.log(` vd drift user with: ${convertToNumber(driftUserWithdraws, spotPrecision)}`);
|
|
178
|
+
console.log(` vd drift user scls: ${convertToNumber(driftUserSocialLoss, spotPrecision)}`);
|
|
179
|
+
|
|
102
180
|
|
|
103
181
|
console.log(``);
|
|
104
182
|
console.log(`==== Manager share ====`);
|
|
@@ -107,8 +185,36 @@ export const vaultInvariantChecks = async (program: Command, cmdOpts: OptionValu
|
|
|
107
185
|
const managerSharePct = managerShares.toNumber() / vault.totalShares.toNumber();
|
|
108
186
|
const managerShareWithPendingPct = managerShares.add(totalPendingProfitShareShares).toNumber() / vault.totalShares.toNumber();
|
|
109
187
|
console.log(` Manager shares: ${managerShares.toString()} (${(managerSharePct * 100.0).toFixed(4)}%)`);
|
|
110
|
-
const vaultEquityNum = convertToNumber(vaultEquity,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
console.log(`
|
|
114
|
-
};
|
|
188
|
+
const vaultEquityNum = convertToNumber(vaultEquity, spotPrecision);
|
|
189
|
+
const vaultEquitySpotNum = convertToNumber(vaultEquitySpot, spotPrecision);
|
|
190
|
+
const vaultPnlNum = convertToNumber(user.getTotalAllTimePnl(), QUOTE_PRECISION);
|
|
191
|
+
console.log(`vaultEquity (USDC): $${vaultEquityNum}`);
|
|
192
|
+
console.log(`vaultEquity (deposit asset): ${vaultEquitySpotNum}`);
|
|
193
|
+
const managerValueWoPending = managerSharePct * vaultEquitySpotNum;
|
|
194
|
+
const managerValueWithPending = managerShareWithPendingPct * vaultEquitySpotNum;
|
|
195
|
+
console.log(`manager share (w/o pending) (deposit asset): ${managerValueWoPending} (share: ${managerValueWoPending / vaultPnlNum * 100.0}%)`);
|
|
196
|
+
console.log(`manager share (with pending) (deposit asset): ${managerValueWithPending} (share: ${managerValueWithPending / vaultPnlNum * 100.0}%)`);
|
|
197
|
+
|
|
198
|
+
console.log(``);
|
|
199
|
+
const profitSharePct = vault.profitShare / PERCENTAGE_PRECISION.toNumber();
|
|
200
|
+
const vdPnlBeforeProfitShare = convertToNumber(totalUserProfitSharePaid, spotPrecision) / profitSharePct;
|
|
201
|
+
console.log(`back out vault pnl: (userPnl + managerShareValue): ${totalUserProfits} + ${managerSharePct * vaultEquitySpotNum} = ${totalUserProfits + managerSharePct * vaultEquitySpotNum}`);
|
|
202
|
+
console.log(`vaultDepositors pnl (before profit share): ${vdPnlBeforeProfitShare}`);
|
|
203
|
+
|
|
204
|
+
console.log(`vault PnL (spot): ${vaultEquitySpotNum - convertToNumber(vault.netDeposits, spotPrecision)}`);
|
|
205
|
+
console.log(`vault PnL (USD) ${vaultPnlNum}`);
|
|
206
|
+
console.log(`vault PnL (spot) ${vaultPnlNum / spotOraclePriceNum}`);
|
|
207
|
+
|
|
208
|
+
console.log(``);
|
|
209
|
+
console.log(`==== ${decodeName(vault.name)} Profit Summary ====`);
|
|
210
|
+
console.log(`Depositors' total PnL: ${totalUserProfits} ${spotSymbol}`);
|
|
211
|
+
console.log(`Depositors' profit share paid to date: ${totalUserProfitSharePaidNum} ${spotSymbol}`);
|
|
212
|
+
console.log(`Unrealized profit share: ${totalPendingProfitShareAmountNum} ${spotSymbol}`);
|
|
213
|
+
console.log(`Vault manager net deposits: ${convertToNumber(vault.managerNetDeposits, spotPrecision)} ${spotSymbol}`);
|
|
214
|
+
console.log(`Vault manager profit share received: ${convertToNumber(vault.managerTotalProfitShare, spotPrecision)} ${spotSymbol}`);
|
|
215
|
+
console.log(`Vault manager share value: ${managerValueWithPending} ${spotSymbol} (share of vault: ${managerValueWithPending / vaultPnlNum * 100.0}%)`);
|
|
216
|
+
if (spotSymbol !== 'USDC') {
|
|
217
|
+
console.log(`Vault manager share value: ${managerValueWithPending * spotOraclePriceNum} USDC`);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
package/cli/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BASE_PRECISION, BN, DriftClient, OraclePriceData, PRICE_PRECISION, QUOTE_PRECISION, SpotMarketAccount, TEN, User, Wallet, convertToNumber, getSignedTokenAmount, getTokenAmount, loadKeypair } from "@drift-labs/sdk";
|
|
1
|
+
import { BASE_PRECISION, BN, DriftClient, 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
4
|
import { Connection, Keypair } from "@solana/web3.js";
|
|
@@ -67,6 +67,7 @@ export async function printVault(slot: number, driftClient: DriftClient, vault:
|
|
|
67
67
|
userAccountPublicKey: vault.user,
|
|
68
68
|
});
|
|
69
69
|
await user.subscribe();
|
|
70
|
+
|
|
70
71
|
for (const spotPos of user.getActiveSpotPositions()) {
|
|
71
72
|
const sm = driftClient.getSpotMarketAccount(spotPos.marketIndex)!;
|
|
72
73
|
const prec = TEN.pow(new BN(sm.decimals));
|
|
@@ -74,6 +75,7 @@ export async function printVault(slot: number, driftClient: DriftClient, vault:
|
|
|
74
75
|
const bal = getSignedTokenAmount(getTokenAmount(spotPos.scaledBalance, sm, spotPos.balanceType), spotPos.balanceType);
|
|
75
76
|
console.log(`Spot Position: ${spotPos.marketIndex}, ${convertToNumber(bal, prec)} ${sym}`);
|
|
76
77
|
}
|
|
78
|
+
|
|
77
79
|
for (const perpPos of user.getActivePerpPositions()) {
|
|
78
80
|
console.log(`Perp Position: ${perpPos.marketIndex}, base: ${convertToNumber(perpPos.baseAssetAmount, BASE_PRECISION)}, quote: ${convertToNumber(perpPos.quoteAssetAmount, QUOTE_PRECISION)}`);
|
|
79
81
|
const upnl = user.getUnrealizedPNL(true, perpPos.marketIndex);
|
|
@@ -82,7 +84,9 @@ export async function printVault(slot: number, driftClient: DriftClient, vault:
|
|
|
82
84
|
|
|
83
85
|
console.log(`vaultEquity (${spotSymbol}): ${vaultEquitySpot}`);
|
|
84
86
|
console.log(`manager share (${spotSymbol}): ${managerSharePct * vaultEquitySpot}`);
|
|
85
|
-
console.log(`vault PnL
|
|
87
|
+
console.log(`vault PnL (${spotSymbol}): ${vaultEquitySpot - netDepositsNum}`);
|
|
88
|
+
console.log(`vault PnL (USD) ${convertToNumber(user.getTotalAllTimePnl(), QUOTE_PRECISION)}`);
|
|
89
|
+
console.log(`vault PnL (spot) ${convertToNumber(user.getTotalAllTimePnl(), QUOTE_PRECISION) / oraclePriceNum}`);
|
|
86
90
|
|
|
87
91
|
return {
|
|
88
92
|
managerShares,
|
|
@@ -134,6 +138,7 @@ export async function getCommandContext(program: Command, needToSign: boolean):
|
|
|
134
138
|
const connection = new Connection(opts.url, {
|
|
135
139
|
commitment: opts.commitment,
|
|
136
140
|
});
|
|
141
|
+
|
|
137
142
|
const driftClient = new DriftClient({
|
|
138
143
|
connection,
|
|
139
144
|
wallet,
|
|
@@ -143,6 +148,14 @@ export async function getCommandContext(program: Command, needToSign: boolean):
|
|
|
143
148
|
skipPreflight: false,
|
|
144
149
|
preflightCommitment: opts.commitment,
|
|
145
150
|
},
|
|
151
|
+
txSender: new WhileValidTxSender({
|
|
152
|
+
connection,
|
|
153
|
+
wallet,
|
|
154
|
+
opts: {
|
|
155
|
+
maxRetries: 0,
|
|
156
|
+
},
|
|
157
|
+
retrySleep: 1000,
|
|
158
|
+
}),
|
|
146
159
|
});
|
|
147
160
|
await driftClient.subscribe();
|
|
148
161
|
|
package/lib/vaultClient.d.ts
CHANGED
|
@@ -44,12 +44,21 @@ export declare class VaultClient {
|
|
|
44
44
|
/**
|
|
45
45
|
*
|
|
46
46
|
* @param vault pubkey
|
|
47
|
-
* @returns vault equity, in
|
|
47
|
+
* @returns vault equity, in USDC
|
|
48
48
|
*/
|
|
49
49
|
calculateVaultEquity(params: {
|
|
50
50
|
address?: PublicKey;
|
|
51
51
|
vault?: Vault;
|
|
52
52
|
}): Promise<BN>;
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param vault pubkey
|
|
56
|
+
* @returns vault equity, in spot deposit asset
|
|
57
|
+
*/
|
|
58
|
+
calculateVaultEquityInDepositAsset(params: {
|
|
59
|
+
address?: PublicKey;
|
|
60
|
+
vault?: Vault;
|
|
61
|
+
}): Promise<BN>;
|
|
53
62
|
initializeVault(params: {
|
|
54
63
|
name: number[];
|
|
55
64
|
spotMarketIndex: number;
|
package/lib/vaultClient.js
CHANGED
|
@@ -103,7 +103,7 @@ class VaultClient {
|
|
|
103
103
|
/**
|
|
104
104
|
*
|
|
105
105
|
* @param vault pubkey
|
|
106
|
-
* @returns vault equity, in
|
|
106
|
+
* @returns vault equity, in USDC
|
|
107
107
|
*/
|
|
108
108
|
async calculateVaultEquity(params) {
|
|
109
109
|
let vaultAccount;
|
|
@@ -122,6 +122,31 @@ class VaultClient {
|
|
|
122
122
|
const unrealizedPnl = user.getUnrealizedPNL(true, undefined, undefined);
|
|
123
123
|
return netSpotValue.add(unrealizedPnl);
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
*
|
|
127
|
+
* @param vault pubkey
|
|
128
|
+
* @returns vault equity, in spot deposit asset
|
|
129
|
+
*/
|
|
130
|
+
async calculateVaultEquityInDepositAsset(params) {
|
|
131
|
+
let vaultAccount;
|
|
132
|
+
if (params.address !== undefined) {
|
|
133
|
+
// @ts-ignore
|
|
134
|
+
vaultAccount = await this.program.account.vault.fetch(params.address);
|
|
135
|
+
}
|
|
136
|
+
else if (params.vault !== undefined) {
|
|
137
|
+
vaultAccount = params.vault;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
throw new Error('Must supply address or vault');
|
|
141
|
+
}
|
|
142
|
+
const vaultEquity = await this.calculateVaultEquity({
|
|
143
|
+
vault: vaultAccount,
|
|
144
|
+
});
|
|
145
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(vaultAccount.spotMarketIndex);
|
|
146
|
+
const spotOracle = this.driftClient.getOracleDataForSpotMarket(vaultAccount.spotMarketIndex);
|
|
147
|
+
const spotPrecision = sdk_1.TEN.pow(new sdk_1.BN(spotMarket.decimals));
|
|
148
|
+
return vaultEquity.mul(spotPrecision).div(spotOracle.price);
|
|
149
|
+
}
|
|
125
150
|
async initializeVault(params) {
|
|
126
151
|
const vault = (0, addresses_1.getVaultAddressSync)(this.program.programId, params.name);
|
|
127
152
|
const tokenAccount = (0, addresses_1.getTokenVaultAddressSync)(this.program.programId, vault);
|
|
@@ -320,13 +345,16 @@ class VaultClient {
|
|
|
320
345
|
});
|
|
321
346
|
}
|
|
322
347
|
async managerUpdateVault(vault, params) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
})
|
|
329
|
-
|
|
348
|
+
const ix = this.program.instruction.updateVault(params, {
|
|
349
|
+
accounts: {
|
|
350
|
+
vault,
|
|
351
|
+
manager: this.driftClient.wallet.publicKey,
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
return this.createAndSendTxn([ix], {
|
|
355
|
+
cuLimit: 600000,
|
|
356
|
+
cuPriceMicroLamports: 10000,
|
|
357
|
+
});
|
|
330
358
|
}
|
|
331
359
|
async getApplyProfitShareIx(vault, vaultDepositor) {
|
|
332
360
|
const vaultAccount = await this.program.account.vault.fetch(vault);
|
|
@@ -591,7 +619,10 @@ class VaultClient {
|
|
|
591
619
|
.forceWithdraw()
|
|
592
620
|
.preInstructions([
|
|
593
621
|
web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
|
|
594
|
-
units:
|
|
622
|
+
units: 500000,
|
|
623
|
+
}),
|
|
624
|
+
web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
|
|
625
|
+
microLamports: 50000,
|
|
595
626
|
}),
|
|
596
627
|
])
|
|
597
628
|
.accounts(accounts)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drift-labs/vaults-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.292",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"directories": {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@coral-xyz/anchor": "^0.26.0",
|
|
11
|
-
"@drift-labs/competitions-sdk": "0.2.
|
|
12
|
-
"@drift-labs/sdk": "2.82.0-beta.
|
|
11
|
+
"@drift-labs/competitions-sdk": "0.2.303",
|
|
12
|
+
"@drift-labs/sdk": "2.82.0-beta.13",
|
|
13
13
|
"@solana/web3.js": "1.73.2",
|
|
14
14
|
"commander": "^11.0.0",
|
|
15
15
|
"dotenv": "^16.3.1",
|
package/src/vaultClient.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getUserAccountPublicKey,
|
|
7
7
|
getUserAccountPublicKeySync,
|
|
8
8
|
getUserStatsAccountPublicKey,
|
|
9
|
+
TEN,
|
|
9
10
|
UserMap,
|
|
10
11
|
} from '@drift-labs/sdk';
|
|
11
12
|
import { BorshAccountsCoder, Program, ProgramAccount } from '@coral-xyz/anchor';
|
|
@@ -184,7 +185,7 @@ export class VaultClient {
|
|
|
184
185
|
/**
|
|
185
186
|
*
|
|
186
187
|
* @param vault pubkey
|
|
187
|
-
* @returns vault equity, in
|
|
188
|
+
* @returns vault equity, in USDC
|
|
188
189
|
*/
|
|
189
190
|
public async calculateVaultEquity(params: {
|
|
190
191
|
address?: PublicKey;
|
|
@@ -208,6 +209,38 @@ export class VaultClient {
|
|
|
208
209
|
return netSpotValue.add(unrealizedPnl);
|
|
209
210
|
}
|
|
210
211
|
|
|
212
|
+
/**
|
|
213
|
+
*
|
|
214
|
+
* @param vault pubkey
|
|
215
|
+
* @returns vault equity, in spot deposit asset
|
|
216
|
+
*/
|
|
217
|
+
public async calculateVaultEquityInDepositAsset(params: {
|
|
218
|
+
address?: PublicKey;
|
|
219
|
+
vault?: Vault;
|
|
220
|
+
}): Promise<BN> {
|
|
221
|
+
let vaultAccount: Vault;
|
|
222
|
+
if (params.address !== undefined) {
|
|
223
|
+
// @ts-ignore
|
|
224
|
+
vaultAccount = await this.program.account.vault.fetch(params.address);
|
|
225
|
+
} else if (params.vault !== undefined) {
|
|
226
|
+
vaultAccount = params.vault;
|
|
227
|
+
} else {
|
|
228
|
+
throw new Error('Must supply address or vault');
|
|
229
|
+
}
|
|
230
|
+
const vaultEquity = await this.calculateVaultEquity({
|
|
231
|
+
vault: vaultAccount,
|
|
232
|
+
});
|
|
233
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(
|
|
234
|
+
vaultAccount.spotMarketIndex
|
|
235
|
+
);
|
|
236
|
+
const spotOracle = this.driftClient.getOracleDataForSpotMarket(
|
|
237
|
+
vaultAccount.spotMarketIndex
|
|
238
|
+
);
|
|
239
|
+
const spotPrecision = TEN.pow(new BN(spotMarket!.decimals));
|
|
240
|
+
|
|
241
|
+
return vaultEquity.mul(spotPrecision).div(spotOracle.price);
|
|
242
|
+
}
|
|
243
|
+
|
|
211
244
|
public async initializeVault(params: {
|
|
212
245
|
name: number[];
|
|
213
246
|
spotMarketIndex: number;
|
|
@@ -526,13 +559,16 @@ export class VaultClient {
|
|
|
526
559
|
permissioned: boolean | null;
|
|
527
560
|
}
|
|
528
561
|
): Promise<TransactionSignature> {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
.accounts({
|
|
562
|
+
const ix = this.program.instruction.updateVault(params, {
|
|
563
|
+
accounts: {
|
|
532
564
|
vault,
|
|
533
565
|
manager: this.driftClient.wallet.publicKey,
|
|
534
|
-
}
|
|
535
|
-
|
|
566
|
+
},
|
|
567
|
+
});
|
|
568
|
+
return this.createAndSendTxn([ix], {
|
|
569
|
+
cuLimit: 600_000,
|
|
570
|
+
cuPriceMicroLamports: 10_000,
|
|
571
|
+
});
|
|
536
572
|
}
|
|
537
573
|
|
|
538
574
|
public async getApplyProfitShareIx(
|
|
@@ -941,7 +977,10 @@ export class VaultClient {
|
|
|
941
977
|
.forceWithdraw()
|
|
942
978
|
.preInstructions([
|
|
943
979
|
ComputeBudgetProgram.setComputeUnitLimit({
|
|
944
|
-
units:
|
|
980
|
+
units: 500_000,
|
|
981
|
+
}),
|
|
982
|
+
ComputeBudgetProgram.setComputeUnitPrice({
|
|
983
|
+
microLamports: 50_000,
|
|
945
984
|
}),
|
|
946
985
|
])
|
|
947
986
|
.accounts(accounts)
|