@drift-labs/sdk 2.49.0-beta.9 → 2.52.0-beta.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/VERSION +1 -1
- package/lib/accounts/{mockUserAccountSubscriber.d.ts → basicUserAccountSubscriber.d.ts} +6 -2
- package/lib/accounts/{mockUserAccountSubscriber.js → basicUserAccountSubscriber.js} +13 -6
- package/lib/accounts/bulkAccountLoader.js +7 -1
- package/lib/accounts/oneShotUserAccountSubscriber.d.ts +17 -0
- package/lib/accounts/oneShotUserAccountSubscriber.js +48 -0
- package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +1 -0
- package/lib/adminClient.d.ts +2 -0
- package/lib/adminClient.js +17 -0
- package/lib/constants/numericConstants.d.ts +3 -0
- package/lib/constants/numericConstants.js +4 -1
- package/lib/constants/perpMarkets.js +40 -0
- package/lib/constants/spotMarkets.js +10 -0
- package/lib/decode/user.d.ts +3 -0
- package/lib/decode/user.js +329 -0
- package/lib/driftClient.d.ts +6 -1
- package/lib/driftClient.js +35 -10
- package/lib/examples/loadDlob.js +10 -5
- package/lib/idl/drift.json +32 -2
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/math/state.d.ts +5 -0
- package/lib/math/state.js +27 -0
- package/lib/math/superStake.d.ts +43 -0
- package/lib/math/superStake.js +64 -22
- package/lib/orderSubscriber/OrderSubscriber.d.ts +3 -0
- package/lib/orderSubscriber/OrderSubscriber.js +17 -3
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +1 -1
- package/lib/orderSubscriber/WebsocketSubscription.js +8 -6
- package/lib/orderSubscriber/types.d.ts +4 -1
- package/lib/types.d.ts +2 -1
- package/lib/user.d.ts +2 -1
- package/lib/user.js +13 -5
- package/lib/userMap/PollingSubscription.d.ts +15 -0
- package/lib/userMap/PollingSubscription.js +28 -0
- package/lib/userMap/WebsocketSubscription.d.ts +23 -0
- package/lib/userMap/WebsocketSubscription.js +41 -0
- package/lib/userMap/userMap.d.ts +16 -18
- package/lib/userMap/userMap.js +73 -34
- package/lib/userMap/userMapConfig.d.ts +21 -0
- package/lib/userMap/userMapConfig.js +2 -0
- package/lib/userStats.d.ts +1 -0
- package/lib/userStats.js +3 -0
- package/package.json +2 -1
- package/src/accounts/{mockUserAccountSubscriber.ts → basicUserAccountSubscriber.ts} +12 -6
- package/src/accounts/bulkAccountLoader.ts +10 -3
- package/src/accounts/oneShotUserAccountSubscriber.ts +64 -0
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +1 -0
- package/src/adminClient.ts +27 -0
- package/src/constants/numericConstants.ts +4 -0
- package/src/constants/perpMarkets.ts +40 -0
- package/src/constants/spotMarkets.ts +10 -0
- package/src/decode/user.ts +358 -0
- package/src/driftClient.ts +62 -15
- package/src/examples/loadDlob.ts +11 -6
- package/src/idl/drift.json +33 -3
- package/src/index.ts +3 -1
- package/src/math/state.ts +26 -0
- package/src/math/superStake.ts +108 -20
- package/src/orderSubscriber/OrderSubscriber.ts +33 -7
- package/src/orderSubscriber/WebsocketSubscription.ts +17 -16
- package/src/orderSubscriber/types.ts +15 -2
- package/src/types.ts +2 -1
- package/src/user.ts +19 -6
- package/src/userMap/PollingSubscription.ts +48 -0
- package/src/userMap/WebsocketSubscription.ts +76 -0
- package/src/userMap/userMap.ts +105 -70
- package/src/userMap/userMapConfig.ts +34 -0
- package/src/userStats.ts +8 -0
- package/tests/amm/test.ts +6 -3
- package/tests/decode/test.ts +266 -0
- package/tests/decode/userAccountBufferStrings.ts +102 -0
- package/tests/dlob/helpers.ts +1 -0
- package/tests/dlob/test.ts +10 -8
- package/tests/user/helpers.ts +0 -1
package/lib/driftClient.js
CHANGED
|
@@ -665,9 +665,7 @@ class DriftClient {
|
|
|
665
665
|
]);
|
|
666
666
|
return programAccounts.map((programAccount) => programAccount.account);
|
|
667
667
|
}
|
|
668
|
-
async
|
|
669
|
-
var _a;
|
|
670
|
-
const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
|
|
668
|
+
async getUserDeletionIx(userAccountPublicKey) {
|
|
671
669
|
const ix = await this.program.instruction.deleteUser({
|
|
672
670
|
accounts: {
|
|
673
671
|
user: userAccountPublicKey,
|
|
@@ -676,6 +674,12 @@ class DriftClient {
|
|
|
676
674
|
state: await this.getStatePublicKey(),
|
|
677
675
|
},
|
|
678
676
|
});
|
|
677
|
+
return ix;
|
|
678
|
+
}
|
|
679
|
+
async deleteUser(subAccountId = 0, txParams) {
|
|
680
|
+
var _a;
|
|
681
|
+
const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
|
|
682
|
+
const ix = await this.getUserDeletionIx(userAccountPublicKey);
|
|
679
683
|
const { txSig } = await this.sendTransaction(await this.buildTransaction(ix, txParams), [], this.opts);
|
|
680
684
|
const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
|
|
681
685
|
await ((_a = this.users.get(userMapKey)) === null || _a === void 0 ? void 0 : _a.unsubscribe());
|
|
@@ -1061,9 +1065,12 @@ class DriftClient {
|
|
|
1061
1065
|
* @param subAccountId
|
|
1062
1066
|
* @param name
|
|
1063
1067
|
* @param fromSubAccountId
|
|
1068
|
+
* @param referrerInfo
|
|
1069
|
+
* @param donateAmount
|
|
1070
|
+
* @param txParams
|
|
1064
1071
|
* @returns
|
|
1065
1072
|
*/
|
|
1066
|
-
async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, marketIndex = 0, subAccountId = 0, name, fromSubAccountId, referrerInfo, txParams) {
|
|
1073
|
+
async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, marketIndex = 0, subAccountId = 0, name, fromSubAccountId, referrerInfo, donateAmount, txParams) {
|
|
1067
1074
|
var _a;
|
|
1068
1075
|
const ixs = [];
|
|
1069
1076
|
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(subAccountId, name, referrerInfo);
|
|
@@ -1083,10 +1090,19 @@ class DriftClient {
|
|
|
1083
1090
|
const isFromSubaccount = fromSubAccountId !== null &&
|
|
1084
1091
|
fromSubAccountId !== undefined &&
|
|
1085
1092
|
!isNaN(fromSubAccountId);
|
|
1086
|
-
|
|
1093
|
+
donateAmount = donateAmount ? donateAmount : numericConstants_1.ZERO;
|
|
1094
|
+
const createWSOLTokenAccount = (isSolMarket &&
|
|
1095
|
+
userTokenAccount.equals(authority) &&
|
|
1096
|
+
!isFromSubaccount) ||
|
|
1097
|
+
!donateAmount.eq(numericConstants_1.ZERO);
|
|
1098
|
+
const wSolAmount = isSolMarket ? amount.add(donateAmount) : donateAmount;
|
|
1099
|
+
let wsolTokenAccount;
|
|
1087
1100
|
if (createWSOLTokenAccount) {
|
|
1088
|
-
const { ixs: startIxs, pubkey } = await this.getWrappedSolAccountCreationIxs(
|
|
1089
|
-
|
|
1101
|
+
const { ixs: startIxs, pubkey } = await this.getWrappedSolAccountCreationIxs(wSolAmount, true);
|
|
1102
|
+
wsolTokenAccount = pubkey;
|
|
1103
|
+
if (isSolMarket) {
|
|
1104
|
+
userTokenAccount = pubkey;
|
|
1105
|
+
}
|
|
1090
1106
|
ixs.push(...startIxs);
|
|
1091
1107
|
}
|
|
1092
1108
|
const depositCollateralIx = isFromSubaccount
|
|
@@ -1098,9 +1114,13 @@ class DriftClient {
|
|
|
1098
1114
|
}
|
|
1099
1115
|
}
|
|
1100
1116
|
ixs.push(initializeUserAccountIx, depositCollateralIx);
|
|
1117
|
+
if (!donateAmount.eq(numericConstants_1.ZERO)) {
|
|
1118
|
+
const donateIx = await this.getDepositIntoSpotMarketRevenuePoolIx(1, donateAmount, wsolTokenAccount);
|
|
1119
|
+
ixs.push(donateIx);
|
|
1120
|
+
}
|
|
1101
1121
|
// Close the wrapped sol account at the end of the transaction
|
|
1102
1122
|
if (createWSOLTokenAccount) {
|
|
1103
|
-
ixs.push((0, spl_token_1.createCloseAccountInstruction)(
|
|
1123
|
+
ixs.push((0, spl_token_1.createCloseAccountInstruction)(wsolTokenAccount, authority, authority, []));
|
|
1104
1124
|
}
|
|
1105
1125
|
const tx = await this.buildTransaction(ixs, params);
|
|
1106
1126
|
const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
|
|
@@ -3237,9 +3257,9 @@ class DriftClient {
|
|
|
3237
3257
|
remainingAccounts: remainingAccounts,
|
|
3238
3258
|
});
|
|
3239
3259
|
}
|
|
3240
|
-
async
|
|
3260
|
+
async getDepositIntoSpotMarketRevenuePoolIx(marketIndex, amount, userTokenAccountPublicKey) {
|
|
3241
3261
|
const spotMarket = await this.getSpotMarketAccount(marketIndex);
|
|
3242
|
-
const
|
|
3262
|
+
const ix = await this.program.instruction.depositIntoSpotMarketRevenuePool(amount, {
|
|
3243
3263
|
accounts: {
|
|
3244
3264
|
state: await this.getStatePublicKey(),
|
|
3245
3265
|
spotMarket: spotMarket.pubkey,
|
|
@@ -3249,6 +3269,11 @@ class DriftClient {
|
|
|
3249
3269
|
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
3250
3270
|
},
|
|
3251
3271
|
});
|
|
3272
|
+
return ix;
|
|
3273
|
+
}
|
|
3274
|
+
async depositIntoSpotMarketRevenuePool(marketIndex, amount, userTokenAccountPublicKey) {
|
|
3275
|
+
const ix = await this.getDepositIntoSpotMarketRevenuePoolIx(marketIndex, amount, userTokenAccountPublicKey);
|
|
3276
|
+
const tx = await this.buildTransaction([ix]);
|
|
3252
3277
|
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
3253
3278
|
return txSig;
|
|
3254
3279
|
}
|
package/lib/examples/loadDlob.js
CHANGED
|
@@ -35,15 +35,20 @@ const main = async () => {
|
|
|
35
35
|
console.log('Subscribing drift client...');
|
|
36
36
|
await driftClient.subscribe();
|
|
37
37
|
console.log('Loading user map...');
|
|
38
|
-
const userMap = new __1.UserMap(
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
const userMap = new __1.UserMap({
|
|
39
|
+
driftClient,
|
|
40
|
+
subscriptionConfig: {
|
|
41
|
+
type: 'websocket',
|
|
42
|
+
commitment: 'processed',
|
|
43
|
+
},
|
|
44
|
+
skipInitialLoad: false,
|
|
45
|
+
includeIdle: false,
|
|
41
46
|
});
|
|
42
47
|
// fetches all users and subscribes for updates
|
|
43
48
|
await userMap.subscribe();
|
|
44
49
|
console.log('Loading dlob from user map...');
|
|
45
|
-
const
|
|
46
|
-
await
|
|
50
|
+
const slot = await driftClient.connection.getSlot();
|
|
51
|
+
const dlob = await userMap.getDLOB(slot);
|
|
47
52
|
console.log('number of orders', dlob.getDLOBOrders().length);
|
|
48
53
|
dlob.clear();
|
|
49
54
|
console.log('Unsubscribing users...');
|
package/lib/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.51.0",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -4184,6 +4184,27 @@
|
|
|
4184
4184
|
}
|
|
4185
4185
|
]
|
|
4186
4186
|
},
|
|
4187
|
+
{
|
|
4188
|
+
"name": "updateStateMaxInitializeUserFee",
|
|
4189
|
+
"accounts": [
|
|
4190
|
+
{
|
|
4191
|
+
"name": "admin",
|
|
4192
|
+
"isMut": false,
|
|
4193
|
+
"isSigner": true
|
|
4194
|
+
},
|
|
4195
|
+
{
|
|
4196
|
+
"name": "state",
|
|
4197
|
+
"isMut": true,
|
|
4198
|
+
"isSigner": false
|
|
4199
|
+
}
|
|
4200
|
+
],
|
|
4201
|
+
"args": [
|
|
4202
|
+
{
|
|
4203
|
+
"name": "maxInitializeUserFee",
|
|
4204
|
+
"type": "u16"
|
|
4205
|
+
}
|
|
4206
|
+
]
|
|
4207
|
+
},
|
|
4187
4208
|
{
|
|
4188
4209
|
"name": "updatePerpMarketOracle",
|
|
4189
4210
|
"accounts": [
|
|
@@ -5747,12 +5768,16 @@
|
|
|
5747
5768
|
"name": "maxNumberOfSubAccounts",
|
|
5748
5769
|
"type": "u16"
|
|
5749
5770
|
},
|
|
5771
|
+
{
|
|
5772
|
+
"name": "maxInitializeUserFee",
|
|
5773
|
+
"type": "u16"
|
|
5774
|
+
},
|
|
5750
5775
|
{
|
|
5751
5776
|
"name": "padding",
|
|
5752
5777
|
"type": {
|
|
5753
5778
|
"array": [
|
|
5754
5779
|
"u8",
|
|
5755
|
-
|
|
5780
|
+
10
|
|
5756
5781
|
]
|
|
5757
5782
|
}
|
|
5758
5783
|
}
|
|
@@ -11094,6 +11119,11 @@
|
|
|
11094
11119
|
"code": 6255,
|
|
11095
11120
|
"name": "InvalidMarginCalculation",
|
|
11096
11121
|
"msg": "InvalidMarginCalculation"
|
|
11122
|
+
},
|
|
11123
|
+
{
|
|
11124
|
+
"code": 6256,
|
|
11125
|
+
"name": "CantPayUserInitFee",
|
|
11126
|
+
"msg": "CantPayUserInitFee"
|
|
11097
11127
|
}
|
|
11098
11128
|
]
|
|
11099
11129
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -19,7 +19,8 @@ export * from './accounts/pollingTokenAccountSubscriber';
|
|
|
19
19
|
export * from './accounts/pollingUserAccountSubscriber';
|
|
20
20
|
export * from './accounts/pollingUserStatsAccountSubscriber';
|
|
21
21
|
export * from './accounts/pollingInsuranceFundStakeAccountSubscriber';
|
|
22
|
-
export * from './accounts/
|
|
22
|
+
export * from './accounts/basicUserAccountSubscriber';
|
|
23
|
+
export * from './accounts/oneShotUserAccountSubscriber';
|
|
23
24
|
export * from './accounts/types';
|
|
24
25
|
export * from './addresses/pda';
|
|
25
26
|
export * from './adminClient';
|
|
@@ -55,6 +56,7 @@ export * from './math/margin';
|
|
|
55
56
|
export * from './math/insurance';
|
|
56
57
|
export * from './math/superStake';
|
|
57
58
|
export * from './math/spotPosition';
|
|
59
|
+
export * from './math/state';
|
|
58
60
|
export * from './marinade';
|
|
59
61
|
export * from './orderParams';
|
|
60
62
|
export * from './slot/SlotSubscriber';
|
package/lib/index.js
CHANGED
|
@@ -42,7 +42,8 @@ __exportStar(require("./accounts/pollingTokenAccountSubscriber"), exports);
|
|
|
42
42
|
__exportStar(require("./accounts/pollingUserAccountSubscriber"), exports);
|
|
43
43
|
__exportStar(require("./accounts/pollingUserStatsAccountSubscriber"), exports);
|
|
44
44
|
__exportStar(require("./accounts/pollingInsuranceFundStakeAccountSubscriber"), exports);
|
|
45
|
-
__exportStar(require("./accounts/
|
|
45
|
+
__exportStar(require("./accounts/basicUserAccountSubscriber"), exports);
|
|
46
|
+
__exportStar(require("./accounts/oneShotUserAccountSubscriber"), exports);
|
|
46
47
|
__exportStar(require("./accounts/types"), exports);
|
|
47
48
|
__exportStar(require("./addresses/pda"), exports);
|
|
48
49
|
__exportStar(require("./adminClient"), exports);
|
|
@@ -78,6 +79,7 @@ __exportStar(require("./math/margin"), exports);
|
|
|
78
79
|
__exportStar(require("./math/insurance"), exports);
|
|
79
80
|
__exportStar(require("./math/superStake"), exports);
|
|
80
81
|
__exportStar(require("./math/spotPosition"), exports);
|
|
82
|
+
__exportStar(require("./math/state"), exports);
|
|
81
83
|
__exportStar(require("./marinade"), exports);
|
|
82
84
|
__exportStar(require("./orderParams"), exports);
|
|
83
85
|
__exportStar(require("./slot/SlotSubscriber"), exports);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMaxNumberOfSubAccounts = exports.calculateInitUserFee = void 0;
|
|
4
|
+
const __1 = require("../");
|
|
5
|
+
function calculateInitUserFee(stateAccount) {
|
|
6
|
+
const maxInitFee = new __1.BN(stateAccount.maxInitializeUserFee)
|
|
7
|
+
.mul(__1.LAMPORTS_PRECISION)
|
|
8
|
+
.divn(100);
|
|
9
|
+
const targetUtilization = __1.PERCENTAGE_PRECISION.muln(8).divn(10);
|
|
10
|
+
const accountSpaceUtilization = stateAccount.numberOfSubAccounts
|
|
11
|
+
.addn(1)
|
|
12
|
+
.mul(__1.PERCENTAGE_PRECISION)
|
|
13
|
+
.div(getMaxNumberOfSubAccounts(stateAccount));
|
|
14
|
+
if (accountSpaceUtilization.gt(targetUtilization)) {
|
|
15
|
+
return maxInitFee
|
|
16
|
+
.mul(accountSpaceUtilization.sub(targetUtilization))
|
|
17
|
+
.div(__1.PERCENTAGE_PRECISION.sub(targetUtilization));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return __1.ZERO;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.calculateInitUserFee = calculateInitUserFee;
|
|
24
|
+
function getMaxNumberOfSubAccounts(stateAccount) {
|
|
25
|
+
return new __1.BN(stateAccount.maxNumberOfSubAccounts).muln(100);
|
|
26
|
+
}
|
|
27
|
+
exports.getMaxNumberOfSubAccounts = getMaxNumberOfSubAccounts;
|
package/lib/math/superStake.d.ts
CHANGED
|
@@ -5,6 +5,30 @@ import { DriftClient } from '../driftClient';
|
|
|
5
5
|
import { BN } from '@coral-xyz/anchor';
|
|
6
6
|
import { User } from '../user';
|
|
7
7
|
import { DepositRecord } from '../types';
|
|
8
|
+
export type BSOL_STATS_API_RESPONSE = {
|
|
9
|
+
success: boolean;
|
|
10
|
+
stats?: {
|
|
11
|
+
conversion: {
|
|
12
|
+
bsol_to_sol: number;
|
|
13
|
+
sol_to_bsol: number;
|
|
14
|
+
};
|
|
15
|
+
apy: {
|
|
16
|
+
base: number;
|
|
17
|
+
blze: number;
|
|
18
|
+
total: number;
|
|
19
|
+
lending: number;
|
|
20
|
+
liquidity: number;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export type BSOL_EMISSIONS_API_RESPONSE = {
|
|
25
|
+
success: boolean;
|
|
26
|
+
emissions?: {
|
|
27
|
+
lend: number;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare function fetchBSolMetrics(): Promise<any>;
|
|
31
|
+
export declare function fetchBSolDriftEmissions(): Promise<any>;
|
|
8
32
|
export declare function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, driftClient, userAccountPublicKey, price, forceMarinade, onlyDirectRoutes, }: {
|
|
9
33
|
marketIndex: number;
|
|
10
34
|
amount: BN;
|
|
@@ -46,6 +70,25 @@ export declare function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, dr
|
|
|
46
70
|
method: 'jupiter' | 'marinade';
|
|
47
71
|
price: number;
|
|
48
72
|
}>;
|
|
73
|
+
/**
|
|
74
|
+
* Finds best Jupiter Swap instructions for a generic lstMint
|
|
75
|
+
*
|
|
76
|
+
* Without doing any extra steps like checking if you can get a better rate by staking directly with that LST platform
|
|
77
|
+
*/
|
|
78
|
+
export declare function findBestLstSuperStakeIxs({ amount, lstMint, jupiterClient, driftClient, userAccountPublicKey, onlyDirectRoutes, lstMarketIndex, }: {
|
|
79
|
+
amount: BN;
|
|
80
|
+
lstMint: PublicKey;
|
|
81
|
+
lstMarketIndex: number;
|
|
82
|
+
jupiterClient: JupiterClient;
|
|
83
|
+
driftClient: DriftClient;
|
|
84
|
+
userAccountPublicKey?: PublicKey;
|
|
85
|
+
onlyDirectRoutes?: boolean;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
ixs: TransactionInstruction[];
|
|
88
|
+
lookupTables: AddressLookupTableAccount[];
|
|
89
|
+
method: 'jupiter' | 'marinade';
|
|
90
|
+
price: number;
|
|
91
|
+
}>;
|
|
49
92
|
export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
|
|
50
93
|
data: {
|
|
51
94
|
getStakePoolStats: {
|
package/lib/math/superStake.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.calculateEstimatedSuperStakeLiquidationPrice = exports.calculateSolEarned = exports.fetchJitoSolMetrics = exports.findBestJitoSolSuperStakeIxs = exports.findBestMSolSuperStakeIxs = exports.findBestSuperStakeIxs = void 0;
|
|
6
|
+
exports.calculateEstimatedSuperStakeLiquidationPrice = exports.calculateSolEarned = exports.fetchJitoSolMetrics = exports.findBestLstSuperStakeIxs = exports.findBestJitoSolSuperStakeIxs = exports.findBestMSolSuperStakeIxs = exports.findBestSuperStakeIxs = exports.fetchBSolDriftEmissions = exports.fetchBSolMetrics = void 0;
|
|
7
7
|
const web3_js_1 = require("@solana/web3.js");
|
|
8
8
|
const marinade_1 = require("../marinade");
|
|
9
9
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
@@ -11,6 +11,14 @@ const types_1 = require("../types");
|
|
|
11
11
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
12
12
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
13
13
|
const utils_1 = require("./utils");
|
|
14
|
+
async function fetchBSolMetrics() {
|
|
15
|
+
return await (0, node_fetch_1.default)('https://stake.solblaze.org/api/v1/stats');
|
|
16
|
+
}
|
|
17
|
+
exports.fetchBSolMetrics = fetchBSolMetrics;
|
|
18
|
+
async function fetchBSolDriftEmissions() {
|
|
19
|
+
return await (0, node_fetch_1.default)('https://stake.solblaze.org/api/v1/drift_emissions');
|
|
20
|
+
}
|
|
21
|
+
exports.fetchBSolDriftEmissions = fetchBSolDriftEmissions;
|
|
14
22
|
async function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, driftClient, userAccountPublicKey, price, forceMarinade, onlyDirectRoutes, }) {
|
|
15
23
|
if (marketIndex === 2) {
|
|
16
24
|
return findBestMSolSuperStakeIxs({
|
|
@@ -32,6 +40,17 @@ async function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, drift
|
|
|
32
40
|
onlyDirectRoutes,
|
|
33
41
|
});
|
|
34
42
|
}
|
|
43
|
+
else if (marketIndex === 8) {
|
|
44
|
+
return findBestLstSuperStakeIxs({
|
|
45
|
+
amount,
|
|
46
|
+
lstMint: driftClient.getSpotMarketAccount(8).mint,
|
|
47
|
+
lstMarketIndex: 8,
|
|
48
|
+
jupiterClient,
|
|
49
|
+
driftClient,
|
|
50
|
+
userAccountPublicKey,
|
|
51
|
+
onlyDirectRoutes,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
35
54
|
else {
|
|
36
55
|
throw new Error(`Unsupported superstake market index: ${marketIndex}`);
|
|
37
56
|
}
|
|
@@ -90,14 +109,30 @@ async function findBestMSolSuperStakeIxs({ amount, jupiterClient, driftClient, u
|
|
|
90
109
|
}
|
|
91
110
|
exports.findBestMSolSuperStakeIxs = findBestMSolSuperStakeIxs;
|
|
92
111
|
async function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, driftClient, userAccountPublicKey, onlyDirectRoutes, }) {
|
|
112
|
+
return await findBestLstSuperStakeIxs({
|
|
113
|
+
amount,
|
|
114
|
+
jupiterClient,
|
|
115
|
+
driftClient,
|
|
116
|
+
userAccountPublicKey,
|
|
117
|
+
onlyDirectRoutes,
|
|
118
|
+
lstMint: driftClient.getSpotMarketAccount(6).mint,
|
|
119
|
+
lstMarketIndex: 6,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
exports.findBestJitoSolSuperStakeIxs = findBestJitoSolSuperStakeIxs;
|
|
123
|
+
/**
|
|
124
|
+
* Finds best Jupiter Swap instructions for a generic lstMint
|
|
125
|
+
*
|
|
126
|
+
* Without doing any extra steps like checking if you can get a better rate by staking directly with that LST platform
|
|
127
|
+
*/
|
|
128
|
+
async function findBestLstSuperStakeIxs({ amount, lstMint, jupiterClient, driftClient, userAccountPublicKey, onlyDirectRoutes, lstMarketIndex, }) {
|
|
93
129
|
const solMint = driftClient.getSpotMarketAccount(1).mint;
|
|
94
|
-
const JitoSolMint = driftClient.getSpotMarketAccount(6).mint;
|
|
95
130
|
let jupiterPrice;
|
|
96
131
|
let bestRoute;
|
|
97
132
|
try {
|
|
98
133
|
const jupiterRoutes = await jupiterClient.getRoutes({
|
|
99
134
|
inputMint: solMint,
|
|
100
|
-
outputMint:
|
|
135
|
+
outputMint: lstMint,
|
|
101
136
|
amount,
|
|
102
137
|
onlyDirectRoutes,
|
|
103
138
|
});
|
|
@@ -110,7 +145,7 @@ async function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, driftClient
|
|
|
110
145
|
}
|
|
111
146
|
const { ixs, lookupTables } = await driftClient.getJupiterSwapIx({
|
|
112
147
|
inMarketIndex: 1,
|
|
113
|
-
outMarketIndex:
|
|
148
|
+
outMarketIndex: lstMarketIndex,
|
|
114
149
|
route: bestRoute,
|
|
115
150
|
jupiterClient,
|
|
116
151
|
amount,
|
|
@@ -123,7 +158,7 @@ async function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, driftClient
|
|
|
123
158
|
price: jupiterPrice,
|
|
124
159
|
};
|
|
125
160
|
}
|
|
126
|
-
exports.
|
|
161
|
+
exports.findBestLstSuperStakeIxs = findBestLstSuperStakeIxs;
|
|
127
162
|
const JITO_SOL_START_DATE = '2022-10-31T00:00:00Z';
|
|
128
163
|
async function fetchJitoSolMetrics() {
|
|
129
164
|
const res = await (0, node_fetch_1.default)('https://kobe.mainnet.jito.network/', {
|
|
@@ -213,12 +248,30 @@ async function calculateSolEarned({ marketIndex, user, depositRecords, }) {
|
|
|
213
248
|
lstRatios.set(timestamp, data);
|
|
214
249
|
}
|
|
215
250
|
};
|
|
251
|
+
const getBSolPrice = async (timestamps) => {
|
|
252
|
+
var _a, _b;
|
|
253
|
+
// Currently there's only one bSOL price, no timestamped data
|
|
254
|
+
// So just use the same price for every timestamp for now
|
|
255
|
+
const response = await fetchBSolMetrics();
|
|
256
|
+
if (response.status === 200) {
|
|
257
|
+
const data = (await response.json());
|
|
258
|
+
const bSolRatio = (_b = (_a = data === null || data === void 0 ? void 0 : data.stats) === null || _a === void 0 ? void 0 : _a.conversion) === null || _b === void 0 ? void 0 : _b.bsol_to_sol;
|
|
259
|
+
if (bSolRatio) {
|
|
260
|
+
timestamps.forEach((timestamp) => lstRatios.set(timestamp, bSolRatio));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
// This block kind of assumes the record are all from the same market
|
|
265
|
+
// Otherwise the following code that checks the record.marketIndex would break
|
|
216
266
|
if (marketIndex === 2) {
|
|
217
267
|
await Promise.all(timestamps.map(getMsolPrice));
|
|
218
268
|
}
|
|
219
269
|
else if (marketIndex === 6) {
|
|
220
270
|
lstRatios = await getJitoSolHistoricalPriceMap(timestamps);
|
|
221
271
|
}
|
|
272
|
+
else if (marketIndex === 8) {
|
|
273
|
+
await getBSolPrice(timestamps);
|
|
274
|
+
}
|
|
222
275
|
let solEarned = numericConstants_1.ZERO;
|
|
223
276
|
for (const record of depositRecords) {
|
|
224
277
|
if (record.marketIndex === 1) {
|
|
@@ -229,23 +282,12 @@ async function calculateSolEarned({ marketIndex, user, depositRecords, }) {
|
|
|
229
282
|
solEarned = solEarned.add(record.amount);
|
|
230
283
|
}
|
|
231
284
|
}
|
|
232
|
-
else if (record.marketIndex === 2
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
solEarned = solEarned.add(solAmount);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
else if (record.marketIndex === 6) {
|
|
244
|
-
const jitoSolRatio = lstRatios.get(record.ts.toNumber());
|
|
245
|
-
const jitoSolRatioBN = new anchor_1.BN(jitoSolRatio * web3_js_1.LAMPORTS_PER_SOL);
|
|
246
|
-
const solAmount = record.amount
|
|
247
|
-
.mul(jitoSolRatioBN)
|
|
248
|
-
.div(numericConstants_1.LAMPORTS_PRECISION);
|
|
285
|
+
else if (record.marketIndex === 2 ||
|
|
286
|
+
record.marketIndex === 6 ||
|
|
287
|
+
record.marketIndex === 8) {
|
|
288
|
+
const lstRatio = lstRatios.get(record.ts.toNumber());
|
|
289
|
+
const lstRatioBN = new anchor_1.BN(lstRatio * web3_js_1.LAMPORTS_PER_SOL);
|
|
290
|
+
const solAmount = record.amount.mul(lstRatioBN).div(numericConstants_1.LAMPORTS_PRECISION);
|
|
249
291
|
if ((0, types_1.isVariant)(record.direction, 'deposit')) {
|
|
250
292
|
solEarned = solEarned.sub(solAmount);
|
|
251
293
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
2
3
|
import { DriftClient } from '../driftClient';
|
|
3
4
|
import { UserAccount } from '../types';
|
|
4
5
|
import { Commitment } from '@solana/web3.js';
|
|
6
|
+
import { Buffer } from 'buffer';
|
|
5
7
|
import { DLOB } from '../dlob/DLOB';
|
|
6
8
|
import { OrderSubscriberConfig, OrderSubscriberEvents } from './types';
|
|
7
9
|
import { PollingSubscription } from './PollingSubscription';
|
|
@@ -20,6 +22,7 @@ export declare class OrderSubscriber {
|
|
|
20
22
|
fetchPromise?: Promise<void>;
|
|
21
23
|
fetchPromiseResolver: () => void;
|
|
22
24
|
mostRecentSlot: number;
|
|
25
|
+
decodeFn: (name: string, data: Buffer) => UserAccount;
|
|
23
26
|
constructor(config: OrderSubscriberConfig);
|
|
24
27
|
subscribe(): Promise<void>;
|
|
25
28
|
fetch(): Promise<void>;
|
|
@@ -9,8 +9,10 @@ const PollingSubscription_1 = require("./PollingSubscription");
|
|
|
9
9
|
const WebsocketSubscription_1 = require("./WebsocketSubscription");
|
|
10
10
|
const events_1 = require("events");
|
|
11
11
|
const index_1 = require("../index");
|
|
12
|
+
const user_1 = require("../decode/user");
|
|
12
13
|
class OrderSubscriber {
|
|
13
14
|
constructor(config) {
|
|
15
|
+
var _a;
|
|
14
16
|
this.usersAccounts = new Map();
|
|
15
17
|
this.driftClient = config.driftClient;
|
|
16
18
|
this.commitment = config.subscriptionConfig.commitment || 'processed';
|
|
@@ -28,6 +30,13 @@ class OrderSubscriber {
|
|
|
28
30
|
resubTimeoutMs: config.subscriptionConfig.resubTimeoutMs,
|
|
29
31
|
});
|
|
30
32
|
}
|
|
33
|
+
if ((_a = config.fastDecode) !== null && _a !== void 0 ? _a : true) {
|
|
34
|
+
this.decodeFn = (name, data) => (0, user_1.decodeUser)(data);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.decodeFn =
|
|
38
|
+
this.driftClient.program.account.user.coder.accounts.decodeUnchecked.bind(this.driftClient.program.account.user.coder.accounts);
|
|
39
|
+
}
|
|
31
40
|
this.eventEmitter = new events_1.EventEmitter();
|
|
32
41
|
}
|
|
33
42
|
async subscribe() {
|
|
@@ -60,11 +69,15 @@ class OrderSubscriber {
|
|
|
60
69
|
const key = programAccount.pubkey.toString();
|
|
61
70
|
programAccountSet.add(key);
|
|
62
71
|
this.tryUpdateUserAccount(key, 'raw', programAccount.account.data, slot);
|
|
72
|
+
// give event loop a chance to breathe
|
|
73
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
63
74
|
}
|
|
64
75
|
for (const key of this.usersAccounts.keys()) {
|
|
65
76
|
if (!programAccountSet.has(key)) {
|
|
66
77
|
this.usersAccounts.delete(key);
|
|
67
78
|
}
|
|
79
|
+
// give event loop a chance to breathe
|
|
80
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
68
81
|
}
|
|
69
82
|
}
|
|
70
83
|
catch (e) {
|
|
@@ -79,6 +92,7 @@ class OrderSubscriber {
|
|
|
79
92
|
if (!this.mostRecentSlot || slot > this.mostRecentSlot) {
|
|
80
93
|
this.mostRecentSlot = slot;
|
|
81
94
|
}
|
|
95
|
+
this.eventEmitter.emit('updateReceived', new web3_js_1.PublicKey(key), slot, dataType);
|
|
82
96
|
const slotAndUserAccount = this.usersAccounts.get(key);
|
|
83
97
|
if (!slotAndUserAccount || slotAndUserAccount.slot <= slot) {
|
|
84
98
|
let userAccount;
|
|
@@ -91,19 +105,19 @@ class OrderSubscriber {
|
|
|
91
105
|
slotAndUserAccount.userAccount.lastActiveSlot.gt(newLastActiveSlot)) {
|
|
92
106
|
return;
|
|
93
107
|
}
|
|
94
|
-
userAccount =
|
|
95
|
-
this.driftClient.program.account.user.coder.accounts.decodeUnchecked('User', buffer);
|
|
108
|
+
userAccount = this.decodeFn('User', buffer);
|
|
96
109
|
}
|
|
97
110
|
else {
|
|
98
111
|
userAccount = data;
|
|
99
112
|
}
|
|
113
|
+
this.eventEmitter.emit('userUpdated', userAccount, new web3_js_1.PublicKey(key), slot, dataType);
|
|
100
114
|
const newOrders = userAccount.orders.filter((order) => {
|
|
101
115
|
var _a;
|
|
102
116
|
return order.slot.toNumber() > ((_a = slotAndUserAccount === null || slotAndUserAccount === void 0 ? void 0 : slotAndUserAccount.slot) !== null && _a !== void 0 ? _a : 0) &&
|
|
103
117
|
order.slot.toNumber() <= slot;
|
|
104
118
|
});
|
|
105
119
|
if (newOrders.length > 0) {
|
|
106
|
-
this.eventEmitter.emit('
|
|
120
|
+
this.eventEmitter.emit('orderCreated', userAccount, newOrders, new web3_js_1.PublicKey(key), slot, dataType);
|
|
107
121
|
}
|
|
108
122
|
if (userAccount.hasOpenOrder) {
|
|
109
123
|
this.usersAccounts.set(key, { slot, userAccount });
|
|
@@ -5,7 +5,7 @@ export declare class WebsocketSubscription {
|
|
|
5
5
|
private commitment;
|
|
6
6
|
private skipInitialLoad;
|
|
7
7
|
private resubTimeoutMs?;
|
|
8
|
-
private subscriber
|
|
8
|
+
private subscriber?;
|
|
9
9
|
constructor({ orderSubscriber, commitment, skipInitialLoad, resubTimeoutMs, }: {
|
|
10
10
|
orderSubscriber: OrderSubscriber;
|
|
11
11
|
commitment: Commitment;
|
|
@@ -11,12 +11,13 @@ class WebsocketSubscription {
|
|
|
11
11
|
this.resubTimeoutMs = resubTimeoutMs;
|
|
12
12
|
}
|
|
13
13
|
async subscribe() {
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
filters: [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getNonIdleUserFilter)()],
|
|
17
|
-
commitment: this.commitment,
|
|
18
|
-
}, this.resubTimeoutMs);
|
|
14
|
+
if (this.subscriber) {
|
|
15
|
+
return;
|
|
19
16
|
}
|
|
17
|
+
this.subscriber = new webSocketProgramAccountSubscriber_1.WebSocketProgramAccountSubscriber('OrderSubscriber', 'User', this.orderSubscriber.driftClient.program, this.orderSubscriber.decodeFn, {
|
|
18
|
+
filters: [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getNonIdleUserFilter)()],
|
|
19
|
+
commitment: this.commitment,
|
|
20
|
+
}, this.resubTimeoutMs);
|
|
20
21
|
await this.subscriber.subscribe((accountId, account, context) => {
|
|
21
22
|
const userKey = accountId.toBase58();
|
|
22
23
|
this.orderSubscriber.tryUpdateUserAccount(userKey, 'decoded', account, context.slot);
|
|
@@ -28,7 +29,8 @@ class WebsocketSubscription {
|
|
|
28
29
|
async unsubscribe() {
|
|
29
30
|
if (!this.subscriber)
|
|
30
31
|
return;
|
|
31
|
-
this.subscriber.unsubscribe();
|
|
32
|
+
await this.subscriber.unsubscribe();
|
|
33
|
+
this.subscriber = undefined;
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
exports.WebsocketSubscription = WebsocketSubscription;
|
|
@@ -13,7 +13,10 @@ export type OrderSubscriberConfig = {
|
|
|
13
13
|
resubTimeoutMs?: number;
|
|
14
14
|
commitment?: Commitment;
|
|
15
15
|
};
|
|
16
|
+
fastDecode?: boolean;
|
|
16
17
|
};
|
|
17
18
|
export interface OrderSubscriberEvents {
|
|
18
|
-
|
|
19
|
+
orderCreated: (account: UserAccount, updatedOrders: Order[], pubkey: PublicKey, slot: number, dataType: 'raw' | 'decoded') => void;
|
|
20
|
+
userUpdated: (account: UserAccount, pubkey: PublicKey, slot: number, dataType: 'raw' | 'decoded') => void;
|
|
21
|
+
updateReceived: (pubkey: PublicKey, slot: number, dataType: 'raw' | 'decoded') => void;
|
|
19
22
|
}
|
package/lib/types.d.ts
CHANGED
|
@@ -629,6 +629,7 @@ export type StateAccount = {
|
|
|
629
629
|
lpCooldownTime: BN;
|
|
630
630
|
initialPctToLiquidate: number;
|
|
631
631
|
liquidationDuration: number;
|
|
632
|
+
maxInitializeUserFee: number;
|
|
632
633
|
};
|
|
633
634
|
export type PerpMarketAccount = {
|
|
634
635
|
status: MarketStatus;
|
|
@@ -913,8 +914,8 @@ export type Order = {
|
|
|
913
914
|
marketIndex: number;
|
|
914
915
|
price: BN;
|
|
915
916
|
baseAssetAmount: BN;
|
|
916
|
-
baseAssetAmountFilled: BN;
|
|
917
917
|
quoteAssetAmount: BN;
|
|
918
|
+
baseAssetAmountFilled: BN;
|
|
918
919
|
quoteAssetAmountFilled: BN;
|
|
919
920
|
direction: PositionDirection;
|
|
920
921
|
reduceOnly: boolean;
|
package/lib/user.d.ts
CHANGED
|
@@ -95,7 +95,7 @@ export declare class User {
|
|
|
95
95
|
* @returns : the dust base asset amount (ie, < stepsize)
|
|
96
96
|
* @returns : pnl from settle
|
|
97
97
|
*/
|
|
98
|
-
getPerpPositionWithLPSettle(marketIndex: number, originalPosition?: PerpPosition, burnLpShares?: boolean): [PerpPosition, BN, BN];
|
|
98
|
+
getPerpPositionWithLPSettle(marketIndex: number, originalPosition?: PerpPosition, burnLpShares?: boolean, includeRemainderInBaseAmount?: boolean): [PerpPosition, BN, BN];
|
|
99
99
|
/**
|
|
100
100
|
* calculates Buying Power = free collateral / initial margin ratio
|
|
101
101
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -196,6 +196,7 @@ export declare class User {
|
|
|
196
196
|
};
|
|
197
197
|
getTotalLiabilityValue(marginCategory?: MarginCategory): BN;
|
|
198
198
|
getTotalAssetValue(marginCategory?: MarginCategory): BN;
|
|
199
|
+
getNetUsdValue(): BN;
|
|
199
200
|
/**
|
|
200
201
|
* Calculates the all time P&L of the user.
|
|
201
202
|
*
|