@drift-labs/sdk 2.40.0-beta.7 → 2.40.0-beta.9
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/types.d.ts +5 -1
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -1
- package/lib/accounts/webSocketAccountSubscriber.js +28 -2
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +2 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +6 -5
- package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +32 -0
- package/lib/accounts/webSocketProgramAccountSubscriber.js +99 -0
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts +2 -1
- package/lib/accounts/webSocketUserAccountSubscriber.js +3 -2
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +2 -1
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +3 -2
- package/lib/auctionSubscriber/auctionSubscriber.d.ts +3 -2
- package/lib/auctionSubscriber/auctionSubscriber.js +15 -7
- package/lib/auctionSubscriber/types.d.ts +1 -0
- package/lib/constants/spotMarkets.js +1 -1
- package/lib/driftClient.js +3 -3
- package/lib/driftClientConfig.d.ts +1 -0
- package/lib/math/superStake.d.ts +51 -4
- package/lib/math/superStake.js +173 -21
- package/lib/math/utils.d.ts +1 -0
- package/lib/math/utils.js +10 -1
- package/lib/orderSubscriber/OrderSubscriber.d.ts +1 -3
- package/lib/orderSubscriber/OrderSubscriber.js +4 -3
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -2
- package/lib/orderSubscriber/WebsocketSubscription.js +13 -12
- package/lib/orderSubscriber/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/accounts/types.ts +8 -1
- package/src/accounts/webSocketAccountSubscriber.ts +36 -2
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +15 -5
- package/src/accounts/webSocketProgramAccountSubscriber.ts +152 -0
- package/src/accounts/webSocketUserAccountSubscriber.ts +10 -2
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +10 -2
- package/src/auctionSubscriber/auctionSubscriber.ts +30 -21
- package/src/auctionSubscriber/types.ts +1 -0
- package/src/constants/spotMarkets.ts +1 -1
- package/src/driftClient.ts +2 -1
- package/src/driftClientConfig.ts +1 -0
- package/src/math/superStake.ts +248 -24
- package/src/math/utils.ts +12 -0
- package/src/orderSubscriber/OrderSubscriber.ts +12 -7
- package/src/orderSubscriber/WebsocketSubscription.ts +33 -23
- package/src/orderSubscriber/types.ts +1 -0
package/lib/math/superStake.js
CHANGED
|
@@ -3,17 +3,44 @@ 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.findBestSuperStakeIxs = void 0;
|
|
6
|
+
exports.calculateEstimatedSuperStakeLiquidationPrice = exports.calculateSolEarned = exports.fetchJitoSolMetrics = exports.findBestJitoSolSuperStakeIxs = exports.findBestMSolSuperStakeIxs = exports.findBestSuperStakeIxs = 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");
|
|
10
10
|
const types_1 = require("../types");
|
|
11
11
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
12
12
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
async function findBestSuperStakeIxs({ marketIndex, amount, jupiterClient, driftClient, userAccountPublicKey, price, forceMarinade, onlyDirectRoutes, }) {
|
|
15
|
+
if (marketIndex === 2) {
|
|
16
|
+
return findBestMSolSuperStakeIxs({
|
|
17
|
+
amount,
|
|
18
|
+
jupiterClient,
|
|
19
|
+
driftClient,
|
|
20
|
+
userAccountPublicKey,
|
|
21
|
+
price,
|
|
22
|
+
forceMarinade,
|
|
23
|
+
onlyDirectRoutes,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
else if (marketIndex === 6) {
|
|
27
|
+
return findBestJitoSolSuperStakeIxs({
|
|
28
|
+
amount,
|
|
29
|
+
jupiterClient,
|
|
30
|
+
driftClient,
|
|
31
|
+
userAccountPublicKey,
|
|
32
|
+
onlyDirectRoutes,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
throw new Error(`Unsupported superstake market index: ${marketIndex}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.findBestSuperStakeIxs = findBestSuperStakeIxs;
|
|
40
|
+
async function findBestMSolSuperStakeIxs({ amount, jupiterClient, driftClient, userAccountPublicKey, price, forceMarinade, onlyDirectRoutes, }) {
|
|
41
|
+
if (!price) {
|
|
15
42
|
const marinadeProgram = (0, marinade_1.getMarinadeFinanceProgram)(driftClient.provider);
|
|
16
|
-
|
|
43
|
+
price = await (0, marinade_1.getMarinadeMSolPrice)(marinadeProgram);
|
|
17
44
|
}
|
|
18
45
|
const solMint = driftClient.getSpotMarketAccount(1).mint;
|
|
19
46
|
const mSOLMint = driftClient.getSpotMarketAccount(2).mint;
|
|
@@ -32,7 +59,7 @@ async function findBestSuperStakeIxs({ amount, jupiterClient, driftClient, userA
|
|
|
32
59
|
catch (e) {
|
|
33
60
|
console.error('Error getting jupiter price', e);
|
|
34
61
|
}
|
|
35
|
-
if (!jupiterPrice ||
|
|
62
|
+
if (!jupiterPrice || price <= jupiterPrice || forceMarinade) {
|
|
36
63
|
const ixs = await driftClient.getStakeForMSOLIx({
|
|
37
64
|
amount,
|
|
38
65
|
userAccountPublicKey,
|
|
@@ -41,7 +68,7 @@ async function findBestSuperStakeIxs({ amount, jupiterClient, driftClient, userA
|
|
|
41
68
|
method: 'marinade',
|
|
42
69
|
ixs,
|
|
43
70
|
lookupTables: [],
|
|
44
|
-
price:
|
|
71
|
+
price: price,
|
|
45
72
|
};
|
|
46
73
|
}
|
|
47
74
|
else {
|
|
@@ -61,25 +88,137 @@ async function findBestSuperStakeIxs({ amount, jupiterClient, driftClient, userA
|
|
|
61
88
|
};
|
|
62
89
|
}
|
|
63
90
|
}
|
|
64
|
-
exports.
|
|
65
|
-
async function
|
|
91
|
+
exports.findBestMSolSuperStakeIxs = findBestMSolSuperStakeIxs;
|
|
92
|
+
async function findBestJitoSolSuperStakeIxs({ amount, jupiterClient, driftClient, userAccountPublicKey, onlyDirectRoutes, }) {
|
|
93
|
+
const solMint = driftClient.getSpotMarketAccount(1).mint;
|
|
94
|
+
const JitoSolMint = driftClient.getSpotMarketAccount(6).mint;
|
|
95
|
+
let jupiterPrice;
|
|
96
|
+
let bestRoute;
|
|
97
|
+
try {
|
|
98
|
+
const jupiterRoutes = await jupiterClient.getRoutes({
|
|
99
|
+
inputMint: solMint,
|
|
100
|
+
outputMint: JitoSolMint,
|
|
101
|
+
amount,
|
|
102
|
+
onlyDirectRoutes,
|
|
103
|
+
});
|
|
104
|
+
bestRoute = jupiterRoutes[0];
|
|
105
|
+
jupiterPrice = bestRoute.inAmount / bestRoute.outAmount;
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
console.error('Error getting jupiter price', e);
|
|
109
|
+
throw e;
|
|
110
|
+
}
|
|
111
|
+
const { ixs, lookupTables } = await driftClient.getJupiterSwapIx({
|
|
112
|
+
inMarketIndex: 1,
|
|
113
|
+
outMarketIndex: 6,
|
|
114
|
+
route: bestRoute,
|
|
115
|
+
jupiterClient,
|
|
116
|
+
amount,
|
|
117
|
+
userAccountPublicKey,
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
method: 'jupiter',
|
|
121
|
+
ixs,
|
|
122
|
+
lookupTables,
|
|
123
|
+
price: jupiterPrice,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
exports.findBestJitoSolSuperStakeIxs = findBestJitoSolSuperStakeIxs;
|
|
127
|
+
const JITO_SOL_START_DATE = '2022-10-31T00:00:00Z';
|
|
128
|
+
async function fetchJitoSolMetrics() {
|
|
129
|
+
const res = await (0, node_fetch_1.default)('https://kobe.mainnet.jito.network/', {
|
|
130
|
+
body: JSON.stringify({
|
|
131
|
+
operationName: 'QueryRoot',
|
|
132
|
+
variables: {
|
|
133
|
+
request: {
|
|
134
|
+
bucketType: 'DAILY',
|
|
135
|
+
rangeFilter: {
|
|
136
|
+
start: JITO_SOL_START_DATE,
|
|
137
|
+
end: new Date().toISOString(),
|
|
138
|
+
},
|
|
139
|
+
sortBy: {
|
|
140
|
+
order: 'ASC',
|
|
141
|
+
field: 'BLOCK_TIME',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
query: `
|
|
146
|
+
query QueryRoot($request: GetStakePoolStatsRequest!) {
|
|
147
|
+
getStakePoolStats(req: $request) {
|
|
148
|
+
tvl {
|
|
149
|
+
data
|
|
150
|
+
date
|
|
151
|
+
}
|
|
152
|
+
apy {
|
|
153
|
+
data
|
|
154
|
+
date
|
|
155
|
+
}
|
|
156
|
+
supply {
|
|
157
|
+
data
|
|
158
|
+
date
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
`,
|
|
163
|
+
}),
|
|
164
|
+
method: 'POST',
|
|
165
|
+
});
|
|
166
|
+
const data = await res.json();
|
|
167
|
+
return data;
|
|
168
|
+
}
|
|
169
|
+
exports.fetchJitoSolMetrics = fetchJitoSolMetrics;
|
|
170
|
+
const getJitoSolHistoricalPriceMap = async (timestamps) => {
|
|
171
|
+
try {
|
|
172
|
+
const data = await fetchJitoSolMetrics();
|
|
173
|
+
const jitoSolHistoricalPriceMap = new Map();
|
|
174
|
+
const jitoSolHistoricalPriceInSol = [];
|
|
175
|
+
for (let i = 0; i < data.data.getStakePoolStats.supply.length; i++) {
|
|
176
|
+
const priceInSol = data.data.getStakePoolStats.tvl[i].data /
|
|
177
|
+
new anchor_1.BN(10).pow(numericConstants_1.NINE) /
|
|
178
|
+
data.data.getStakePoolStats.supply[i].data;
|
|
179
|
+
jitoSolHistoricalPriceInSol.push({
|
|
180
|
+
price: priceInSol,
|
|
181
|
+
ts: data.data.getStakePoolStats.tvl[i].date,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
for (const timestamp of timestamps) {
|
|
185
|
+
const date = new Date(timestamp * 1000);
|
|
186
|
+
const dateString = date.toISOString();
|
|
187
|
+
const price = jitoSolHistoricalPriceInSol.find((p) => (0, utils_1.checkSameDate)(p.ts, dateString));
|
|
188
|
+
if (price) {
|
|
189
|
+
jitoSolHistoricalPriceMap.set(timestamp, price.price);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return jitoSolHistoricalPriceMap;
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
console.error(err);
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
async function calculateSolEarned({ marketIndex, user, depositRecords, }) {
|
|
66
200
|
const now = Date.now() / 1000;
|
|
67
201
|
const timestamps = [
|
|
68
202
|
now,
|
|
69
203
|
...depositRecords.map((r) => r.ts.toNumber()),
|
|
70
204
|
];
|
|
71
|
-
|
|
72
|
-
const
|
|
205
|
+
let lstRatios = new Map();
|
|
206
|
+
const getMsolPrice = async (timestamp) => {
|
|
73
207
|
const date = new Date(timestamp * 1000); // Convert Unix timestamp to milliseconds
|
|
74
208
|
const swaggerApiDateTime = date.toISOString(); // Format date as swagger API date-time
|
|
75
209
|
const url = `https://api.marinade.finance/msol/price_sol?time=${swaggerApiDateTime}`;
|
|
76
210
|
const response = await (0, node_fetch_1.default)(url);
|
|
77
211
|
if (response.status === 200) {
|
|
78
212
|
const data = await response.json();
|
|
79
|
-
|
|
213
|
+
lstRatios.set(timestamp, data);
|
|
80
214
|
}
|
|
81
215
|
};
|
|
82
|
-
|
|
216
|
+
if (marketIndex === 2) {
|
|
217
|
+
await Promise.all(timestamps.map(getMsolPrice));
|
|
218
|
+
}
|
|
219
|
+
else if (marketIndex === 6) {
|
|
220
|
+
lstRatios = await getJitoSolHistoricalPriceMap(timestamps);
|
|
221
|
+
}
|
|
83
222
|
let solEarned = numericConstants_1.ZERO;
|
|
84
223
|
for (const record of depositRecords) {
|
|
85
224
|
if (record.marketIndex === 1) {
|
|
@@ -91,7 +230,7 @@ async function calculateSolEarned({ user, depositRecords, }) {
|
|
|
91
230
|
}
|
|
92
231
|
}
|
|
93
232
|
else if (record.marketIndex === 2) {
|
|
94
|
-
const msolRatio =
|
|
233
|
+
const msolRatio = lstRatios.get(record.ts.toNumber());
|
|
95
234
|
const msolRatioBN = new anchor_1.BN(msolRatio * web3_js_1.LAMPORTS_PER_SOL);
|
|
96
235
|
const solAmount = record.amount.mul(msolRatioBN).div(numericConstants_1.LAMPORTS_PRECISION);
|
|
97
236
|
if ((0, types_1.isVariant)(record.direction, 'deposit')) {
|
|
@@ -101,21 +240,34 @@ async function calculateSolEarned({ user, depositRecords, }) {
|
|
|
101
240
|
solEarned = solEarned.add(solAmount);
|
|
102
241
|
}
|
|
103
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);
|
|
249
|
+
if ((0, types_1.isVariant)(record.direction, 'deposit')) {
|
|
250
|
+
solEarned = solEarned.sub(solAmount);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
solEarned = solEarned.add(solAmount);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
104
256
|
}
|
|
105
|
-
const
|
|
257
|
+
const currentLstTokenAmount = await user.getTokenAmount(marketIndex);
|
|
258
|
+
const currentLstRatio = lstRatios.get(now);
|
|
259
|
+
const currentLstRatioBN = new anchor_1.BN(currentLstRatio * web3_js_1.LAMPORTS_PER_SOL);
|
|
260
|
+
solEarned = solEarned.add(currentLstTokenAmount.mul(currentLstRatioBN).div(numericConstants_1.LAMPORTS_PRECISION));
|
|
106
261
|
const currentSOLTokenAmount = await user.getTokenAmount(1);
|
|
107
|
-
const currentMSOLRatio = msolRatios.get(now);
|
|
108
|
-
const currentMSOLRatioBN = new anchor_1.BN(currentMSOLRatio * web3_js_1.LAMPORTS_PER_SOL);
|
|
109
|
-
solEarned = solEarned.add(currentMSOLTokenAmount.mul(currentMSOLRatioBN).div(numericConstants_1.LAMPORTS_PRECISION));
|
|
110
262
|
solEarned = solEarned.add(currentSOLTokenAmount);
|
|
111
263
|
return solEarned;
|
|
112
264
|
}
|
|
113
265
|
exports.calculateSolEarned = calculateSolEarned;
|
|
114
|
-
// calculate estimated liquidation price (in
|
|
115
|
-
function calculateEstimatedSuperStakeLiquidationPrice(
|
|
266
|
+
// calculate estimated liquidation price (in LST/SOL) based on target amounts
|
|
267
|
+
function calculateEstimatedSuperStakeLiquidationPrice(lstDepositAmount, lstMaintenanceAssetWeight, solBorrowAmount, solMaintenanceLiabilityWeight, lstPriceRatio) {
|
|
116
268
|
const liquidationDivergence = (solMaintenanceLiabilityWeight * solBorrowAmount) /
|
|
117
|
-
(
|
|
118
|
-
const liquidationPrice =
|
|
269
|
+
(lstMaintenanceAssetWeight * lstDepositAmount * lstPriceRatio);
|
|
270
|
+
const liquidationPrice = lstPriceRatio * liquidationDivergence;
|
|
119
271
|
return liquidationPrice;
|
|
120
272
|
}
|
|
121
273
|
exports.calculateEstimatedSuperStakeLiquidationPrice = calculateEstimatedSuperStakeLiquidationPrice;
|
package/lib/math/utils.d.ts
CHANGED
|
@@ -12,3 +12,4 @@ export declare const sigNum: (x: BN) => BN;
|
|
|
12
12
|
* @returns: timeRemainingUntilUpdate (in seconds)
|
|
13
13
|
*/
|
|
14
14
|
export declare function timeRemainingUntilUpdate(now: BN, lastUpdateTs: BN, updatePeriod: BN): BN;
|
|
15
|
+
export declare const checkSameDate: (dateString1: string, dateString2: string) => boolean;
|
package/lib/math/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.timeRemainingUntilUpdate = exports.sigNum = exports.divCeil = exports.squareRootBN = exports.clampBN = void 0;
|
|
3
|
+
exports.checkSameDate = exports.timeRemainingUntilUpdate = exports.sigNum = exports.divCeil = exports.squareRootBN = exports.clampBN = void 0;
|
|
4
4
|
const __1 = require("../");
|
|
5
5
|
function clampBN(x, min, max) {
|
|
6
6
|
return __1.BN.max(min, __1.BN.min(x, max));
|
|
@@ -76,3 +76,12 @@ function timeRemainingUntilUpdate(now, lastUpdateTs, updatePeriod) {
|
|
|
76
76
|
return timeRemainingUntilUpdate;
|
|
77
77
|
}
|
|
78
78
|
exports.timeRemainingUntilUpdate = timeRemainingUntilUpdate;
|
|
79
|
+
const checkSameDate = (dateString1, dateString2) => {
|
|
80
|
+
const date1 = new Date(dateString1);
|
|
81
|
+
const date2 = new Date(dateString2);
|
|
82
|
+
const isSameDate = date1.getDate() === date2.getDate() &&
|
|
83
|
+
date1.getMonth() === date2.getMonth() &&
|
|
84
|
+
date1.getFullYear() === date2.getFullYear();
|
|
85
|
+
return isSameDate;
|
|
86
|
+
};
|
|
87
|
+
exports.checkSameDate = checkSameDate;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
2
|
import { DriftClient } from '../driftClient';
|
|
4
3
|
import { UserAccount } from '../types';
|
|
5
|
-
import { Buffer } from 'buffer';
|
|
6
4
|
import { DLOB } from '../dlob/DLOB';
|
|
7
5
|
import { OrderSubscriberConfig, OrderSubscriberEvents } from './types';
|
|
8
6
|
import { PollingSubscription } from './PollingSubscription';
|
|
@@ -22,7 +20,7 @@ export declare class OrderSubscriber {
|
|
|
22
20
|
constructor(config: OrderSubscriberConfig);
|
|
23
21
|
subscribe(): Promise<void>;
|
|
24
22
|
fetch(): Promise<void>;
|
|
25
|
-
tryUpdateUserAccount(key: string,
|
|
23
|
+
tryUpdateUserAccount(key: string, userAccount: UserAccount, slot: number): void;
|
|
26
24
|
getDLOB(slot: number): Promise<DLOB>;
|
|
27
25
|
unsubscribe(): Promise<void>;
|
|
28
26
|
}
|
|
@@ -22,6 +22,7 @@ class OrderSubscriber {
|
|
|
22
22
|
this.subscription = new WebsocketSubscription_1.WebsocketSubscription({
|
|
23
23
|
orderSubscriber: this,
|
|
24
24
|
skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
|
|
25
|
+
resubTimeoutMs: config.subscriptionConfig.resubTimeoutMs,
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
this.eventEmitter = new events_1.EventEmitter();
|
|
@@ -57,7 +58,8 @@ class OrderSubscriber {
|
|
|
57
58
|
// @ts-ignore
|
|
58
59
|
const buffer = buffer_1.Buffer.from(programAccount.account.data[0], programAccount.account.data[1]);
|
|
59
60
|
programAccountSet.add(key);
|
|
60
|
-
this.
|
|
61
|
+
const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', buffer);
|
|
62
|
+
this.tryUpdateUserAccount(key, userAccount, slot);
|
|
61
63
|
}
|
|
62
64
|
for (const key of this.usersAccounts.keys()) {
|
|
63
65
|
if (!programAccountSet.has(key)) {
|
|
@@ -73,10 +75,9 @@ class OrderSubscriber {
|
|
|
73
75
|
this.fetchPromise = undefined;
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
|
-
tryUpdateUserAccount(key,
|
|
78
|
+
tryUpdateUserAccount(key, userAccount, slot) {
|
|
77
79
|
const slotAndUserAccount = this.usersAccounts.get(key);
|
|
78
80
|
if (!slotAndUserAccount || slotAndUserAccount.slot < slot) {
|
|
79
|
-
const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', buffer);
|
|
80
81
|
const newOrders = userAccount.orders.filter((order) => {
|
|
81
82
|
var _a;
|
|
82
83
|
return order.slot.toNumber() > ((_a = slotAndUserAccount === null || slotAndUserAccount === void 0 ? void 0 : slotAndUserAccount.slot) !== null && _a !== void 0 ? _a : 0) &&
|
|
@@ -2,10 +2,12 @@ import { OrderSubscriber } from './OrderSubscriber';
|
|
|
2
2
|
export declare class WebsocketSubscription {
|
|
3
3
|
private orderSubscriber;
|
|
4
4
|
private skipInitialLoad;
|
|
5
|
-
private
|
|
6
|
-
|
|
5
|
+
private resubTimeoutMs?;
|
|
6
|
+
private subscriber;
|
|
7
|
+
constructor({ orderSubscriber, skipInitialLoad, resubTimeoutMs, }: {
|
|
7
8
|
orderSubscriber: OrderSubscriber;
|
|
8
9
|
skipInitialLoad?: boolean;
|
|
10
|
+
resubTimeoutMs?: number;
|
|
9
11
|
});
|
|
10
12
|
subscribe(): Promise<void>;
|
|
11
13
|
unsubscribe(): Promise<void>;
|
|
@@ -2,29 +2,30 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WebsocketSubscription = void 0;
|
|
4
4
|
const memcmp_1 = require("../memcmp");
|
|
5
|
+
const webSocketProgramAccountSubscriber_1 = require("../accounts/webSocketProgramAccountSubscriber");
|
|
5
6
|
class WebsocketSubscription {
|
|
6
|
-
constructor({ orderSubscriber, skipInitialLoad = false, }) {
|
|
7
|
+
constructor({ orderSubscriber, skipInitialLoad = false, resubTimeoutMs, }) {
|
|
7
8
|
this.orderSubscriber = orderSubscriber;
|
|
8
9
|
this.skipInitialLoad = skipInitialLoad;
|
|
10
|
+
this.resubTimeoutMs = resubTimeoutMs;
|
|
9
11
|
}
|
|
10
12
|
async subscribe() {
|
|
11
|
-
if (this.
|
|
12
|
-
|
|
13
|
+
if (!this.subscriber) {
|
|
14
|
+
this.subscriber = new webSocketProgramAccountSubscriber_1.WebSocketProgramAccountSubscriber('OrderSubscriber', 'User', this.orderSubscriber.driftClient.program, this.orderSubscriber.driftClient.program.account.user.coder.accounts.decode.bind(this.orderSubscriber.driftClient.program.account.user.coder.accounts), {
|
|
15
|
+
filters: [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getNonIdleUserFilter)()],
|
|
16
|
+
commitment: this.orderSubscriber.driftClient.opts.commitment,
|
|
17
|
+
}, this.resubTimeoutMs);
|
|
13
18
|
}
|
|
14
|
-
this.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}, this.orderSubscriber.driftClient.opts.commitment, [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getNonIdleUserFilter)()]);
|
|
19
|
+
await this.subscriber.subscribe((accountId, account, context) => {
|
|
20
|
+
const userKey = accountId.toBase58();
|
|
21
|
+
this.orderSubscriber.tryUpdateUserAccount(userKey, account, context.slot);
|
|
22
|
+
});
|
|
19
23
|
if (!this.skipInitialLoad) {
|
|
20
24
|
await this.orderSubscriber.fetch();
|
|
21
25
|
}
|
|
22
26
|
}
|
|
23
27
|
async unsubscribe() {
|
|
24
|
-
|
|
25
|
-
await this.orderSubscriber.driftClient.connection.removeProgramAccountChangeListener(this.websocketId);
|
|
26
|
-
this.websocketId = undefined;
|
|
27
|
-
}
|
|
28
|
+
this.subscriber.unsubscribe();
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
exports.WebsocketSubscription = WebsocketSubscription;
|
package/package.json
CHANGED
package/src/accounts/types.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '../types';
|
|
9
9
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
10
10
|
import { EventEmitter } from 'events';
|
|
11
|
-
import { PublicKey } from '@solana/web3.js';
|
|
11
|
+
import { Context, PublicKey } from '@solana/web3.js';
|
|
12
12
|
import { Account } from '@solana/spl-token';
|
|
13
13
|
import { OracleInfo, OraclePriceData } from '..';
|
|
14
14
|
|
|
@@ -21,6 +21,13 @@ export interface AccountSubscriber<T> {
|
|
|
21
21
|
setData(userAccount: T, slot?: number): void;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export interface ProgramAccountSubscriber<T> {
|
|
25
|
+
subscribe(
|
|
26
|
+
onChange: (accountId: PublicKey, data: T, context: Context) => void
|
|
27
|
+
): Promise<void>;
|
|
28
|
+
unsubscribe(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
export class NotSubscribedError extends Error {
|
|
25
32
|
name = 'NotSubscribedError';
|
|
26
33
|
}
|
|
@@ -13,17 +13,24 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
13
13
|
decodeBufferFn: (buffer: Buffer) => T;
|
|
14
14
|
onChange: (data: T) => void;
|
|
15
15
|
listenerId?: number;
|
|
16
|
+
resubTimeoutMs?: number;
|
|
17
|
+
timeoutId?: NodeJS.Timeout;
|
|
18
|
+
|
|
19
|
+
receivingData: boolean;
|
|
16
20
|
|
|
17
21
|
public constructor(
|
|
18
22
|
accountName: string,
|
|
19
23
|
program: Program,
|
|
20
24
|
accountPublicKey: PublicKey,
|
|
21
|
-
decodeBuffer?: (buffer: Buffer) => T
|
|
25
|
+
decodeBuffer?: (buffer: Buffer) => T,
|
|
26
|
+
resubTimeoutMs?: number
|
|
22
27
|
) {
|
|
23
28
|
this.accountName = accountName;
|
|
24
29
|
this.program = program;
|
|
25
30
|
this.accountPublicKey = accountPublicKey;
|
|
26
31
|
this.decodeBufferFn = decodeBuffer;
|
|
32
|
+
this.resubTimeoutMs = resubTimeoutMs;
|
|
33
|
+
this.receivingData = false;
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
async subscribe(onChange: (data: T) => void): Promise<void> {
|
|
@@ -39,10 +46,21 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
39
46
|
this.listenerId = this.program.provider.connection.onAccountChange(
|
|
40
47
|
this.accountPublicKey,
|
|
41
48
|
(accountInfo, context) => {
|
|
42
|
-
this.
|
|
49
|
+
if (this.resubTimeoutMs) {
|
|
50
|
+
this.receivingData = true;
|
|
51
|
+
clearTimeout(this.timeoutId);
|
|
52
|
+
this.handleRpcResponse(context, accountInfo);
|
|
53
|
+
this.setTimeout();
|
|
54
|
+
} else {
|
|
55
|
+
this.handleRpcResponse(context, accountInfo);
|
|
56
|
+
}
|
|
43
57
|
},
|
|
44
58
|
(this.program.provider as AnchorProvider).opts.commitment
|
|
45
59
|
);
|
|
60
|
+
|
|
61
|
+
if (this.resubTimeoutMs) {
|
|
62
|
+
this.setTimeout();
|
|
63
|
+
}
|
|
46
64
|
}
|
|
47
65
|
|
|
48
66
|
setData(data: T, slot?: number): void {
|
|
@@ -57,6 +75,22 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
57
75
|
};
|
|
58
76
|
}
|
|
59
77
|
|
|
78
|
+
private setTimeout(): void {
|
|
79
|
+
if (!this.onChange) {
|
|
80
|
+
throw new Error('onChange callback function must be set');
|
|
81
|
+
}
|
|
82
|
+
this.timeoutId = setTimeout(async () => {
|
|
83
|
+
if (this.receivingData) {
|
|
84
|
+
console.log(
|
|
85
|
+
`No ws data from ${this.accountName} in ${this.resubTimeoutMs}ms, resubscribing`
|
|
86
|
+
);
|
|
87
|
+
await this.unsubscribe();
|
|
88
|
+
this.receivingData = false;
|
|
89
|
+
await this.subscribe(this.onChange);
|
|
90
|
+
}
|
|
91
|
+
}, this.resubTimeoutMs);
|
|
92
|
+
}
|
|
93
|
+
|
|
60
94
|
async fetch(): Promise<void> {
|
|
61
95
|
const rpcResponse =
|
|
62
96
|
await this.program.provider.connection.getAccountInfoAndContext(
|
|
@@ -31,6 +31,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
31
31
|
oracleInfos: OracleInfo[];
|
|
32
32
|
oracleClientCache = new OracleClientCache();
|
|
33
33
|
|
|
34
|
+
resubTimeoutMs?: number;
|
|
34
35
|
shouldFindAllMarketsAndOracles: boolean;
|
|
35
36
|
|
|
36
37
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
@@ -54,7 +55,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
54
55
|
perpMarketIndexes: number[],
|
|
55
56
|
spotMarketIndexes: number[],
|
|
56
57
|
oracleInfos: OracleInfo[],
|
|
57
|
-
shouldFindAllMarketsAndOracles: boolean
|
|
58
|
+
shouldFindAllMarketsAndOracles: boolean,
|
|
59
|
+
resubTimeoutMs?: number
|
|
58
60
|
) {
|
|
59
61
|
this.isSubscribed = false;
|
|
60
62
|
this.program = program;
|
|
@@ -63,6 +65,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
63
65
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
64
66
|
this.oracleInfos = oracleInfos;
|
|
65
67
|
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
68
|
+
this.resubTimeoutMs = resubTimeoutMs;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
public async subscribe(): Promise<boolean> {
|
|
@@ -96,7 +99,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
96
99
|
this.stateAccountSubscriber = new WebSocketAccountSubscriber(
|
|
97
100
|
'state',
|
|
98
101
|
this.program,
|
|
99
|
-
statePublicKey
|
|
102
|
+
statePublicKey,
|
|
103
|
+
undefined,
|
|
104
|
+
this.resubTimeoutMs
|
|
100
105
|
);
|
|
101
106
|
await this.stateAccountSubscriber.subscribe((data: StateAccount) => {
|
|
102
107
|
this.eventEmitter.emit('stateAccountUpdate', data);
|
|
@@ -136,7 +141,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
136
141
|
const accountSubscriber = new WebSocketAccountSubscriber<PerpMarketAccount>(
|
|
137
142
|
'perpMarket',
|
|
138
143
|
this.program,
|
|
139
|
-
perpMarketPublicKey
|
|
144
|
+
perpMarketPublicKey,
|
|
145
|
+
undefined,
|
|
146
|
+
this.resubTimeoutMs
|
|
140
147
|
);
|
|
141
148
|
await accountSubscriber.subscribe((data: PerpMarketAccount) => {
|
|
142
149
|
this.eventEmitter.emit('perpMarketAccountUpdate', data);
|
|
@@ -161,7 +168,9 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
161
168
|
const accountSubscriber = new WebSocketAccountSubscriber<SpotMarketAccount>(
|
|
162
169
|
'spotMarket',
|
|
163
170
|
this.program,
|
|
164
|
-
marketPublicKey
|
|
171
|
+
marketPublicKey,
|
|
172
|
+
undefined,
|
|
173
|
+
this.resubTimeoutMs
|
|
165
174
|
);
|
|
166
175
|
await accountSubscriber.subscribe((data: SpotMarketAccount) => {
|
|
167
176
|
this.eventEmitter.emit('spotMarketAccountUpdate', data);
|
|
@@ -192,7 +201,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
192
201
|
oracleInfo.publicKey,
|
|
193
202
|
(buffer: Buffer) => {
|
|
194
203
|
return client.getOraclePriceDataFromBuffer(buffer);
|
|
195
|
-
}
|
|
204
|
+
},
|
|
205
|
+
this.resubTimeoutMs
|
|
196
206
|
);
|
|
197
207
|
|
|
198
208
|
await accountSubscriber.subscribe((data: OraclePriceData) => {
|