@drift-labs/sdk 2.52.0-beta.1 → 2.52.0-beta.10
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/examples/phoenix.ts +11 -4
- package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
- package/lib/accounts/webSocketAccountSubscriber.js +7 -4
- package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +1 -1
- package/lib/accounts/webSocketProgramAccountSubscriber.js +7 -4
- package/lib/dlob/orderBookLevels.d.ts +22 -0
- package/lib/dlob/orderBookLevels.js +115 -1
- package/lib/driftClient.d.ts +3 -1
- package/lib/driftClient.js +30 -8
- package/lib/events/webSocketLogProvider.js +3 -3
- package/lib/factory/bigNum.d.ts +1 -1
- package/lib/factory/bigNum.js +5 -2
- package/lib/idl/drift.json +52 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/math/amm.d.ts +5 -1
- package/lib/math/amm.js +62 -13
- package/lib/math/state.js +3 -0
- package/lib/orderSubscriber/OrderSubscriber.js +1 -0
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -1
- package/lib/orderSubscriber/WebsocketSubscription.js +25 -1
- package/lib/orderSubscriber/types.d.ts +1 -0
- package/lib/phoenix/phoenixSubscriber.js +10 -6
- package/lib/priorityFee/averageOverSlotsStrategy.d.ts +12 -0
- package/lib/priorityFee/averageOverSlotsStrategy.js +28 -0
- package/lib/priorityFee/averageStrategy.d.ts +7 -0
- package/lib/priorityFee/averageStrategy.js +11 -0
- package/lib/priorityFee/ewmaStrategy.d.ts +13 -0
- package/lib/priorityFee/ewmaStrategy.js +33 -0
- package/lib/priorityFee/index.d.ts +7 -0
- package/lib/priorityFee/index.js +23 -0
- package/lib/priorityFee/maxOverSlotsStrategy.d.ts +12 -0
- package/lib/priorityFee/maxOverSlotsStrategy.js +29 -0
- package/lib/priorityFee/maxStrategy.d.ts +7 -0
- package/lib/priorityFee/maxStrategy.js +9 -0
- package/lib/priorityFee/priorityFeeSubscriber.d.ts +15 -4
- package/lib/priorityFee/priorityFeeSubscriber.js +38 -14
- package/lib/priorityFee/types.d.ts +6 -0
- package/lib/priorityFee/types.js +2 -0
- package/lib/slot/SlotSubscriber.d.ts +11 -3
- package/lib/slot/SlotSubscriber.js +40 -4
- package/lib/types.d.ts +4 -1
- package/lib/types.js +1 -0
- package/lib/user.d.ts +1 -1
- package/lib/user.js +15 -8
- package/lib/userMap/userMap.d.ts +3 -0
- package/lib/userMap/userMap.js +9 -0
- package/package.json +1 -1
- package/src/accounts/webSocketAccountSubscriber.ts +7 -4
- package/src/accounts/webSocketProgramAccountSubscriber.ts +7 -4
- package/src/dlob/orderBookLevels.ts +136 -0
- package/src/driftClient.ts +46 -8
- package/src/events/webSocketLogProvider.ts +3 -3
- package/src/factory/bigNum.ts +11 -2
- package/src/idl/drift.json +52 -1
- package/src/index.ts +1 -1
- package/src/math/amm.ts +159 -25
- package/src/math/state.ts +3 -0
- package/src/orderSubscriber/OrderSubscriber.ts +1 -0
- package/src/orderSubscriber/WebsocketSubscription.ts +28 -0
- package/src/orderSubscriber/types.ts +1 -0
- package/src/phoenix/phoenixSubscriber.ts +14 -8
- package/src/priorityFee/averageOverSlotsStrategy.ts +30 -0
- package/src/priorityFee/averageStrategy.ts +11 -0
- package/src/priorityFee/ewmaStrategy.ts +40 -0
- package/src/priorityFee/index.ts +7 -0
- package/src/priorityFee/maxOverSlotsStrategy.ts +31 -0
- package/src/priorityFee/maxStrategy.ts +7 -0
- package/src/priorityFee/priorityFeeSubscriber.ts +46 -19
- package/src/priorityFee/types.ts +5 -0
- package/src/slot/SlotSubscriber.ts +52 -5
- package/src/types.ts +2 -1
- package/src/user.ts +25 -8
- package/src/userMap/userMap.ts +12 -0
- package/tests/amm/test.ts +219 -11
- package/tests/bn/test.ts +27 -0
- package/tests/dlob/helpers.ts +1 -1
- package/tests/dlob/test.ts +372 -2
- package/tests/tx/priorityFeeStrategy.ts +97 -0
- package/tests/user/helpers.ts +1 -0
|
@@ -3,28 +3,64 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SlotSubscriber = void 0;
|
|
4
4
|
const events_1 = require("events");
|
|
5
5
|
class SlotSubscriber {
|
|
6
|
-
constructor(connection,
|
|
6
|
+
constructor(connection, config) {
|
|
7
7
|
this.connection = connection;
|
|
8
|
+
this.isUnsubscribing = false;
|
|
9
|
+
this.receivingData = false;
|
|
8
10
|
this.eventEmitter = new events_1.EventEmitter();
|
|
11
|
+
this.resubTimeoutMs = config === null || config === void 0 ? void 0 : config.resubTimeoutMs;
|
|
9
12
|
}
|
|
10
13
|
async subscribe() {
|
|
11
|
-
if (this.subscriptionId) {
|
|
14
|
+
if (this.subscriptionId != null) {
|
|
12
15
|
return;
|
|
13
16
|
}
|
|
14
17
|
this.currentSlot = await this.connection.getSlot('confirmed');
|
|
15
18
|
this.subscriptionId = this.connection.onSlotChange((slotInfo) => {
|
|
16
19
|
if (!this.currentSlot || this.currentSlot < slotInfo.slot) {
|
|
20
|
+
if (this.resubTimeoutMs && !this.isUnsubscribing) {
|
|
21
|
+
this.receivingData = true;
|
|
22
|
+
clearTimeout(this.timeoutId);
|
|
23
|
+
this.setTimeout();
|
|
24
|
+
}
|
|
17
25
|
this.currentSlot = slotInfo.slot;
|
|
18
26
|
this.eventEmitter.emit('newSlot', slotInfo.slot);
|
|
19
27
|
}
|
|
20
28
|
});
|
|
29
|
+
if (this.resubTimeoutMs) {
|
|
30
|
+
this.setTimeout();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
setTimeout() {
|
|
34
|
+
this.timeoutId = setTimeout(async () => {
|
|
35
|
+
if (this.isUnsubscribing) {
|
|
36
|
+
// If we are in the process of unsubscribing, do not attempt to resubscribe
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (this.receivingData) {
|
|
40
|
+
console.log(`No new slot in ${this.resubTimeoutMs}ms, slot subscriber resubscribing`);
|
|
41
|
+
await this.unsubscribe(true);
|
|
42
|
+
this.receivingData = false;
|
|
43
|
+
await this.subscribe();
|
|
44
|
+
}
|
|
45
|
+
}, this.resubTimeoutMs);
|
|
21
46
|
}
|
|
22
47
|
getSlot() {
|
|
23
48
|
return this.currentSlot;
|
|
24
49
|
}
|
|
25
|
-
async unsubscribe() {
|
|
26
|
-
if (
|
|
50
|
+
async unsubscribe(onResub = false) {
|
|
51
|
+
if (!onResub) {
|
|
52
|
+
this.resubTimeoutMs = undefined;
|
|
53
|
+
}
|
|
54
|
+
this.isUnsubscribing = true;
|
|
55
|
+
clearTimeout(this.timeoutId);
|
|
56
|
+
this.timeoutId = undefined;
|
|
57
|
+
if (this.subscriptionId != null) {
|
|
27
58
|
await this.connection.removeSlotChangeListener(this.subscriptionId);
|
|
59
|
+
this.subscriptionId = undefined;
|
|
60
|
+
this.isUnsubscribing = false;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
this.isUnsubscribing = false;
|
|
28
64
|
}
|
|
29
65
|
}
|
|
30
66
|
}
|
package/lib/types.d.ts
CHANGED
|
@@ -278,6 +278,9 @@ export declare class DepositExplanation {
|
|
|
278
278
|
static readonly TRANSFER: {
|
|
279
279
|
transfer: {};
|
|
280
280
|
};
|
|
281
|
+
static readonly BORROW: {
|
|
282
|
+
borrow: {};
|
|
283
|
+
};
|
|
281
284
|
}
|
|
282
285
|
export declare class SettlePnlExplanation {
|
|
283
286
|
static readonly NONE: {
|
|
@@ -767,7 +770,7 @@ export type AMM = {
|
|
|
767
770
|
pegMultiplier: BN;
|
|
768
771
|
cumulativeFundingRateLong: BN;
|
|
769
772
|
cumulativeFundingRateShort: BN;
|
|
770
|
-
|
|
773
|
+
last24HAvgFundingRate: BN;
|
|
771
774
|
lastFundingRateShort: BN;
|
|
772
775
|
lastFundingRateLong: BN;
|
|
773
776
|
totalLiquidationFee: BN;
|
package/lib/types.js
CHANGED
|
@@ -183,6 +183,7 @@ class DepositExplanation {
|
|
|
183
183
|
exports.DepositExplanation = DepositExplanation;
|
|
184
184
|
DepositExplanation.NONE = { none: {} };
|
|
185
185
|
DepositExplanation.TRANSFER = { transfer: {} };
|
|
186
|
+
DepositExplanation.BORROW = { borrow: {} };
|
|
186
187
|
class SettlePnlExplanation {
|
|
187
188
|
}
|
|
188
189
|
exports.SettlePnlExplanation = SettlePnlExplanation;
|
package/lib/user.d.ts
CHANGED
|
@@ -353,7 +353,7 @@ export declare class User {
|
|
|
353
353
|
* @param quoteAmount
|
|
354
354
|
* @returns feeForQuote : Precision QUOTE_PRECISION
|
|
355
355
|
*/
|
|
356
|
-
calculateFeeForQuoteAmount(quoteAmount: BN): BN;
|
|
356
|
+
calculateFeeForQuoteAmount(quoteAmount: BN, marketIndex?: number): BN;
|
|
357
357
|
/**
|
|
358
358
|
* Calculates a user's max withdrawal amounts for a spot market. If reduceOnly is true,
|
|
359
359
|
* it will return the max withdrawal amount without opening a liability for the user
|
package/lib/user.js
CHANGED
|
@@ -768,8 +768,7 @@ class User {
|
|
|
768
768
|
* @returns : Precision QUOTE_PRECISION
|
|
769
769
|
*/
|
|
770
770
|
getPerpPositionValue(marketIndex, oraclePriceData, includeOpenOrders = false) {
|
|
771
|
-
const userPosition = this.getPerpPositionWithLPSettle(marketIndex)[0] ||
|
|
772
|
-
this.getEmptyPosition(marketIndex);
|
|
771
|
+
const userPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, false, true)[0] || this.getEmptyPosition(marketIndex);
|
|
773
772
|
const market = this.driftClient.getPerpMarketAccount(userPosition.marketIndex);
|
|
774
773
|
return (0, margin_1.calculateBaseAssetValueWithOracle)(market, userPosition, oraclePriceData, includeOpenOrders);
|
|
775
774
|
}
|
|
@@ -1645,7 +1644,7 @@ class User {
|
|
|
1645
1644
|
const feeTier = this.getUserFeeTier(marketType);
|
|
1646
1645
|
let takerFee = feeTier.feeNumerator / feeTier.feeDenominator;
|
|
1647
1646
|
let makerFee = feeTier.makerRebateNumerator / feeTier.makerRebateDenominator;
|
|
1648
|
-
if (marketIndex && (0, types_1.isVariant)(marketType, 'perp')) {
|
|
1647
|
+
if (marketIndex !== undefined && (0, types_1.isVariant)(marketType, 'perp')) {
|
|
1649
1648
|
const marketAccount = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1650
1649
|
takerFee += (takerFee * marketAccount.feeAdjustment) / 100;
|
|
1651
1650
|
makerFee += (makerFee * marketAccount.feeAdjustment) / 100;
|
|
@@ -1660,11 +1659,19 @@ class User {
|
|
|
1660
1659
|
* @param quoteAmount
|
|
1661
1660
|
* @returns feeForQuote : Precision QUOTE_PRECISION
|
|
1662
1661
|
*/
|
|
1663
|
-
calculateFeeForQuoteAmount(quoteAmount) {
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1662
|
+
calculateFeeForQuoteAmount(quoteAmount, marketIndex) {
|
|
1663
|
+
if (marketIndex !== undefined) {
|
|
1664
|
+
const takerFeeMultiplier = this.getMarketFees(_1.MarketType.PERP, marketIndex).takerFee;
|
|
1665
|
+
const feeAmountNum = _1.BigNum.from(quoteAmount, numericConstants_1.QUOTE_PRECISION_EXP).toNum() *
|
|
1666
|
+
takerFeeMultiplier;
|
|
1667
|
+
return _1.BigNum.fromPrint(feeAmountNum.toString(), numericConstants_1.QUOTE_PRECISION_EXP).val;
|
|
1668
|
+
}
|
|
1669
|
+
else {
|
|
1670
|
+
const feeTier = this.getUserFeeTier(_1.MarketType.PERP);
|
|
1671
|
+
return quoteAmount
|
|
1672
|
+
.mul(new _1.BN(feeTier.feeNumerator))
|
|
1673
|
+
.div(new _1.BN(feeTier.feeDenominator));
|
|
1674
|
+
}
|
|
1668
1675
|
}
|
|
1669
1676
|
/**
|
|
1670
1677
|
* Calculates a user's max withdrawal amounts for a spot market. If reduceOnly is true,
|
package/lib/userMap/userMap.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare class UserMap implements UserMapInterface {
|
|
|
22
22
|
private subscription;
|
|
23
23
|
private stateAccountUpdateCallback;
|
|
24
24
|
private decode;
|
|
25
|
+
private mostRecentSlot;
|
|
25
26
|
private syncPromise?;
|
|
26
27
|
private syncPromiseResolver;
|
|
27
28
|
/**
|
|
@@ -68,4 +69,6 @@ export declare class UserMap implements UserMapInterface {
|
|
|
68
69
|
sync(): Promise<void>;
|
|
69
70
|
unsubscribe(): Promise<void>;
|
|
70
71
|
updateUserAccount(key: string, userAccount: UserAccount, slot: number): Promise<void>;
|
|
72
|
+
updateLatestSlot(slot: number): void;
|
|
73
|
+
getSlot(): number;
|
|
71
74
|
}
|
package/lib/userMap/userMap.js
CHANGED
|
@@ -21,6 +21,7 @@ class UserMap {
|
|
|
21
21
|
this.lastNumberOfSubAccounts = state.numberOfSubAccounts;
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
|
+
this.mostRecentSlot = 0;
|
|
24
25
|
this.driftClient = config.driftClient;
|
|
25
26
|
if (config.connection) {
|
|
26
27
|
this.connection = config.connection;
|
|
@@ -218,6 +219,7 @@ class UserMap {
|
|
|
218
219
|
await this.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
|
|
219
220
|
const rpcResponseAndContext = rpcJSONResponse.result;
|
|
220
221
|
const slot = rpcResponseAndContext.context.slot;
|
|
222
|
+
this.updateLatestSlot(slot);
|
|
221
223
|
const programAccountBufferMap = new Map();
|
|
222
224
|
for (const programAccount of rpcResponseAndContext.value) {
|
|
223
225
|
programAccountBufferMap.set(programAccount.pubkey.toString(),
|
|
@@ -263,6 +265,7 @@ class UserMap {
|
|
|
263
265
|
}
|
|
264
266
|
}
|
|
265
267
|
async updateUserAccount(key, userAccount, slot) {
|
|
268
|
+
this.updateLatestSlot(slot);
|
|
266
269
|
if (!this.userMap.has(key)) {
|
|
267
270
|
this.addPubkey(new web3_js_1.PublicKey(key), userAccount, slot);
|
|
268
271
|
}
|
|
@@ -271,5 +274,11 @@ class UserMap {
|
|
|
271
274
|
user.accountSubscriber.updateData(userAccount, slot);
|
|
272
275
|
}
|
|
273
276
|
}
|
|
277
|
+
updateLatestSlot(slot) {
|
|
278
|
+
this.mostRecentSlot = Math.max(slot, this.mostRecentSlot);
|
|
279
|
+
}
|
|
280
|
+
getSlot() {
|
|
281
|
+
return this.mostRecentSlot;
|
|
282
|
+
}
|
|
274
283
|
}
|
|
275
284
|
exports.UserMap = UserMap;
|
package/package.json
CHANGED
|
@@ -40,7 +40,7 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
async subscribe(onChange: (data: T) => void): Promise<void> {
|
|
43
|
-
if (this.listenerId || this.isUnsubscribing) {
|
|
43
|
+
if (this.listenerId != null || this.isUnsubscribing) {
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -95,7 +95,7 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
95
95
|
console.log(
|
|
96
96
|
`No ws data from ${this.accountName} in ${this.resubTimeoutMs}ms, resubscribing`
|
|
97
97
|
);
|
|
98
|
-
await this.unsubscribe();
|
|
98
|
+
await this.unsubscribe(true);
|
|
99
99
|
this.receivingData = false;
|
|
100
100
|
await this.subscribe(this.onChange);
|
|
101
101
|
}
|
|
@@ -164,12 +164,15 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
unsubscribe(): Promise<void> {
|
|
167
|
+
unsubscribe(onResub = false): Promise<void> {
|
|
168
|
+
if (!onResub) {
|
|
169
|
+
this.resubTimeoutMs = undefined;
|
|
170
|
+
}
|
|
168
171
|
this.isUnsubscribing = true;
|
|
169
172
|
clearTimeout(this.timeoutId);
|
|
170
173
|
this.timeoutId = undefined;
|
|
171
174
|
|
|
172
|
-
if (this.listenerId) {
|
|
175
|
+
if (this.listenerId != null) {
|
|
173
176
|
const promise = this.program.provider.connection
|
|
174
177
|
.removeAccountChangeListener(this.listenerId)
|
|
175
178
|
.then(() => {
|
|
@@ -49,7 +49,7 @@ export class WebSocketProgramAccountSubscriber<T>
|
|
|
49
49
|
async subscribe(
|
|
50
50
|
onChange: (accountId: PublicKey, data: T, context: Context) => void
|
|
51
51
|
): Promise<void> {
|
|
52
|
-
if (this.listenerId || this.isUnsubscribing) {
|
|
52
|
+
if (this.listenerId != null || this.isUnsubscribing) {
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -91,7 +91,7 @@ export class WebSocketProgramAccountSubscriber<T>
|
|
|
91
91
|
console.log(
|
|
92
92
|
`No ws data from ${this.subscriptionName} in ${this.resubTimeoutMs}ms, resubscribing`
|
|
93
93
|
);
|
|
94
|
-
await this.unsubscribe();
|
|
94
|
+
await this.unsubscribe(true);
|
|
95
95
|
this.receivingData = false;
|
|
96
96
|
await this.subscribe(this.onChange);
|
|
97
97
|
}
|
|
@@ -145,12 +145,15 @@ export class WebSocketProgramAccountSubscriber<T>
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
unsubscribe(): Promise<void> {
|
|
148
|
+
unsubscribe(onResub = false): Promise<void> {
|
|
149
|
+
if (!onResub) {
|
|
150
|
+
this.resubTimeoutMs = undefined;
|
|
151
|
+
}
|
|
149
152
|
this.isUnsubscribing = true;
|
|
150
153
|
clearTimeout(this.timeoutId);
|
|
151
154
|
this.timeoutId = undefined;
|
|
152
155
|
|
|
153
|
-
if (this.listenerId) {
|
|
156
|
+
if (this.listenerId != null) {
|
|
154
157
|
const promise = this.program.provider.connection
|
|
155
158
|
.removeAccountChangeListener(this.listenerId)
|
|
156
159
|
.then(() => {
|
|
@@ -407,3 +407,139 @@ function groupL2Levels(
|
|
|
407
407
|
}
|
|
408
408
|
return groupedLevels;
|
|
409
409
|
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
|
|
413
|
+
* This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
|
|
414
|
+
* crossing book)
|
|
415
|
+
*
|
|
416
|
+
* Things to note about how it works:
|
|
417
|
+
* - it will not uncross the user's liquidity
|
|
418
|
+
* - it does the uncrossing by "shifting" the crossing liquidity to the nearest uncrossed levels. Thus the output liquidity maintains the same total size.
|
|
419
|
+
*
|
|
420
|
+
* @param bids
|
|
421
|
+
* @param asks
|
|
422
|
+
* @param oraclePrice
|
|
423
|
+
* @param oracleTwap5Min
|
|
424
|
+
* @param markTwap5Min
|
|
425
|
+
* @param grouping
|
|
426
|
+
* @param userBids
|
|
427
|
+
* @param userAsks
|
|
428
|
+
*/
|
|
429
|
+
export function uncrossL2(
|
|
430
|
+
bids: L2Level[],
|
|
431
|
+
asks: L2Level[],
|
|
432
|
+
oraclePrice: BN,
|
|
433
|
+
oracleTwap5Min: BN,
|
|
434
|
+
markTwap5Min: BN,
|
|
435
|
+
grouping: BN,
|
|
436
|
+
userBids: Set<string>,
|
|
437
|
+
userAsks: Set<string>
|
|
438
|
+
): { bids: L2Level[]; asks: L2Level[] } {
|
|
439
|
+
// If there are no bids or asks, there is nothing to center
|
|
440
|
+
if (bids.length === 0 || asks.length === 0) {
|
|
441
|
+
return { bids, asks };
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// If the top of the book is already centered, there is nothing to do
|
|
445
|
+
if (bids[0].price.lt(asks[0].price)) {
|
|
446
|
+
return { bids, asks };
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const newBids = [];
|
|
450
|
+
const newAsks = [];
|
|
451
|
+
|
|
452
|
+
const updateLevels = (newPrice: BN, oldLevel: L2Level, levels: L2Level[]) => {
|
|
453
|
+
if (levels.length > 0 && levels[levels.length - 1].price.eq(newPrice)) {
|
|
454
|
+
levels[levels.length - 1].size = levels[levels.length - 1].size.add(
|
|
455
|
+
oldLevel.size
|
|
456
|
+
);
|
|
457
|
+
for (const [source, size] of Object.entries(oldLevel.sources)) {
|
|
458
|
+
if (levels[levels.length - 1].sources[source]) {
|
|
459
|
+
levels[levels.length - 1].sources = {
|
|
460
|
+
...levels[levels.length - 1].sources,
|
|
461
|
+
[source]: levels[levels.length - 1].sources[source].add(size),
|
|
462
|
+
};
|
|
463
|
+
} else {
|
|
464
|
+
levels[levels.length - 1].sources[source] = size;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
levels.push({
|
|
469
|
+
price: newPrice,
|
|
470
|
+
size: oldLevel.size,
|
|
471
|
+
sources: oldLevel.sources,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
// This is the best estimate of the premium in the market vs oracle to filter crossing around
|
|
477
|
+
const referencePrice = oraclePrice.add(markTwap5Min.sub(oracleTwap5Min));
|
|
478
|
+
|
|
479
|
+
let bidIndex = 0;
|
|
480
|
+
let askIndex = 0;
|
|
481
|
+
while (bidIndex < bids.length || askIndex < asks.length) {
|
|
482
|
+
const nextBid = bids[bidIndex];
|
|
483
|
+
const nextAsk = asks[askIndex];
|
|
484
|
+
|
|
485
|
+
if (!nextBid) {
|
|
486
|
+
newAsks.push(nextAsk);
|
|
487
|
+
askIndex++;
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (!nextAsk) {
|
|
492
|
+
newBids.push(nextBid);
|
|
493
|
+
bidIndex++;
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (nextBid.price.gt(nextAsk.price)) {
|
|
498
|
+
if (userBids.has(nextBid.price.toString())) {
|
|
499
|
+
newBids.push(nextBid);
|
|
500
|
+
bidIndex++;
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (userAsks.has(nextAsk.price.toString())) {
|
|
505
|
+
newAsks.push(nextAsk);
|
|
506
|
+
askIndex++;
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (
|
|
511
|
+
nextBid.price.gt(referencePrice) &&
|
|
512
|
+
nextAsk.price.gt(referencePrice)
|
|
513
|
+
) {
|
|
514
|
+
const newBidPrice = nextAsk.price.sub(grouping);
|
|
515
|
+
updateLevels(newBidPrice, nextBid, newBids);
|
|
516
|
+
bidIndex++;
|
|
517
|
+
} else if (
|
|
518
|
+
nextAsk.price.lt(referencePrice) &&
|
|
519
|
+
nextBid.price.lt(referencePrice)
|
|
520
|
+
) {
|
|
521
|
+
const newAskPrice = nextBid.price.add(grouping);
|
|
522
|
+
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
523
|
+
askIndex++;
|
|
524
|
+
} else {
|
|
525
|
+
const newBidPrice = referencePrice.sub(grouping);
|
|
526
|
+
const newAskPrice = referencePrice.add(grouping);
|
|
527
|
+
updateLevels(newBidPrice, nextBid, newBids);
|
|
528
|
+
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
529
|
+
bidIndex++;
|
|
530
|
+
askIndex++;
|
|
531
|
+
}
|
|
532
|
+
} else {
|
|
533
|
+
newAsks.push(nextAsk);
|
|
534
|
+
askIndex++;
|
|
535
|
+
|
|
536
|
+
newBids.push(nextBid);
|
|
537
|
+
bidIndex++;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return {
|
|
542
|
+
bids: newBids,
|
|
543
|
+
asks: newAsks,
|
|
544
|
+
};
|
|
545
|
+
}
|
package/src/driftClient.ts
CHANGED
|
@@ -1112,6 +1112,31 @@ export class DriftClient {
|
|
|
1112
1112
|
);
|
|
1113
1113
|
}
|
|
1114
1114
|
|
|
1115
|
+
public async deleteUser(
|
|
1116
|
+
subAccountId = 0,
|
|
1117
|
+
txParams?: TxParams
|
|
1118
|
+
): Promise<TransactionSignature> {
|
|
1119
|
+
const userAccountPublicKey = getUserAccountPublicKeySync(
|
|
1120
|
+
this.program.programId,
|
|
1121
|
+
this.wallet.publicKey,
|
|
1122
|
+
subAccountId
|
|
1123
|
+
);
|
|
1124
|
+
|
|
1125
|
+
const ix = await this.getUserDeletionIx(userAccountPublicKey);
|
|
1126
|
+
|
|
1127
|
+
const { txSig } = await this.sendTransaction(
|
|
1128
|
+
await this.buildTransaction(ix, txParams),
|
|
1129
|
+
[],
|
|
1130
|
+
this.opts
|
|
1131
|
+
);
|
|
1132
|
+
|
|
1133
|
+
const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
|
|
1134
|
+
await this.users.get(userMapKey)?.unsubscribe();
|
|
1135
|
+
this.users.delete(userMapKey);
|
|
1136
|
+
|
|
1137
|
+
return txSig;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1115
1140
|
public async getUserDeletionIx(userAccountPublicKey: PublicKey) {
|
|
1116
1141
|
const ix = await this.program.instruction.deleteUser({
|
|
1117
1142
|
accounts: {
|
|
@@ -1125,7 +1150,7 @@ export class DriftClient {
|
|
|
1125
1150
|
return ix;
|
|
1126
1151
|
}
|
|
1127
1152
|
|
|
1128
|
-
public async
|
|
1153
|
+
public async reclaimRent(
|
|
1129
1154
|
subAccountId = 0,
|
|
1130
1155
|
txParams?: TxParams
|
|
1131
1156
|
): Promise<TransactionSignature> {
|
|
@@ -1135,7 +1160,7 @@ export class DriftClient {
|
|
|
1135
1160
|
subAccountId
|
|
1136
1161
|
);
|
|
1137
1162
|
|
|
1138
|
-
const ix = await this.
|
|
1163
|
+
const ix = await this.getReclaimRentIx(userAccountPublicKey);
|
|
1139
1164
|
|
|
1140
1165
|
const { txSig } = await this.sendTransaction(
|
|
1141
1166
|
await this.buildTransaction(ix, txParams),
|
|
@@ -1143,13 +1168,21 @@ export class DriftClient {
|
|
|
1143
1168
|
this.opts
|
|
1144
1169
|
);
|
|
1145
1170
|
|
|
1146
|
-
const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
|
|
1147
|
-
await this.users.get(userMapKey)?.unsubscribe();
|
|
1148
|
-
this.users.delete(userMapKey);
|
|
1149
|
-
|
|
1150
1171
|
return txSig;
|
|
1151
1172
|
}
|
|
1152
1173
|
|
|
1174
|
+
public async getReclaimRentIx(userAccountPublicKey: PublicKey) {
|
|
1175
|
+
return await this.program.instruction.reclaimRent({
|
|
1176
|
+
accounts: {
|
|
1177
|
+
user: userAccountPublicKey,
|
|
1178
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
1179
|
+
authority: this.wallet.publicKey,
|
|
1180
|
+
state: await this.getStatePublicKey(),
|
|
1181
|
+
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
1182
|
+
},
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1153
1186
|
public getUser(subAccountId?: number, authority?: PublicKey): User {
|
|
1154
1187
|
subAccountId = subAccountId ?? this.activeSubAccountId;
|
|
1155
1188
|
authority = authority ?? this.authority;
|
|
@@ -3959,9 +3992,14 @@ export class DriftClient {
|
|
|
3959
3992
|
userAccountPublicKey || (await this.getUserAccountPublicKey());
|
|
3960
3993
|
|
|
3961
3994
|
const userAccounts = [];
|
|
3962
|
-
|
|
3963
|
-
|
|
3995
|
+
try {
|
|
3996
|
+
if (this.hasUser() && this.getUser().getUserAccountAndSlot()) {
|
|
3997
|
+
userAccounts.push(this.getUser().getUserAccountAndSlot()!.data);
|
|
3998
|
+
}
|
|
3999
|
+
} catch (err) {
|
|
4000
|
+
// ignore
|
|
3964
4001
|
}
|
|
4002
|
+
|
|
3965
4003
|
const remainingAccounts = this.getRemainingAccounts({
|
|
3966
4004
|
userAccounts,
|
|
3967
4005
|
writableSpotMarketIndexes: [outMarketIndex, inMarketIndex],
|
|
@@ -23,7 +23,7 @@ export class WebSocketLogProvider implements LogProvider {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public async subscribe(callback: logProviderCallback): Promise<boolean> {
|
|
26
|
-
if (this.subscriptionId) {
|
|
26
|
+
if (this.subscriptionId != null) {
|
|
27
27
|
return true;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -62,7 +62,7 @@ export class WebSocketLogProvider implements LogProvider {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
public isSubscribed(): boolean {
|
|
65
|
-
return this.subscriptionId
|
|
65
|
+
return this.subscriptionId != null;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
public async unsubscribe(external = false): Promise<boolean> {
|
|
@@ -71,7 +71,7 @@ export class WebSocketLogProvider implements LogProvider {
|
|
|
71
71
|
clearTimeout(this.timeoutId);
|
|
72
72
|
this.timeoutId = undefined;
|
|
73
73
|
|
|
74
|
-
if (this.subscriptionId
|
|
74
|
+
if (this.subscriptionId != null) {
|
|
75
75
|
try {
|
|
76
76
|
await this.connection.removeOnLogsListener(this.subscriptionId);
|
|
77
77
|
this.subscriptionId = undefined;
|
package/src/factory/bigNum.ts
CHANGED
|
@@ -497,7 +497,11 @@ export class BigNum {
|
|
|
497
497
|
return `${prefix}${val.replace('-', '')}`;
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
public toMillified(
|
|
500
|
+
public toMillified(
|
|
501
|
+
precision = 3,
|
|
502
|
+
rounded = false,
|
|
503
|
+
type: 'financial' | 'scientific' = 'financial'
|
|
504
|
+
): string {
|
|
501
505
|
if (rounded) {
|
|
502
506
|
return this.toRounded(precision).toMillified(precision);
|
|
503
507
|
}
|
|
@@ -520,7 +524,12 @@ export class BigNum {
|
|
|
520
524
|
return this.shift(new BN(precision)).toPrecision(precision, true);
|
|
521
525
|
}
|
|
522
526
|
|
|
523
|
-
const unitTicks =
|
|
527
|
+
const unitTicks =
|
|
528
|
+
type === 'financial'
|
|
529
|
+
? ['', 'K', 'M', 'B', 'T', 'Q']
|
|
530
|
+
: ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
|
|
531
|
+
// TODO -- handle nubers which are larger than the max unit tick
|
|
532
|
+
|
|
524
533
|
const unitNumber = Math.floor((leftSide.length - 1) / 3);
|
|
525
534
|
const unit = unitTicks[unitNumber];
|
|
526
535
|
|
package/src/idl/drift.json
CHANGED
|
@@ -1173,6 +1173,37 @@
|
|
|
1173
1173
|
],
|
|
1174
1174
|
"args": []
|
|
1175
1175
|
},
|
|
1176
|
+
{
|
|
1177
|
+
"name": "reclaimRent",
|
|
1178
|
+
"accounts": [
|
|
1179
|
+
{
|
|
1180
|
+
"name": "user",
|
|
1181
|
+
"isMut": true,
|
|
1182
|
+
"isSigner": false
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
"name": "userStats",
|
|
1186
|
+
"isMut": true,
|
|
1187
|
+
"isSigner": false
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
"name": "state",
|
|
1191
|
+
"isMut": false,
|
|
1192
|
+
"isSigner": false
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
"name": "authority",
|
|
1196
|
+
"isMut": false,
|
|
1197
|
+
"isSigner": true
|
|
1198
|
+
},
|
|
1199
|
+
{
|
|
1200
|
+
"name": "rent",
|
|
1201
|
+
"isMut": false,
|
|
1202
|
+
"isSigner": false
|
|
1203
|
+
}
|
|
1204
|
+
],
|
|
1205
|
+
"args": []
|
|
1206
|
+
},
|
|
1176
1207
|
{
|
|
1177
1208
|
"name": "fillPerpOrder",
|
|
1178
1209
|
"accounts": [
|
|
@@ -7343,12 +7374,24 @@
|
|
|
7343
7374
|
"name": "totalFeeEarnedPerLp",
|
|
7344
7375
|
"type": "u64"
|
|
7345
7376
|
},
|
|
7377
|
+
{
|
|
7378
|
+
"name": "netUnsettledFundingPnl",
|
|
7379
|
+
"type": "i64"
|
|
7380
|
+
},
|
|
7381
|
+
{
|
|
7382
|
+
"name": "quoteAssetAmountWithUnsettledLp",
|
|
7383
|
+
"type": "i64"
|
|
7384
|
+
},
|
|
7385
|
+
{
|
|
7386
|
+
"name": "referencePriceOffset",
|
|
7387
|
+
"type": "i32"
|
|
7388
|
+
},
|
|
7346
7389
|
{
|
|
7347
7390
|
"name": "padding",
|
|
7348
7391
|
"type": {
|
|
7349
7392
|
"array": [
|
|
7350
7393
|
"u8",
|
|
7351
|
-
|
|
7394
|
+
12
|
|
7352
7395
|
]
|
|
7353
7396
|
}
|
|
7354
7397
|
}
|
|
@@ -8232,6 +8275,9 @@
|
|
|
8232
8275
|
},
|
|
8233
8276
|
{
|
|
8234
8277
|
"name": "Transfer"
|
|
8278
|
+
},
|
|
8279
|
+
{
|
|
8280
|
+
"name": "Borrow"
|
|
8235
8281
|
}
|
|
8236
8282
|
]
|
|
8237
8283
|
}
|
|
@@ -11124,6 +11170,11 @@
|
|
|
11124
11170
|
"code": 6256,
|
|
11125
11171
|
"name": "CantPayUserInitFee",
|
|
11126
11172
|
"msg": "CantPayUserInitFee"
|
|
11173
|
+
},
|
|
11174
|
+
{
|
|
11175
|
+
"code": 6257,
|
|
11176
|
+
"name": "CantReclaimRent",
|
|
11177
|
+
"msg": "CantReclaimRent"
|
|
11127
11178
|
}
|
|
11128
11179
|
]
|
|
11129
11180
|
}
|
package/src/index.ts
CHANGED
|
@@ -69,7 +69,7 @@ export * from './constants/numericConstants';
|
|
|
69
69
|
export * from './serum/serumSubscriber';
|
|
70
70
|
export * from './serum/serumFulfillmentConfigMap';
|
|
71
71
|
export * from './phoenix/phoenixSubscriber';
|
|
72
|
-
export * from './priorityFee
|
|
72
|
+
export * from './priorityFee';
|
|
73
73
|
export * from './phoenix/phoenixFulfillmentConfigMap';
|
|
74
74
|
export * from './tx/fastSingleTxSender';
|
|
75
75
|
export * from './tx/retryTxSender';
|