@velocity-exchange/vaults-sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -0
- package/README.md +152 -0
- package/cli/cli.ts +751 -0
- package/cli/commands/adminDeleteFeeUpdate.ts +73 -0
- package/cli/commands/adminInitFeeUpdate.ts +73 -0
- package/cli/commands/adminUpdateVaultClass.ts +49 -0
- package/cli/commands/applyProfitShare.ts +139 -0
- package/cli/commands/decodeLogs.ts +98 -0
- package/cli/commands/deposit.ts +98 -0
- package/cli/commands/deriveVaultAddress.ts +14 -0
- package/cli/commands/forceWithdraw.ts +56 -0
- package/cli/commands/forceWithdrawAll.ts +142 -0
- package/cli/commands/index.ts +28 -0
- package/cli/commands/initVault.ts +227 -0
- package/cli/commands/initVaultDepositor.ts +42 -0
- package/cli/commands/listDepositorsForVault.ts +32 -0
- package/cli/commands/managerApplyProfitShare.ts +32 -0
- package/cli/commands/managerBorrow.ts +77 -0
- package/cli/commands/managerCancelWithdraw.ts +30 -0
- package/cli/commands/managerDeposit.ts +45 -0
- package/cli/commands/managerRepay.ts +94 -0
- package/cli/commands/managerRequestWithdraw.ts +86 -0
- package/cli/commands/managerUpdateBorrow.ts +56 -0
- package/cli/commands/managerUpdateFees.ts +156 -0
- package/cli/commands/managerUpdateMarginTradingEnabled.ts +32 -0
- package/cli/commands/managerUpdatePoolId.ts +36 -0
- package/cli/commands/managerUpdateVault.ts +210 -0
- package/cli/commands/managerUpdateVaultDelegate.ts +43 -0
- package/cli/commands/managerUpdateVaultManager.ts +77 -0
- package/cli/commands/managerWithdraw.ts +30 -0
- package/cli/commands/requestWithdraw.ts +58 -0
- package/cli/commands/vaultDeposit.ts +42 -0
- package/cli/commands/vaultInvariantChecks.ts +407 -0
- package/cli/commands/vaultWithdraw.ts +42 -0
- package/cli/commands/viewVault.ts +50 -0
- package/cli/commands/viewVaultDepositor.ts +36 -0
- package/cli/commands/withdraw.ts +40 -0
- package/cli/ledgerWallet.test.ts +49 -0
- package/cli/ledgerWallet.ts +111 -0
- package/cli/utils.ts +389 -0
- package/package.json +48 -0
- package/src/accountSubscribers/index.ts +2 -0
- package/src/accountSubscribers/pollingVaultDepositorSubscriber.ts +69 -0
- package/src/accountSubscribers/pollingVaultSubscriber.ts +63 -0
- package/src/accountSubscribers/pollingVaultsProgramAccountSubscriber.ts +114 -0
- package/src/accounts/index.ts +2 -0
- package/src/accounts/vaultAccount.ts +255 -0
- package/src/accounts/vaultDepositorAccount.ts +77 -0
- package/src/accounts/vaultsProgramAccount.ts +38 -0
- package/src/addresses.ts +114 -0
- package/src/constants/index.ts +15 -0
- package/src/idl/drift_vaults.json +5698 -0
- package/src/index.ts +11 -0
- package/src/math/index.ts +2 -0
- package/src/math/vault.ts +71 -0
- package/src/math/vaultDepositor.ts +90 -0
- package/src/name.ts +18 -0
- package/src/parsers/index.ts +1 -0
- package/src/parsers/logParser.ts +28 -0
- package/src/types/drift_vaults.ts +6211 -0
- package/src/types/types.ts +336 -0
- package/src/utils.ts +74 -0
- package/src/vaultClient.ts +3666 -0
- package/tsconfig.json +24 -0
- package/velocity-exchange-vaults-sdk-0.0.1.tgz +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
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 managerUpdateVaultDelegate = 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
|
+
let delegate = cmdOpts.delegate;
|
|
24
|
+
if (!delegate) {
|
|
25
|
+
throw new Error(`Must provide delegate address`);
|
|
26
|
+
} else {
|
|
27
|
+
try {
|
|
28
|
+
delegate = new PublicKey(delegate);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
throw new Error(`Invalid delegate address: ${err}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
35
|
+
const vaultAccount = await driftVault.program.account.vault.fetch(vaultAddress);
|
|
36
|
+
const tx = await driftVault.getUpdateDelegateIx(vaultAddress, delegate, vaultAccount.user, vaultAccount.manager);
|
|
37
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
38
|
+
} else {
|
|
39
|
+
const tx = await driftVault.updateDelegate(vaultAddress, delegate);
|
|
40
|
+
console.log(`Updated vault delegate to ${delegate.toBase58()}: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
};
|
|
@@ -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-solana" : ""}`);
|
|
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
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
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 managerWithdraw = 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
|
+
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://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { BN } from '@velocity-exchange/sdk';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { OptionValues, Command } from 'commander';
|
|
4
|
+
import { getCommandContext } from '../utils';
|
|
5
|
+
import { WithdrawUnit } from '../../src/types/types';
|
|
6
|
+
import { getVaultDepositorAddressSync, VAULT_PROGRAM_ID } from '../../src';
|
|
7
|
+
|
|
8
|
+
export const requestWithdraw = async (
|
|
9
|
+
program: Command,
|
|
10
|
+
cmdOpts: OptionValues
|
|
11
|
+
) => {
|
|
12
|
+
// verify correct args provided
|
|
13
|
+
if (!cmdOpts.vaultDepositorAddress) {
|
|
14
|
+
if (!cmdOpts.vaultAddress || !cmdOpts.authority) {
|
|
15
|
+
console.error(
|
|
16
|
+
'Must provide --vault-address and --authority if not providing --vault-depositor-address'
|
|
17
|
+
);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { driftVault, driftClient } = await getCommandContext(program, true);
|
|
23
|
+
|
|
24
|
+
let vaultDepositorAddress: PublicKey;
|
|
25
|
+
if (cmdOpts.vaultDepositorAddress) {
|
|
26
|
+
try {
|
|
27
|
+
vaultDepositorAddress = new PublicKey(
|
|
28
|
+
cmdOpts.vaultDepositorAddress as string
|
|
29
|
+
);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error('Invalid vault depositor address');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
const vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
36
|
+
const authority = new PublicKey(cmdOpts.authority as string);
|
|
37
|
+
vaultDepositorAddress = getVaultDepositorAddressSync(
|
|
38
|
+
VAULT_PROGRAM_ID,
|
|
39
|
+
vaultAddress,
|
|
40
|
+
authority
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const withdrawAmountBN = new BN(cmdOpts.amount);
|
|
45
|
+
|
|
46
|
+
const tx = await driftVault.requestWithdraw(
|
|
47
|
+
vaultDepositorAddress,
|
|
48
|
+
withdrawAmountBN,
|
|
49
|
+
WithdrawUnit.SHARES
|
|
50
|
+
);
|
|
51
|
+
console.log(
|
|
52
|
+
`Requested to withdraw ${
|
|
53
|
+
cmdOpts.amount
|
|
54
|
+
} shares from the vault: https://solana.fm/tx/${tx}${
|
|
55
|
+
driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
|
|
56
|
+
}`
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import {
|
|
3
|
+
getVaultDepositorAddressSync
|
|
4
|
+
} from "../../src/addresses";
|
|
5
|
+
import {
|
|
6
|
+
OptionValues,
|
|
7
|
+
Command
|
|
8
|
+
} from "commander";
|
|
9
|
+
import { getCommandContext } from "../utils";
|
|
10
|
+
import { VAULT_PROGRAM_ID } from "../../src/types/types";
|
|
11
|
+
|
|
12
|
+
export const vaultDeposit = async (program: Command, cmdOpts: OptionValues) => {
|
|
13
|
+
|
|
14
|
+
let vaultAddress: PublicKey;
|
|
15
|
+
try {
|
|
16
|
+
vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.error("Invalid vault address");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let depositAuthority: PublicKey;
|
|
23
|
+
try {
|
|
24
|
+
depositAuthority = new PublicKey(cmdOpts.depositAuthority as string);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.error("Invalid deposit authority");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
driftVault
|
|
32
|
+
} = await getCommandContext(program, true);
|
|
33
|
+
|
|
34
|
+
const vaultDepositorAddress = getVaultDepositorAddressSync(
|
|
35
|
+
VAULT_PROGRAM_ID,
|
|
36
|
+
vaultAddress,
|
|
37
|
+
depositAuthority,
|
|
38
|
+
);
|
|
39
|
+
const tx = await driftVault.initializeVaultDepositor(vaultAddress, depositAuthority);
|
|
40
|
+
console.log(`VaultDepositor initialized for ${depositAuthority}: ${tx}`);
|
|
41
|
+
console.log(`VaultDepositor address: ${vaultDepositorAddress}`);
|
|
42
|
+
};
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { OptionValues, Command } from 'commander';
|
|
3
|
+
import { getCommandContext } from '../utils';
|
|
4
|
+
import {
|
|
5
|
+
BN,
|
|
6
|
+
PERCENTAGE_PRECISION,
|
|
7
|
+
PRICE_PRECISION,
|
|
8
|
+
QUOTE_PRECISION,
|
|
9
|
+
User,
|
|
10
|
+
ZERO,
|
|
11
|
+
convertToNumber,
|
|
12
|
+
decodeName,
|
|
13
|
+
} from '@velocity-exchange/sdk';
|
|
14
|
+
import { calculateApplyProfitShare } from '../../src/math';
|
|
15
|
+
import { VaultDepositor } from '../../src';
|
|
16
|
+
|
|
17
|
+
export const vaultInvariantChecks = async (
|
|
18
|
+
program: Command,
|
|
19
|
+
cmdOpts: OptionValues
|
|
20
|
+
) => {
|
|
21
|
+
let vaultAddress: PublicKey;
|
|
22
|
+
try {
|
|
23
|
+
vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error('Invalid vault address');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { driftVault, driftClient } = await getCommandContext(program, true);
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
Invariants:
|
|
33
|
+
* sum(vault_depositors.shares) == vault.user_shares
|
|
34
|
+
* sum(vault_depositors.profit_share_paid) == vault.manager_total_profit_share
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const vault = await driftVault.getVault(vaultAddress);
|
|
38
|
+
const spotMarket = driftVault.driftClient.getSpotMarketAccount(
|
|
39
|
+
vault.spotMarketIndex
|
|
40
|
+
);
|
|
41
|
+
const spotPrecision = new BN(10).pow(new BN(spotMarket!.decimals));
|
|
42
|
+
const spotOracle = driftVault.driftClient.getOracleDataForSpotMarket(
|
|
43
|
+
vault.spotMarketIndex
|
|
44
|
+
);
|
|
45
|
+
const spotOraclePriceNum = convertToNumber(spotOracle.price, PRICE_PRECISION);
|
|
46
|
+
const spotSymbol = decodeName(spotMarket!.name);
|
|
47
|
+
|
|
48
|
+
const user = new User({
|
|
49
|
+
// accountSubscription,
|
|
50
|
+
driftClient,
|
|
51
|
+
userAccountPublicKey: vault.user,
|
|
52
|
+
});
|
|
53
|
+
await user.subscribe();
|
|
54
|
+
|
|
55
|
+
const vaultEquity = await driftVault.calculateVaultEquity({
|
|
56
|
+
vault,
|
|
57
|
+
});
|
|
58
|
+
const vaultEquitySpot = vaultEquity.mul(spotPrecision).div(spotOracle.price);
|
|
59
|
+
|
|
60
|
+
const allVaultDepositors = await driftVault.getAllVaultDepositors(
|
|
61
|
+
vaultAddress
|
|
62
|
+
);
|
|
63
|
+
const approxSlot = await driftVault.driftClient.connection.getSlot();
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
|
|
66
|
+
// let nonZeroDepositors = allVaultDepositors.filter(vd => vd.account.vaultShares.gt(new BN(0)));
|
|
67
|
+
// nonZeroDepositors = nonZeroDepositors.sort((a, b) => b.account.vaultShares.cmp(a.account.vaultShares));
|
|
68
|
+
|
|
69
|
+
let totalUserShares = new BN(0);
|
|
70
|
+
let totalUserProfits = 0;
|
|
71
|
+
let totalUserCumProfits = 0;
|
|
72
|
+
let totalUserProfitSharePaid = new BN(0);
|
|
73
|
+
let totalUserProfitShareSharesPaid = new BN(0);
|
|
74
|
+
let totalPendingProfitShareAmount = new BN(0);
|
|
75
|
+
let totalPendingProfitShareShares = new BN(0);
|
|
76
|
+
let totalUserNetDeposits = new BN(0);
|
|
77
|
+
|
|
78
|
+
console.log(
|
|
79
|
+
`Vault ${vaultAddress} vd and invariant check at approx slot: ${approxSlot}, date: ${new Date(
|
|
80
|
+
now
|
|
81
|
+
).toLocaleString()}`
|
|
82
|
+
);
|
|
83
|
+
let nonZero = 0;
|
|
84
|
+
let usersWithoutPendingProfitShare = 0;
|
|
85
|
+
let usersWithPendingProfitShare = 0;
|
|
86
|
+
const sortedVd = allVaultDepositors.sort((a, b) =>
|
|
87
|
+
b.account.vaultShares.cmp(a.account.vaultShares)
|
|
88
|
+
);
|
|
89
|
+
const checkAuths: Array<string> = [];
|
|
90
|
+
for (const vd of sortedVd) {
|
|
91
|
+
const vdAccount = vd.account as VaultDepositor;
|
|
92
|
+
|
|
93
|
+
if (vdAccount.vaultShares.gt(new BN(0))) {
|
|
94
|
+
nonZero++;
|
|
95
|
+
}
|
|
96
|
+
totalUserNetDeposits = totalUserNetDeposits.add(vdAccount.netDeposits);
|
|
97
|
+
|
|
98
|
+
totalUserShares = totalUserShares.add(vdAccount.vaultShares);
|
|
99
|
+
const vdAuth = vdAccount.authority.toBase58();
|
|
100
|
+
const vdPct =
|
|
101
|
+
vdAccount.vaultShares.toNumber() / vault.totalShares.toNumber();
|
|
102
|
+
console.log(
|
|
103
|
+
`- ${vdAuth} has ${vdAccount.vaultShares.toNumber()} shares (${
|
|
104
|
+
vdPct * 100.0
|
|
105
|
+
}% of vault)`
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (!vdAccount.lastWithdrawRequest.shares.eq(new BN(0))) {
|
|
109
|
+
const withdrawRequested = vdAccount.lastWithdrawRequest.ts.toNumber();
|
|
110
|
+
const secToWithdrawal =
|
|
111
|
+
withdrawRequested + vault.redeemPeriod.toNumber() - Date.now() / 1000;
|
|
112
|
+
const withdrawAvailable = secToWithdrawal < 0;
|
|
113
|
+
const pct =
|
|
114
|
+
vdAccount.lastWithdrawRequest.shares.toNumber() /
|
|
115
|
+
vd.account.vaultShares.toNumber();
|
|
116
|
+
const daysUntilWithdraw = Math.floor(secToWithdrawal / 86400);
|
|
117
|
+
const hoursUntilWithdraw = Math.floor((secToWithdrawal % 86400) / 3600);
|
|
118
|
+
|
|
119
|
+
console.log(
|
|
120
|
+
` - pending withdrawal: ${vdAccount.lastWithdrawRequest.shares.toString()} ($${convertToNumber(
|
|
121
|
+
vd.account.lastWithdrawRequest.value,
|
|
122
|
+
spotPrecision
|
|
123
|
+
)}), ${(pct * 100.0).toFixed(2)}% of their deposit ${
|
|
124
|
+
withdrawAvailable ? '<--- WITHDRAWABLE' : ''
|
|
125
|
+
}`
|
|
126
|
+
);
|
|
127
|
+
console.log(
|
|
128
|
+
` - requested at: ${new Date(
|
|
129
|
+
withdrawRequested * 1000
|
|
130
|
+
).toISOString()}`
|
|
131
|
+
);
|
|
132
|
+
console.log(
|
|
133
|
+
` - can withdraw in: ${daysUntilWithdraw} days and ${hoursUntilWithdraw} hours`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
totalUserProfitSharePaid = totalUserProfitSharePaid.add(
|
|
138
|
+
vdAccount.profitShareFeePaid
|
|
139
|
+
);
|
|
140
|
+
totalUserProfitShareSharesPaid = totalUserProfitShareSharesPaid.add(
|
|
141
|
+
vdAccount.cumulativeProfitShareAmount
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const pendingProfitShares = calculateApplyProfitShare(
|
|
145
|
+
vdAccount,
|
|
146
|
+
vaultEquitySpot,
|
|
147
|
+
vault
|
|
148
|
+
);
|
|
149
|
+
const pendingProfitShareAmtNum = convertToNumber(
|
|
150
|
+
pendingProfitShares.profitShareAmount,
|
|
151
|
+
spotPrecision
|
|
152
|
+
);
|
|
153
|
+
if (pendingProfitShares.profitShareAmount.gt(ZERO)) {
|
|
154
|
+
totalPendingProfitShareAmount = totalPendingProfitShareAmount.add(
|
|
155
|
+
pendingProfitShares.profitShareAmount
|
|
156
|
+
);
|
|
157
|
+
totalPendingProfitShareShares = totalPendingProfitShareShares.add(
|
|
158
|
+
pendingProfitShares.profitShareShares
|
|
159
|
+
);
|
|
160
|
+
console.log(
|
|
161
|
+
` - pending profit share amount: ${convertToNumber(
|
|
162
|
+
pendingProfitShares.profitShareAmount,
|
|
163
|
+
spotPrecision
|
|
164
|
+
)}`
|
|
165
|
+
);
|
|
166
|
+
usersWithPendingProfitShare++;
|
|
167
|
+
} else {
|
|
168
|
+
console.log(` - no pending profit share`);
|
|
169
|
+
usersWithoutPendingProfitShare++;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const userShareValue = vaultEquitySpot
|
|
173
|
+
.mul(vdAccount.vaultShares)
|
|
174
|
+
.div(vault.totalShares);
|
|
175
|
+
const userShareValueNum = convertToNumber(userShareValue, spotPrecision);
|
|
176
|
+
const netDepositsNum = convertToNumber(
|
|
177
|
+
vdAccount.netDeposits,
|
|
178
|
+
spotPrecision
|
|
179
|
+
);
|
|
180
|
+
const vdProfits = userShareValueNum - netDepositsNum;
|
|
181
|
+
const profitSharePaid = convertToNumber(
|
|
182
|
+
vdAccount.profitShareFeePaid,
|
|
183
|
+
spotPrecision
|
|
184
|
+
);
|
|
185
|
+
const cumProfitShareNum = convertToNumber(
|
|
186
|
+
vdAccount.cumulativeProfitShareAmount,
|
|
187
|
+
spotPrecision
|
|
188
|
+
);
|
|
189
|
+
totalUserProfits += vdProfits;
|
|
190
|
+
totalUserCumProfits += cumProfitShareNum;
|
|
191
|
+
console.log(` - net deposits: ${netDepositsNum}`);
|
|
192
|
+
console.log(` - vd profit: ${vdProfits}`);
|
|
193
|
+
console.log(` - cumProfitshareAmt: ${cumProfitShareNum}`);
|
|
194
|
+
console.log(
|
|
195
|
+
` - profitShareFeePaid: ${convertToNumber(
|
|
196
|
+
vdAccount.profitShareFeePaid,
|
|
197
|
+
spotPrecision
|
|
198
|
+
)}`
|
|
199
|
+
);
|
|
200
|
+
const inclProfitShare =
|
|
201
|
+
((profitSharePaid + pendingProfitShareAmtNum) /
|
|
202
|
+
(cumProfitShareNum + pendingProfitShareAmtNum)) *
|
|
203
|
+
100.0;
|
|
204
|
+
console.log(
|
|
205
|
+
` - pftSharePaidPct (excl pend): ${(
|
|
206
|
+
(profitSharePaid / cumProfitShareNum) *
|
|
207
|
+
100.0
|
|
208
|
+
).toFixed(2)}%`
|
|
209
|
+
);
|
|
210
|
+
console.log(
|
|
211
|
+
` - pftSharePaidPct (incl pend): ${inclProfitShare.toFixed(2)}% `
|
|
212
|
+
);
|
|
213
|
+
if (inclProfitShare < 29.9 && inclProfitShare > 0) {
|
|
214
|
+
console.log(` ^^^ weird: ${inclProfitShare}`);
|
|
215
|
+
checkAuths.push(vdAuth);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (vdAccount.vaultSharesBase !== 0) {
|
|
219
|
+
console.log(
|
|
220
|
+
` - Nonzero vault shares base: ${vdAccount.vaultSharesBase} `
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
console.log(`Check these auths:\n${checkAuths.join('\n')}`);
|
|
225
|
+
console.log(
|
|
226
|
+
`Depositors with 0 shares: ${allVaultDepositors.length - nonZero} /${
|
|
227
|
+
allVaultDepositors.length
|
|
228
|
+
}`
|
|
229
|
+
);
|
|
230
|
+
console.log(
|
|
231
|
+
`Depositors with pending profit share: ${usersWithPendingProfitShare}`
|
|
232
|
+
);
|
|
233
|
+
console.log(
|
|
234
|
+
`Depositors without pending profit share: ${usersWithoutPendingProfitShare}`
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
console.log(`==== Vault Depositor Shares == vault.user_shares ====`);
|
|
238
|
+
console.log(`total vd shares: ${totalUserShares.toString()}`);
|
|
239
|
+
console.log(`total vault usershares: ${vault.userShares.toString()}`);
|
|
240
|
+
console.log(`diff: ${vault.userShares.sub(totalUserShares)}`);
|
|
241
|
+
|
|
242
|
+
console.log(``);
|
|
243
|
+
console.log(
|
|
244
|
+
`==== Vault Depositor ProfitSharePaid == vault.manager_total_profit_share ====`
|
|
245
|
+
);
|
|
246
|
+
console.log(
|
|
247
|
+
`total vault d profitshares: ${totalUserProfitSharePaid.toString()}`
|
|
248
|
+
);
|
|
249
|
+
console.log(
|
|
250
|
+
`vault total profit shares: ${vault.managerTotalProfitShare.toString()}`
|
|
251
|
+
);
|
|
252
|
+
console.log(
|
|
253
|
+
`diff: ${vault.managerTotalProfitShare.sub(totalUserProfitSharePaid)}`
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
console.log(``);
|
|
257
|
+
console.log(`==== Pending profit shares to realize ====`);
|
|
258
|
+
const totalPendingProfitShareAmountNum = convertToNumber(
|
|
259
|
+
totalPendingProfitShareAmount,
|
|
260
|
+
spotPrecision
|
|
261
|
+
);
|
|
262
|
+
const totalUserProfitSharePaidNum = convertToNumber(
|
|
263
|
+
totalUserProfitSharePaid,
|
|
264
|
+
spotPrecision
|
|
265
|
+
);
|
|
266
|
+
console.log(`amount: ${totalPendingProfitShareAmountNum}`);
|
|
267
|
+
console.log(`shares: ${totalPendingProfitShareShares.toNumber()}`);
|
|
268
|
+
// console.log(`csv: ${cmdOpts.csv}`);
|
|
269
|
+
|
|
270
|
+
console.log(``);
|
|
271
|
+
console.log(`==== Agg user profit share paid ====`);
|
|
272
|
+
console.log(
|
|
273
|
+
`vd total profit (incl unrealized profit share): ${totalUserProfits}`
|
|
274
|
+
);
|
|
275
|
+
console.log(
|
|
276
|
+
`vd total cum profits (before pending profit share): ${totalUserCumProfits}`
|
|
277
|
+
);
|
|
278
|
+
console.log(
|
|
279
|
+
`vd total profit share paid): ${totalUserProfitSharePaidNum}`
|
|
280
|
+
);
|
|
281
|
+
console.log(
|
|
282
|
+
`vd total pending profit share: ${totalPendingProfitShareAmountNum}`
|
|
283
|
+
);
|
|
284
|
+
console.log(
|
|
285
|
+
`vd total net deposits: ${convertToNumber(
|
|
286
|
+
totalUserNetDeposits,
|
|
287
|
+
spotPrecision
|
|
288
|
+
)}`
|
|
289
|
+
);
|
|
290
|
+
const driftUserDeposits = user.getUserAccount().totalDeposits;
|
|
291
|
+
const driftUserWithdraws = user.getUserAccount().totalWithdraws;
|
|
292
|
+
const driftUserSocialLoss = user.getUserAccount().totalSocialLoss;
|
|
293
|
+
console.log(
|
|
294
|
+
`vd drift user net deposits: ${convertToNumber(
|
|
295
|
+
driftUserDeposits.sub(driftUserWithdraws).sub(driftUserSocialLoss),
|
|
296
|
+
spotPrecision
|
|
297
|
+
)}`
|
|
298
|
+
);
|
|
299
|
+
console.log(
|
|
300
|
+
` vd drift user deps: ${convertToNumber(driftUserDeposits, spotPrecision)}`
|
|
301
|
+
);
|
|
302
|
+
console.log(
|
|
303
|
+
` vd drift user with: ${convertToNumber(
|
|
304
|
+
driftUserWithdraws,
|
|
305
|
+
spotPrecision
|
|
306
|
+
)}`
|
|
307
|
+
);
|
|
308
|
+
console.log(
|
|
309
|
+
` vd drift user scls: ${convertToNumber(
|
|
310
|
+
driftUserSocialLoss,
|
|
311
|
+
spotPrecision
|
|
312
|
+
)}`
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
console.log(``);
|
|
316
|
+
console.log(`==== Manager share ====`);
|
|
317
|
+
console.log(` Vault total shares: ${vault.totalShares.toNumber()}`);
|
|
318
|
+
const managerShares = vault.totalShares.sub(vault.userShares);
|
|
319
|
+
const managerSharePct =
|
|
320
|
+
managerShares.toNumber() / vault.totalShares.toNumber();
|
|
321
|
+
const managerShareWithPendingPct =
|
|
322
|
+
managerShares.add(totalPendingProfitShareShares).toNumber() /
|
|
323
|
+
vault.totalShares.toNumber();
|
|
324
|
+
console.log(
|
|
325
|
+
` Manager shares: ${managerShares.toString()} (${(
|
|
326
|
+
managerSharePct * 100.0
|
|
327
|
+
).toFixed(4)}%)`
|
|
328
|
+
);
|
|
329
|
+
const vaultEquityNum = convertToNumber(vaultEquity, spotPrecision);
|
|
330
|
+
const vaultEquitySpotNum = convertToNumber(vaultEquitySpot, spotPrecision);
|
|
331
|
+
const vaultPnlNum = convertToNumber(
|
|
332
|
+
user.getTotalAllTimePnl(),
|
|
333
|
+
QUOTE_PRECISION
|
|
334
|
+
);
|
|
335
|
+
console.log(`vaultEquity (USDC): $${vaultEquityNum}`);
|
|
336
|
+
console.log(`vaultEquity (deposit asset): ${vaultEquitySpotNum}`);
|
|
337
|
+
const managerValueWoPending = managerSharePct * vaultEquitySpotNum;
|
|
338
|
+
const managerValueWithPending =
|
|
339
|
+
managerShareWithPendingPct * vaultEquitySpotNum;
|
|
340
|
+
console.log(
|
|
341
|
+
`manager share (w/o pending) (deposit asset): ${managerValueWoPending} (share: ${
|
|
342
|
+
(managerValueWoPending / vaultPnlNum) * 100.0
|
|
343
|
+
}%)`
|
|
344
|
+
);
|
|
345
|
+
console.log(
|
|
346
|
+
`manager share (with pending) (deposit asset): ${managerValueWithPending} (share: ${
|
|
347
|
+
(managerValueWithPending / vaultPnlNum) * 100.0
|
|
348
|
+
}%)`
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
console.log(``);
|
|
352
|
+
const profitSharePct = vault.profitShare / PERCENTAGE_PRECISION.toNumber();
|
|
353
|
+
const vdPnlBeforeProfitShare =
|
|
354
|
+
convertToNumber(totalUserProfitSharePaid, spotPrecision) / profitSharePct;
|
|
355
|
+
console.log(
|
|
356
|
+
`back out vault pnl: (userPnl + managerShareValue): ${totalUserProfits} + ${
|
|
357
|
+
managerSharePct * vaultEquitySpotNum
|
|
358
|
+
} = ${totalUserProfits + managerSharePct * vaultEquitySpotNum}`
|
|
359
|
+
);
|
|
360
|
+
console.log(
|
|
361
|
+
`vaultDepositors pnl (before profit share): ${vdPnlBeforeProfitShare}`
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
console.log(
|
|
365
|
+
`vault PnL (spot): ${
|
|
366
|
+
vaultEquitySpotNum - convertToNumber(vault.netDeposits, spotPrecision)
|
|
367
|
+
}`
|
|
368
|
+
);
|
|
369
|
+
console.log(`vault PnL (USD) ${vaultPnlNum}`);
|
|
370
|
+
console.log(`vault PnL (spot) ${vaultPnlNum / spotOraclePriceNum}`);
|
|
371
|
+
|
|
372
|
+
console.log(``);
|
|
373
|
+
console.log(`==== ${decodeName(vault.name)} Profit Summary ====`);
|
|
374
|
+
console.log(
|
|
375
|
+
`Depositors' total PnL: ${totalUserProfits} ${spotSymbol}`
|
|
376
|
+
);
|
|
377
|
+
console.log(
|
|
378
|
+
`Depositors' profit share paid to date: ${totalUserProfitSharePaidNum} ${spotSymbol}`
|
|
379
|
+
);
|
|
380
|
+
console.log(
|
|
381
|
+
`Unrealized profit share: ${totalPendingProfitShareAmountNum} ${spotSymbol}`
|
|
382
|
+
);
|
|
383
|
+
console.log(
|
|
384
|
+
`Vault manager net deposits: ${convertToNumber(
|
|
385
|
+
vault.managerNetDeposits,
|
|
386
|
+
spotPrecision
|
|
387
|
+
)} ${spotSymbol}`
|
|
388
|
+
);
|
|
389
|
+
console.log(
|
|
390
|
+
`Vault manager profit share received: ${convertToNumber(
|
|
391
|
+
vault.managerTotalProfitShare,
|
|
392
|
+
spotPrecision
|
|
393
|
+
)} ${spotSymbol}`
|
|
394
|
+
);
|
|
395
|
+
console.log(
|
|
396
|
+
`Vault manager share value: ${managerValueWithPending} ${spotSymbol} (share of vault: ${
|
|
397
|
+
(managerValueWithPending / vaultPnlNum) * 100.0
|
|
398
|
+
}%)`
|
|
399
|
+
);
|
|
400
|
+
if (spotSymbol !== 'USDC') {
|
|
401
|
+
console.log(
|
|
402
|
+
`Vault manager share value: ${
|
|
403
|
+
managerValueWithPending * spotOraclePriceNum
|
|
404
|
+
} USDC`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import {
|
|
3
|
+
getVaultDepositorAddressSync
|
|
4
|
+
} from "../../src/addresses";
|
|
5
|
+
import {
|
|
6
|
+
OptionValues,
|
|
7
|
+
Command
|
|
8
|
+
} from "commander";
|
|
9
|
+
import { getCommandContext } from "../utils";
|
|
10
|
+
import { VAULT_PROGRAM_ID } from "../../src/types/types";
|
|
11
|
+
|
|
12
|
+
export const vaultWithdraw= async (program: Command, cmdOpts: OptionValues) => {
|
|
13
|
+
|
|
14
|
+
let vaultAddress: PublicKey;
|
|
15
|
+
try {
|
|
16
|
+
vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.error("Invalid vault address");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let depositAuthority: PublicKey;
|
|
23
|
+
try {
|
|
24
|
+
depositAuthority = new PublicKey(cmdOpts.depositAuthority as string);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.error("Invalid deposit authority");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
driftVault
|
|
32
|
+
} = await getCommandContext(program, true);
|
|
33
|
+
|
|
34
|
+
const vaultDepositorAddress = getVaultDepositorAddressSync(
|
|
35
|
+
VAULT_PROGRAM_ID,
|
|
36
|
+
vaultAddress,
|
|
37
|
+
depositAuthority,
|
|
38
|
+
);
|
|
39
|
+
const tx = await driftVault.initializeVaultDepositor(vaultAddress, depositAuthority);
|
|
40
|
+
console.log(`VaultDepositor initialized for ${depositAuthority}: ${tx}`);
|
|
41
|
+
console.log(`VaultDepositor address: ${vaultDepositorAddress}`);
|
|
42
|
+
};
|