@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,94 @@
|
|
|
1
|
+
import { Command, OptionValues } from 'commander';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { BN, TEN } from '@velocity-exchange/sdk';
|
|
4
|
+
import { dumpTransactionMessage, getCommandContext } from '../utils';
|
|
5
|
+
|
|
6
|
+
export async function managerRepay(
|
|
7
|
+
program: Command,
|
|
8
|
+
cmdOpts: OptionValues
|
|
9
|
+
): Promise<void> {
|
|
10
|
+
const {
|
|
11
|
+
vaultAddress,
|
|
12
|
+
repaySpotMarketIndex,
|
|
13
|
+
repayAmount,
|
|
14
|
+
repayValue,
|
|
15
|
+
managerTokenAccount,
|
|
16
|
+
dumpTransactionMessage: dumpTx,
|
|
17
|
+
} = cmdOpts;
|
|
18
|
+
|
|
19
|
+
const { driftClient, driftVault } = await getCommandContext(program, true);
|
|
20
|
+
|
|
21
|
+
if (!vaultAddress) {
|
|
22
|
+
throw new Error('Must provide vault address with --vault-address');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!repaySpotMarketIndex) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
'Must provide repay spot market index with --repay-spot-market-index'
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!repayAmount) {
|
|
32
|
+
throw new Error('Must provide repay amount with --repay-amount');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const vault = new PublicKey(vaultAddress);
|
|
36
|
+
const repayIndex = parseInt(repaySpotMarketIndex);
|
|
37
|
+
|
|
38
|
+
const repaySpotMarket = driftClient.getSpotMarketAccount(repayIndex);
|
|
39
|
+
if (!repaySpotMarket) {
|
|
40
|
+
throw new Error('No repay spot market found');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const vaultAccount = await driftVault.program.account.vault.fetch(vault);
|
|
44
|
+
const depositSpotMarket = driftClient.getSpotMarketAccount(
|
|
45
|
+
vaultAccount.spotMarketIndex
|
|
46
|
+
);
|
|
47
|
+
if (!depositSpotMarket) {
|
|
48
|
+
throw new Error('No deposit spot market found');
|
|
49
|
+
}
|
|
50
|
+
const depositPrecision = TEN.pow(new BN(depositSpotMarket.decimals));
|
|
51
|
+
|
|
52
|
+
const repayPrecision = TEN.pow(new BN(repaySpotMarket.decimals));
|
|
53
|
+
const repayBN = new BN(repayAmount * repayPrecision.toNumber());
|
|
54
|
+
|
|
55
|
+
const valueBN = repayValue
|
|
56
|
+
? new BN(repayValue * depositPrecision.toNumber())
|
|
57
|
+
: null;
|
|
58
|
+
|
|
59
|
+
const managerTokenAccountPubkey = managerTokenAccount
|
|
60
|
+
? new PublicKey(managerTokenAccount)
|
|
61
|
+
: undefined;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
if (dumpTx) {
|
|
65
|
+
const ixs = await driftVault.getManagerRepayIxs(
|
|
66
|
+
vault,
|
|
67
|
+
repayIndex,
|
|
68
|
+
repayBN,
|
|
69
|
+
valueBN,
|
|
70
|
+
managerTokenAccountPubkey
|
|
71
|
+
);
|
|
72
|
+
console.log('Transaction Instructions:');
|
|
73
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, ixs));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const txSig = await driftVault.managerRepay(
|
|
78
|
+
vault,
|
|
79
|
+
repayIndex,
|
|
80
|
+
repayBN,
|
|
81
|
+
valueBN,
|
|
82
|
+
managerTokenAccountPubkey
|
|
83
|
+
);
|
|
84
|
+
console.log(`Manager repay transaction signature: ${txSig}`);
|
|
85
|
+
console.log(
|
|
86
|
+
`Transaction: https://solana.fm/tx/${txSig}${
|
|
87
|
+
driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
|
|
88
|
+
}`
|
|
89
|
+
);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error('Error repaying:', error);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { BN, TEN, decodeName, numberToSafeBN } from '@velocity-exchange/sdk';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { OptionValues, Command } from 'commander';
|
|
4
|
+
import { dumpTransactionMessage, getCommandContext } from '../utils';
|
|
5
|
+
import { WithdrawUnit } from '../../src/types/types';
|
|
6
|
+
|
|
7
|
+
export const managerRequestWithdraw = async (
|
|
8
|
+
program: Command,
|
|
9
|
+
cmdOpts: OptionValues
|
|
10
|
+
) => {
|
|
11
|
+
let vaultAddress: PublicKey;
|
|
12
|
+
try {
|
|
13
|
+
vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.error('Invalid vault address');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { driftClient, driftVault } = await getCommandContext(program, true);
|
|
20
|
+
|
|
21
|
+
if (!cmdOpts.shares && !cmdOpts.amount) {
|
|
22
|
+
console.error('One of --shares or --amount must be provided.');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (cmdOpts.shares && !cmdOpts.amount) {
|
|
27
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
28
|
+
const tx = await driftVault.getManagerRequestWithdrawIx(
|
|
29
|
+
vaultAddress,
|
|
30
|
+
new BN(cmdOpts.shares),
|
|
31
|
+
WithdrawUnit.SHARES
|
|
32
|
+
);
|
|
33
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
34
|
+
} else {
|
|
35
|
+
const tx = await driftVault.managerRequestWithdraw(
|
|
36
|
+
vaultAddress,
|
|
37
|
+
new BN(cmdOpts.shares),
|
|
38
|
+
WithdrawUnit.SHARES
|
|
39
|
+
);
|
|
40
|
+
console.log(
|
|
41
|
+
`Requested to withraw ${
|
|
42
|
+
cmdOpts.shares
|
|
43
|
+
} shares as vault manager: https://solana.fm/tx/${tx}${
|
|
44
|
+
driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
|
|
45
|
+
}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
} else if (cmdOpts.amount && !cmdOpts.shares) {
|
|
49
|
+
const vault = await driftVault.getVault(vaultAddress);
|
|
50
|
+
const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
|
|
51
|
+
if (!spotMarket) {
|
|
52
|
+
console.error('Error: Spot market not found');
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
|
|
56
|
+
const amount = parseFloat(cmdOpts.amount);
|
|
57
|
+
const amountBN = numberToSafeBN(amount, spotPrecision);
|
|
58
|
+
|
|
59
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
60
|
+
const tx = await driftVault.getManagerRequestWithdrawIx(
|
|
61
|
+
vaultAddress,
|
|
62
|
+
amountBN,
|
|
63
|
+
WithdrawUnit.TOKEN
|
|
64
|
+
);
|
|
65
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
66
|
+
} else {
|
|
67
|
+
const tx = await driftVault.managerRequestWithdraw(
|
|
68
|
+
vaultAddress,
|
|
69
|
+
amountBN,
|
|
70
|
+
WithdrawUnit.TOKEN
|
|
71
|
+
);
|
|
72
|
+
console.log(
|
|
73
|
+
`Requested to withdraw ${amount} ${decodeName(
|
|
74
|
+
spotMarket.name
|
|
75
|
+
)} as vault manager: https://solana.fm/tx/${tx}${
|
|
76
|
+
driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
|
|
77
|
+
}`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
console.error(
|
|
82
|
+
'Error: Either shares or amount must be provided, but not both.'
|
|
83
|
+
);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Command, OptionValues } from 'commander';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { BN, TEN } from '@velocity-exchange/sdk';
|
|
4
|
+
import { dumpTransactionMessage, getCommandContext } from '../utils';
|
|
5
|
+
|
|
6
|
+
export async function managerUpdateBorrow(
|
|
7
|
+
program: Command,
|
|
8
|
+
cmdOpts: OptionValues
|
|
9
|
+
): Promise<void> {
|
|
10
|
+
const {
|
|
11
|
+
vaultAddress,
|
|
12
|
+
newBorrowValue,
|
|
13
|
+
dumpTransactionMessage: dumpTx,
|
|
14
|
+
} = cmdOpts;
|
|
15
|
+
|
|
16
|
+
const { driftClient, driftVault } = await getCommandContext(program, true);
|
|
17
|
+
|
|
18
|
+
if (!vaultAddress) {
|
|
19
|
+
throw new Error('Must provide vault address with --vault-address');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!newBorrowValue) {
|
|
23
|
+
throw new Error('Must provide new borrow value with --new-borrow-value');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const vault = new PublicKey(vaultAddress);
|
|
27
|
+
const vaultAccount = await driftVault.program.account.vault.fetch(vault);
|
|
28
|
+
const depositSpotMarket = driftClient.getSpotMarketAccount(
|
|
29
|
+
vaultAccount.spotMarketIndex
|
|
30
|
+
);
|
|
31
|
+
if (!depositSpotMarket) {
|
|
32
|
+
throw new Error('No deposit spot market found');
|
|
33
|
+
}
|
|
34
|
+
const depositPrecision = TEN.pow(new BN(depositSpotMarket.decimals));
|
|
35
|
+
const borrowValue = new BN(newBorrowValue * depositPrecision.toNumber());
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
if (dumpTx) {
|
|
39
|
+
const ix = await driftVault.getManagerUpdateBorrowIx(vault, borrowValue);
|
|
40
|
+
console.log('Transaction Instruction:');
|
|
41
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [ix]));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const txSig = await driftVault.managerUpdateBorrow(vault, borrowValue);
|
|
46
|
+
console.log(`Manager update borrow transaction signature: ${txSig}`);
|
|
47
|
+
console.log(
|
|
48
|
+
`Transaction: https://solana.fm/tx/${txSig}${
|
|
49
|
+
driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
|
|
50
|
+
}`
|
|
51
|
+
);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error('Error updating borrow:', error);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { OptionValues, Command } from 'commander';
|
|
3
|
+
import { dumpTransactionMessage, getCommandContext } from '../utils';
|
|
4
|
+
import {
|
|
5
|
+
BN,
|
|
6
|
+
PERCENTAGE_PRECISION,
|
|
7
|
+
convertToNumber,
|
|
8
|
+
} from '@velocity-exchange/sdk';
|
|
9
|
+
|
|
10
|
+
export const managerUpdateFees = async (
|
|
11
|
+
program: Command,
|
|
12
|
+
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
|
+
const { driftVault, driftClient } = await getCommandContext(program, true);
|
|
23
|
+
|
|
24
|
+
const vault = await driftVault.getVault(vaultAddress);
|
|
25
|
+
|
|
26
|
+
const timelockDuration = cmdOpts.timelockDuration;
|
|
27
|
+
let timelockDurationBN: BN | null = null;
|
|
28
|
+
const minTimelockDurationBN = new BN(
|
|
29
|
+
Math.max(7 * 24 * 60 * 60, vault.redeemPeriod.toNumber() * 2)
|
|
30
|
+
);
|
|
31
|
+
if (timelockDuration !== undefined && timelockDuration !== null) {
|
|
32
|
+
timelockDurationBN = new BN(parseInt(timelockDuration));
|
|
33
|
+
if (timelockDurationBN.lt(minTimelockDurationBN)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Timelock duration must be at least ${minTimelockDurationBN.toNumber()} seconds`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
timelockDurationBN = minTimelockDurationBN;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let managementFee = cmdOpts.managementFee;
|
|
43
|
+
let managementFeeBN: BN | null = null;
|
|
44
|
+
if (managementFee !== undefined && managementFee !== null) {
|
|
45
|
+
managementFee = parseInt(managementFee);
|
|
46
|
+
managementFeeBN = new BN(managementFee)
|
|
47
|
+
.mul(PERCENTAGE_PRECISION)
|
|
48
|
+
.div(new BN(100));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let profitShare = cmdOpts.profitShare;
|
|
52
|
+
let profitShareNumber: number | null = null;
|
|
53
|
+
if (profitShare !== undefined && profitShare !== null) {
|
|
54
|
+
profitShare = parseInt(profitShare);
|
|
55
|
+
profitShareNumber = (profitShare * PERCENTAGE_PRECISION.toNumber()) / 100.0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let hurdleRate = cmdOpts.hurdleRate;
|
|
59
|
+
let hurdleRateNumber: number | null = null;
|
|
60
|
+
if (hurdleRate !== undefined && hurdleRate !== null) {
|
|
61
|
+
hurdleRate = parseInt(hurdleRate);
|
|
62
|
+
hurdleRateNumber = (hurdleRate * PERCENTAGE_PRECISION.toNumber()) / 100.0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(
|
|
66
|
+
`Updating fees, effective in ${timelockDurationBN?.toNumber()} seconds`
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const managementFeeBefore =
|
|
70
|
+
convertToNumber(vault.managementFee, PERCENTAGE_PRECISION) * 100.0;
|
|
71
|
+
const managementFeeAfter = managementFeeBN
|
|
72
|
+
? `${convertToNumber(managementFeeBN, PERCENTAGE_PRECISION) * 100.0}%`
|
|
73
|
+
: 'unchanged';
|
|
74
|
+
console.log(
|
|
75
|
+
` ManagementFee: ${managementFeeBefore}% -> ${managementFeeAfter}`
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const profitShareBefore =
|
|
79
|
+
(vault.profitShare / PERCENTAGE_PRECISION.toNumber()) * 100.0;
|
|
80
|
+
const profitShareAfter =
|
|
81
|
+
profitShareNumber !== null
|
|
82
|
+
? `${(profitShareNumber / PERCENTAGE_PRECISION.toNumber()) * 100.0}%`
|
|
83
|
+
: 'unchanged';
|
|
84
|
+
console.log(
|
|
85
|
+
` ProfitShare: ${profitShareBefore}% -> ${profitShareAfter}`
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const hurdleRateBefore =
|
|
89
|
+
(vault.hurdleRate / PERCENTAGE_PRECISION.toNumber()) * 100.0;
|
|
90
|
+
const hurdleRateAfter =
|
|
91
|
+
hurdleRateNumber !== null
|
|
92
|
+
? `${(hurdleRateNumber / PERCENTAGE_PRECISION.toNumber()) * 100.0}%`
|
|
93
|
+
: 'unchanged';
|
|
94
|
+
console.log(
|
|
95
|
+
` HurdleRate: ${hurdleRateBefore}% -> ${hurdleRateAfter}`
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const readline = require('readline').createInterface({
|
|
99
|
+
input: process.stdin,
|
|
100
|
+
output: process.stdout,
|
|
101
|
+
});
|
|
102
|
+
console.log('');
|
|
103
|
+
const answer = await new Promise((resolve) => {
|
|
104
|
+
readline.question(
|
|
105
|
+
'Is the above information correct? (yes/no) ',
|
|
106
|
+
(answer: string) => {
|
|
107
|
+
readline.close();
|
|
108
|
+
resolve(answer);
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
if ((answer as string).toLowerCase() !== 'yes') {
|
|
113
|
+
console.log('Fee update canceled.');
|
|
114
|
+
readline.close();
|
|
115
|
+
process.exit(0);
|
|
116
|
+
}
|
|
117
|
+
console.log('Updating fees...');
|
|
118
|
+
|
|
119
|
+
const newParams = {
|
|
120
|
+
timelockDuration: timelockDurationBN,
|
|
121
|
+
newManagementFee: managementFeeBN,
|
|
122
|
+
newProfitShare: profitShareNumber,
|
|
123
|
+
newHurdleRate: hurdleRateNumber,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
let done = false;
|
|
127
|
+
while (!done) {
|
|
128
|
+
try {
|
|
129
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
130
|
+
const tx = await driftVault.getManagerUpdateFeesIx(
|
|
131
|
+
vaultAddress,
|
|
132
|
+
newParams
|
|
133
|
+
);
|
|
134
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
135
|
+
} else {
|
|
136
|
+
const tx = await driftVault.managerUpdateFees(vaultAddress, newParams);
|
|
137
|
+
console.log(
|
|
138
|
+
`Updated vault fees as vault manager: https://solana.fm/tx/${tx}${
|
|
139
|
+
driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
|
|
140
|
+
}`
|
|
141
|
+
);
|
|
142
|
+
done = true;
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
} catch (e) {
|
|
146
|
+
const err = e as Error;
|
|
147
|
+
if (err.message.includes('TransactionExpiredTimeoutError')) {
|
|
148
|
+
console.log(err.message);
|
|
149
|
+
console.log('Transaction timeout. Retrying...');
|
|
150
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
151
|
+
} else {
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import {
|
|
3
|
+
OptionValues,
|
|
4
|
+
Command
|
|
5
|
+
} from "commander";
|
|
6
|
+
import { dumpTransactionMessage, getCommandContext } from "../utils";
|
|
7
|
+
|
|
8
|
+
export const managerUpdateMarginTradingEnabled = async (program: Command, cmdOpts: OptionValues) => {
|
|
9
|
+
|
|
10
|
+
let vaultAddress: PublicKey;
|
|
11
|
+
try {
|
|
12
|
+
vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
13
|
+
} catch (err) {
|
|
14
|
+
console.error("Invalid vault address");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
driftVault,
|
|
20
|
+
driftClient
|
|
21
|
+
} = await getCommandContext(program, true);
|
|
22
|
+
|
|
23
|
+
const enabled = cmdOpts.enabled ? (cmdOpts.enabled as string).toLowerCase() === "true" : false;
|
|
24
|
+
|
|
25
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
26
|
+
const tx = await driftVault.getUpdateMarginTradingEnabledIx(vaultAddress, enabled);
|
|
27
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
28
|
+
} else {
|
|
29
|
+
const tx = await driftVault.updateMarginTradingEnabled(vaultAddress, enabled);
|
|
30
|
+
console.log(`Updated margin trading vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import {
|
|
3
|
+
OptionValues,
|
|
4
|
+
Command
|
|
5
|
+
} from "commander";
|
|
6
|
+
import { dumpTransactionMessage, getCommandContext } from "../utils";
|
|
7
|
+
|
|
8
|
+
export const managerUpdatePoolId = async (program: Command, cmdOpts: OptionValues) => {
|
|
9
|
+
|
|
10
|
+
let vaultAddress: PublicKey;
|
|
11
|
+
try {
|
|
12
|
+
vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
13
|
+
} catch (err) {
|
|
14
|
+
console.error("Invalid vault address");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
driftVault,
|
|
20
|
+
driftClient
|
|
21
|
+
} = await getCommandContext(program, true);
|
|
22
|
+
|
|
23
|
+
const poolId = cmdOpts.poolId ? Number(cmdOpts.poolId) : null;
|
|
24
|
+
if (poolId === null) {
|
|
25
|
+
console.error("Invalid pool id");
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
30
|
+
const tx = await driftVault.getUpdatePoolIdIx(vaultAddress, poolId);
|
|
31
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
32
|
+
} else {
|
|
33
|
+
const tx = await driftVault.updateUserPoolId(vaultAddress, poolId);
|
|
34
|
+
console.log(`Updated pool id vault manager: https://solana.fm/tx/${tx}${driftClient.env === "devnet" ? "?cluster=devnet-solana" : ""}`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { OptionValues, Command } from 'commander';
|
|
3
|
+
import { dumpTransactionMessage, getCommandContext } from '../utils';
|
|
4
|
+
import {
|
|
5
|
+
BN,
|
|
6
|
+
PERCENTAGE_PRECISION,
|
|
7
|
+
TEN,
|
|
8
|
+
convertToNumber,
|
|
9
|
+
decodeName,
|
|
10
|
+
} from '@velocity-exchange/sdk';
|
|
11
|
+
|
|
12
|
+
export const managerUpdateVault = async (
|
|
13
|
+
program: Command,
|
|
14
|
+
cmdOpts: OptionValues
|
|
15
|
+
) => {
|
|
16
|
+
let vaultAddress: PublicKey;
|
|
17
|
+
try {
|
|
18
|
+
vaultAddress = new PublicKey(cmdOpts.vaultAddress as string);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error('Invalid vault address');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { driftVault, driftClient } = await getCommandContext(program, true);
|
|
25
|
+
|
|
26
|
+
const vault = await driftVault.getVault(vaultAddress);
|
|
27
|
+
const spotMarket = driftClient.getSpotMarketAccount(vault.spotMarketIndex);
|
|
28
|
+
if (!spotMarket) {
|
|
29
|
+
throw new Error('No spot market found');
|
|
30
|
+
}
|
|
31
|
+
const spotPrecision = TEN.pow(new BN(spotMarket.decimals));
|
|
32
|
+
const spotMarketName = decodeName(spotMarket.name);
|
|
33
|
+
|
|
34
|
+
let redeemPeriodSec = cmdOpts.redeemPeriod ?? null;
|
|
35
|
+
let redeemPeriodBN: BN | null = null;
|
|
36
|
+
if (redeemPeriodSec !== undefined && redeemPeriodSec !== null) {
|
|
37
|
+
redeemPeriodSec = parseInt(redeemPeriodSec);
|
|
38
|
+
redeemPeriodBN = new BN(redeemPeriodSec);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let maxTokens = cmdOpts.maxTokens;
|
|
42
|
+
let maxTokensBN: BN | null = null;
|
|
43
|
+
if (maxTokens !== undefined && maxTokens !== null) {
|
|
44
|
+
maxTokens = parseInt(maxTokens);
|
|
45
|
+
maxTokensBN = new BN(maxTokens).mul(spotPrecision);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let managementFee = cmdOpts.managementFee;
|
|
49
|
+
let managementFeeBN: BN | null = null;
|
|
50
|
+
if (managementFee !== undefined && managementFee !== null) {
|
|
51
|
+
managementFee = parseInt(managementFee);
|
|
52
|
+
managementFeeBN = new BN(managementFee)
|
|
53
|
+
.mul(PERCENTAGE_PRECISION)
|
|
54
|
+
.div(new BN(100));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let profitShare = cmdOpts.profitShare;
|
|
58
|
+
let profitShareNumber: number | null = null;
|
|
59
|
+
if (profitShare !== undefined && profitShare !== null) {
|
|
60
|
+
profitShare = parseInt(profitShare);
|
|
61
|
+
profitShareNumber = (profitShare * PERCENTAGE_PRECISION.toNumber()) / 100.0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let hurdleRate = cmdOpts.hurdleRate;
|
|
65
|
+
let hurdleRateNumber: number | null = null;
|
|
66
|
+
if (hurdleRate !== undefined && hurdleRate !== null) {
|
|
67
|
+
hurdleRate = parseInt(hurdleRate);
|
|
68
|
+
hurdleRateNumber = (hurdleRate * PERCENTAGE_PRECISION.toNumber()) / 100.0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let minDepositAmount = cmdOpts.minDepositAmount;
|
|
72
|
+
let minDepositAmountBN: BN | null = null;
|
|
73
|
+
if (minDepositAmount !== undefined && minDepositAmount !== null) {
|
|
74
|
+
minDepositAmount = parseInt(minDepositAmount);
|
|
75
|
+
minDepositAmountBN = new BN(minDepositAmount).mul(spotPrecision);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log(`Updating params:`);
|
|
79
|
+
const redeemPeriodBefore = vault.redeemPeriod.toNumber();
|
|
80
|
+
const redeemPeriodAfter = redeemPeriodBN
|
|
81
|
+
? redeemPeriodBN.toNumber()
|
|
82
|
+
: 'unchanged';
|
|
83
|
+
console.log(
|
|
84
|
+
` RedeemPeriod: ${redeemPeriodBefore} -> ${redeemPeriodAfter}`
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const maxTokensBefore = `${convertToNumber(
|
|
88
|
+
vault.maxTokens,
|
|
89
|
+
spotPrecision
|
|
90
|
+
)} ${spotMarketName}`;
|
|
91
|
+
const maxTokensAfter = maxTokensBN
|
|
92
|
+
? `${convertToNumber(maxTokensBN, spotPrecision)} ${spotMarketName}`
|
|
93
|
+
: 'unchanged';
|
|
94
|
+
console.log(
|
|
95
|
+
` MaxTokens: ${maxTokensBefore} -> ${maxTokensAfter}`
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const minDepositAmountBefore = `${convertToNumber(
|
|
99
|
+
vault.minDepositAmount,
|
|
100
|
+
spotPrecision
|
|
101
|
+
)} ${spotMarketName}`;
|
|
102
|
+
const minDepositAmountAfter = minDepositAmountBN
|
|
103
|
+
? `${convertToNumber(minDepositAmountBN, spotPrecision)} ${spotMarketName}`
|
|
104
|
+
: 'unchanged';
|
|
105
|
+
console.log(
|
|
106
|
+
` MinDepositAmount: ${minDepositAmountBefore} -> ${minDepositAmountAfter}`
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const managementFeeBefore =
|
|
110
|
+
convertToNumber(vault.managementFee, PERCENTAGE_PRECISION) * 100.0;
|
|
111
|
+
const managementFeeAfter = managementFeeBN
|
|
112
|
+
? `${convertToNumber(managementFeeBN, PERCENTAGE_PRECISION) * 100.0}%`
|
|
113
|
+
: 'unchanged';
|
|
114
|
+
console.log(
|
|
115
|
+
` ManagementFee: ${managementFeeBefore}% -> ${managementFeeAfter}`
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const profitShareBefore =
|
|
119
|
+
(vault.profitShare / PERCENTAGE_PRECISION.toNumber()) * 100.0;
|
|
120
|
+
const profitShareAfter =
|
|
121
|
+
profitShareNumber !== null
|
|
122
|
+
? `${(profitShareNumber / PERCENTAGE_PRECISION.toNumber()) * 100.0}%`
|
|
123
|
+
: 'unchanged';
|
|
124
|
+
console.log(
|
|
125
|
+
` ProfitShare: ${profitShareBefore}% -> ${profitShareAfter}`
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const hurdleRateBefore =
|
|
129
|
+
(vault.hurdleRate / PERCENTAGE_PRECISION.toNumber()) * 100.0;
|
|
130
|
+
const hurdleRateAfter =
|
|
131
|
+
hurdleRateNumber !== null
|
|
132
|
+
? `${(hurdleRateNumber / PERCENTAGE_PRECISION.toNumber()) * 100.0}%`
|
|
133
|
+
: 'unchanged';
|
|
134
|
+
console.log(
|
|
135
|
+
` HurdleRate: ${hurdleRateBefore}% -> ${hurdleRateAfter}`
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const permissioned: boolean | null =
|
|
139
|
+
cmdOpts.permissioned === null || cmdOpts.permissioned === undefined
|
|
140
|
+
? null
|
|
141
|
+
: JSON.parse(cmdOpts.permissioned);
|
|
142
|
+
const permissionedBefore = vault.permissioned;
|
|
143
|
+
const permissionedAfter = permissioned !== null ? permissioned : 'unchanged';
|
|
144
|
+
console.log(
|
|
145
|
+
` Permissioned: ${permissionedBefore} -> ${permissionedAfter}`
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const readline = require('readline').createInterface({
|
|
149
|
+
input: process.stdin,
|
|
150
|
+
output: process.stdout,
|
|
151
|
+
});
|
|
152
|
+
console.log('');
|
|
153
|
+
const answer = await new Promise((resolve) => {
|
|
154
|
+
readline.question(
|
|
155
|
+
'Is the above information correct? (yes/no) ',
|
|
156
|
+
(answer: string) => {
|
|
157
|
+
readline.close();
|
|
158
|
+
resolve(answer);
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
if ((answer as string).toLowerCase() !== 'yes') {
|
|
163
|
+
console.log('Vault update canceled.');
|
|
164
|
+
readline.close();
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
console.log('Updating vault...');
|
|
168
|
+
|
|
169
|
+
// null means unchanged
|
|
170
|
+
const newParams = {
|
|
171
|
+
redeemPeriod: redeemPeriodBN,
|
|
172
|
+
maxTokens: maxTokensBN,
|
|
173
|
+
minDepositAmount: minDepositAmountBN,
|
|
174
|
+
managementFee: managementFeeBN,
|
|
175
|
+
profitShare: profitShareNumber,
|
|
176
|
+
hurdleRate: hurdleRateNumber,
|
|
177
|
+
permissioned,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
let done = false;
|
|
181
|
+
while (!done) {
|
|
182
|
+
try {
|
|
183
|
+
if (cmdOpts.dumpTransactionMessage) {
|
|
184
|
+
const tx = await driftVault.getManagerUpdateVaultIx(
|
|
185
|
+
vaultAddress,
|
|
186
|
+
newParams
|
|
187
|
+
);
|
|
188
|
+
console.log(dumpTransactionMessage(driftClient.wallet.publicKey, [tx]));
|
|
189
|
+
} else {
|
|
190
|
+
const tx = await driftVault.managerUpdateVault(vaultAddress, newParams);
|
|
191
|
+
console.log(
|
|
192
|
+
`Updated vault params as vault manager: https://solana.fm/tx/${tx}${
|
|
193
|
+
driftClient.env === 'devnet' ? '?cluster=devnet-solana' : ''
|
|
194
|
+
}`
|
|
195
|
+
);
|
|
196
|
+
done = true;
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
} catch (e) {
|
|
200
|
+
const err = e as Error;
|
|
201
|
+
if (err.message.includes('TransactionExpiredTimeoutError')) {
|
|
202
|
+
console.log(err.message);
|
|
203
|
+
console.log('Transaction timeout. Retrying...');
|
|
204
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
205
|
+
} else {
|
|
206
|
+
throw err;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|