@drift-labs/sdk 2.49.0-beta.1 → 2.49.0-beta.11
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} +2 -2
- package/lib/accounts/{mockUserAccountSubscriber.js → basicUserAccountSubscriber.js} +9 -6
- package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts +29 -0
- package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +110 -0
- package/lib/accounts/types.d.ts +14 -1
- package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +23 -0
- package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +65 -0
- package/lib/dlob/DLOB.d.ts +6 -2
- package/lib/dlob/DLOB.js +37 -12
- package/lib/driftClient.d.ts +66 -66
- package/lib/driftClient.js +208 -194
- package/lib/events/eventSubscriber.js +2 -1
- package/lib/events/sort.d.ts +2 -2
- package/lib/events/sort.js +6 -23
- package/lib/examples/loadDlob.js +10 -5
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/math/superStake.d.ts +43 -0
- package/lib/math/superStake.js +64 -22
- package/lib/orderSubscriber/OrderSubscriber.js +4 -0
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +1 -1
- package/lib/orderSubscriber/WebsocketSubscription.js +8 -6
- package/lib/types.d.ts +0 -2
- package/lib/userMap/PollingSubscription.d.ts +15 -0
- package/lib/userMap/PollingSubscription.js +26 -0
- package/lib/userMap/WebsocketSubscription.d.ts +19 -0
- package/lib/userMap/WebsocketSubscription.js +40 -0
- package/lib/userMap/userMap.d.ts +15 -18
- package/lib/userMap/userMap.js +62 -31
- package/lib/userMap/userMapConfig.d.ts +20 -0
- package/lib/userMap/userMapConfig.js +2 -0
- package/package.json +1 -1
- package/src/accounts/{mockUserAccountSubscriber.ts → basicUserAccountSubscriber.ts} +8 -6
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +185 -0
- package/src/accounts/types.ts +21 -0
- package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +127 -0
- package/src/dlob/DLOB.ts +55 -15
- package/src/driftClient.ts +429 -272
- package/src/events/eventSubscriber.ts +2 -1
- package/src/events/sort.ts +7 -29
- package/src/examples/loadDlob.ts +11 -6
- package/src/index.ts +3 -1
- package/src/math/superStake.ts +108 -20
- package/src/orderSubscriber/OrderSubscriber.ts +4 -0
- package/src/orderSubscriber/WebsocketSubscription.ts +19 -16
- package/src/types.ts +0 -2
- package/src/userMap/PollingSubscription.ts +46 -0
- package/src/userMap/WebsocketSubscription.ts +74 -0
- package/src/userMap/userMap.ts +88 -60
- package/src/userMap/userMapConfig.ts +31 -0
- package/tests/amm/test.ts +6 -3
- package/tests/dlob/helpers.ts +2 -6
- package/tests/dlob/test.ts +194 -0
package/src/userMap/userMap.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
DriftClient,
|
|
4
4
|
UserAccount,
|
|
5
5
|
OrderRecord,
|
|
6
|
-
UserSubscriptionConfig,
|
|
7
6
|
WrappedEvent,
|
|
8
7
|
DepositRecord,
|
|
9
8
|
FundingPaymentRecord,
|
|
@@ -14,11 +13,24 @@ import {
|
|
|
14
13
|
LPRecord,
|
|
15
14
|
StateAccount,
|
|
16
15
|
DLOB,
|
|
16
|
+
BasicUserAccountSubscriber,
|
|
17
|
+
BN,
|
|
17
18
|
} from '..';
|
|
18
19
|
|
|
19
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
Commitment,
|
|
22
|
+
Connection,
|
|
23
|
+
PublicKey,
|
|
24
|
+
RpcResponseAndContext,
|
|
25
|
+
} from '@solana/web3.js';
|
|
20
26
|
import { Buffer } from 'buffer';
|
|
21
27
|
import { getNonIdleUserFilter, getUserFilter } from '../memcmp';
|
|
28
|
+
import {
|
|
29
|
+
UserAccountFilterCriteria as UserFilterCriteria,
|
|
30
|
+
UserMapConfig,
|
|
31
|
+
} from './userMapConfig';
|
|
32
|
+
import { WebsocketSubscription } from './WebsocketSubscription';
|
|
33
|
+
import { PollingSubscription } from './PollingSubscription';
|
|
22
34
|
|
|
23
35
|
export interface UserMapInterface {
|
|
24
36
|
subscribe(): Promise<void>;
|
|
@@ -32,59 +44,51 @@ export interface UserMapInterface {
|
|
|
32
44
|
values(): IterableIterator<User>;
|
|
33
45
|
}
|
|
34
46
|
|
|
35
|
-
// filter users that meet these criteria when passing into syncCallback
|
|
36
|
-
export type SyncCallbackCriteria = {
|
|
37
|
-
// only sync users that have open orders
|
|
38
|
-
hasOpenOrders: boolean;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
47
|
export class UserMap implements UserMapInterface {
|
|
42
48
|
private userMap = new Map<string, User>();
|
|
43
|
-
|
|
44
|
-
private
|
|
49
|
+
driftClient: DriftClient;
|
|
50
|
+
private connection: Connection;
|
|
51
|
+
private commitment: Commitment;
|
|
45
52
|
private includeIdle: boolean;
|
|
46
|
-
private lastNumberOfSubAccounts;
|
|
53
|
+
private lastNumberOfSubAccounts: BN;
|
|
54
|
+
private subscription: PollingSubscription | WebsocketSubscription;
|
|
47
55
|
private stateAccountUpdateCallback = async (state: StateAccount) => {
|
|
48
|
-
if (state.numberOfSubAccounts
|
|
56
|
+
if (!state.numberOfSubAccounts.eq(this.lastNumberOfSubAccounts)) {
|
|
49
57
|
await this.sync();
|
|
50
58
|
this.lastNumberOfSubAccounts = state.numberOfSubAccounts;
|
|
51
59
|
}
|
|
52
60
|
};
|
|
53
|
-
private syncCallback: (authorities: PublicKey[]) => Promise<void>;
|
|
54
|
-
private syncCallbackCriteria: SyncCallbackCriteria;
|
|
55
61
|
|
|
56
62
|
private syncPromise?: Promise<void>;
|
|
57
63
|
private syncPromiseResolver: () => void;
|
|
58
64
|
|
|
59
65
|
/**
|
|
60
66
|
* Constructs a new UserMap instance.
|
|
61
|
-
*
|
|
62
|
-
* @param {DriftClient} driftClient - The DriftClient instance.
|
|
63
|
-
* @param {UserSubscriptionConfig} accountSubscription - The UserSubscriptionConfig instance.
|
|
64
|
-
* @param {boolean} includeIdle - Whether idle users are subscribed to. Defaults to false to decrease # of user subscriptions.
|
|
65
|
-
* @param {(authorities: PublicKey[]) => Promise<void>} syncCallback - Called after `sync` completes, will pas in unique list of authorities. Useful for using it to sync UserStatsMap.
|
|
66
|
-
* @param {SyncCallbackCriteria} syncCallbackCriteria - The criteria for the sync callback. Defaults to having no filters
|
|
67
67
|
*/
|
|
68
|
-
constructor(
|
|
69
|
-
driftClient
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.
|
|
76
|
-
|
|
77
|
-
this.includeIdle = includeIdle;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
68
|
+
constructor(config: UserMapConfig) {
|
|
69
|
+
this.driftClient = config.driftClient;
|
|
70
|
+
if (config.connection) {
|
|
71
|
+
this.connection = config.connection;
|
|
72
|
+
} else {
|
|
73
|
+
this.connection = this.driftClient.connection;
|
|
74
|
+
}
|
|
75
|
+
this.commitment =
|
|
76
|
+
config.subscriptionConfig.commitment ?? this.driftClient.opts.commitment;
|
|
77
|
+
this.includeIdle = config.includeIdle ?? false;
|
|
78
|
+
if (config.subscriptionConfig.type === 'polling') {
|
|
79
|
+
this.subscription = new PollingSubscription({
|
|
80
|
+
userMap: this,
|
|
81
|
+
frequency: config.subscriptionConfig.frequency,
|
|
82
|
+
skipInitialLoad: config.skipInitialLoad,
|
|
83
|
+
});
|
|
84
|
+
} else {
|
|
85
|
+
this.subscription = new WebsocketSubscription({
|
|
86
|
+
userMap: this,
|
|
87
|
+
commitment: this.commitment,
|
|
88
|
+
resubTimeoutMs: config.subscriptionConfig.resubTimeoutMs,
|
|
89
|
+
skipInitialLoad: config.skipInitialLoad,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
public async subscribe() {
|
|
@@ -100,17 +104,25 @@ export class UserMap implements UserMapInterface {
|
|
|
100
104
|
this.stateAccountUpdateCallback
|
|
101
105
|
);
|
|
102
106
|
|
|
103
|
-
await this.
|
|
107
|
+
await this.subscription.subscribe();
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
public async addPubkey(
|
|
107
111
|
userAccountPublicKey: PublicKey,
|
|
108
|
-
userAccount?: UserAccount
|
|
112
|
+
userAccount?: UserAccount,
|
|
113
|
+
slot?: number
|
|
109
114
|
) {
|
|
110
115
|
const user = new User({
|
|
111
116
|
driftClient: this.driftClient,
|
|
112
117
|
userAccountPublicKey,
|
|
113
|
-
accountSubscription:
|
|
118
|
+
accountSubscription: {
|
|
119
|
+
type: 'custom',
|
|
120
|
+
userAccountSubscriber: new BasicUserAccountSubscriber(
|
|
121
|
+
userAccountPublicKey,
|
|
122
|
+
userAccount,
|
|
123
|
+
slot
|
|
124
|
+
),
|
|
125
|
+
},
|
|
114
126
|
});
|
|
115
127
|
await user.subscribe(userAccount);
|
|
116
128
|
this.userMap.set(userAccountPublicKey.toString(), user);
|
|
@@ -216,14 +228,18 @@ export class UserMap implements UserMapInterface {
|
|
|
216
228
|
return this.userMap.size;
|
|
217
229
|
}
|
|
218
230
|
|
|
219
|
-
|
|
231
|
+
/**
|
|
232
|
+
* Returns a unique list of authorities for all users in the UserMap that meet the filter criteria
|
|
233
|
+
* @param filterCriteria: Users must meet these criteria to be included
|
|
234
|
+
* @returns
|
|
235
|
+
*/
|
|
236
|
+
public getUniqueAuthorities(
|
|
237
|
+
filterCriteria?: UserFilterCriteria
|
|
238
|
+
): PublicKey[] {
|
|
220
239
|
const usersMeetingCriteria = Array.from(this.userMap.values()).filter(
|
|
221
240
|
(user) => {
|
|
222
241
|
let pass = true;
|
|
223
|
-
if (
|
|
224
|
-
useSyncCallbackCriteria &&
|
|
225
|
-
this.syncCallbackCriteria.hasOpenOrders
|
|
226
|
-
) {
|
|
242
|
+
if (filterCriteria && filterCriteria.hasOpenOrders) {
|
|
227
243
|
pass = pass && user.getUserAccount().hasOpenOrder;
|
|
228
244
|
}
|
|
229
245
|
return pass;
|
|
@@ -257,7 +273,7 @@ export class UserMap implements UserMapInterface {
|
|
|
257
273
|
const rpcRequestArgs = [
|
|
258
274
|
this.driftClient.program.programId.toBase58(),
|
|
259
275
|
{
|
|
260
|
-
commitment: this.
|
|
276
|
+
commitment: this.commitment,
|
|
261
277
|
filters,
|
|
262
278
|
encoding: 'base64',
|
|
263
279
|
withContext: true,
|
|
@@ -266,10 +282,7 @@ export class UserMap implements UserMapInterface {
|
|
|
266
282
|
|
|
267
283
|
const rpcJSONResponse: any =
|
|
268
284
|
// @ts-ignore
|
|
269
|
-
await this.
|
|
270
|
-
'getProgramAccounts',
|
|
271
|
-
rpcRequestArgs
|
|
272
|
-
);
|
|
285
|
+
await this.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
|
|
273
286
|
|
|
274
287
|
const rpcResponseAndContext: RpcResponseAndContext<
|
|
275
288
|
Array<{
|
|
@@ -297,12 +310,14 @@ export class UserMap implements UserMapInterface {
|
|
|
297
310
|
for (const [key, buffer] of programAccountBufferMap.entries()) {
|
|
298
311
|
if (!this.has(key)) {
|
|
299
312
|
const userAccount =
|
|
300
|
-
this.driftClient.program.account.user.coder.accounts.
|
|
313
|
+
this.driftClient.program.account.user.coder.accounts.decodeUnchecked(
|
|
301
314
|
'User',
|
|
302
315
|
buffer
|
|
303
316
|
);
|
|
304
317
|
await this.addPubkey(new PublicKey(key), userAccount);
|
|
305
318
|
}
|
|
319
|
+
// give event loop a chance to breathe
|
|
320
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
306
321
|
}
|
|
307
322
|
|
|
308
323
|
for (const [key, user] of this.userMap.entries()) {
|
|
@@ -311,19 +326,17 @@ export class UserMap implements UserMapInterface {
|
|
|
311
326
|
this.userMap.delete(key);
|
|
312
327
|
} else {
|
|
313
328
|
const userAccount =
|
|
314
|
-
this.driftClient.program.account.user.coder.accounts.
|
|
329
|
+
this.driftClient.program.account.user.coder.accounts.decodeUnchecked(
|
|
315
330
|
'User',
|
|
316
331
|
programAccountBufferMap.get(key)
|
|
317
332
|
);
|
|
318
333
|
user.accountSubscriber.updateData(userAccount, slot);
|
|
319
334
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (this.syncCallback) {
|
|
323
|
-
await this.syncCallback(this.getUniqueAuthorities());
|
|
335
|
+
// give event loop a chance to breathe
|
|
336
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
324
337
|
}
|
|
325
338
|
} catch (e) {
|
|
326
|
-
console.error(`Error in UserMap.sync()
|
|
339
|
+
console.error(`Error in UserMap.sync():`);
|
|
327
340
|
console.error(e);
|
|
328
341
|
} finally {
|
|
329
342
|
this.syncPromiseResolver();
|
|
@@ -332,6 +345,8 @@ export class UserMap implements UserMapInterface {
|
|
|
332
345
|
}
|
|
333
346
|
|
|
334
347
|
public async unsubscribe() {
|
|
348
|
+
await this.subscription.unsubscribe();
|
|
349
|
+
|
|
335
350
|
for (const [key, user] of this.userMap.entries()) {
|
|
336
351
|
await user.unsubscribe();
|
|
337
352
|
this.userMap.delete(key);
|
|
@@ -345,4 +360,17 @@ export class UserMap implements UserMapInterface {
|
|
|
345
360
|
this.lastNumberOfSubAccounts = undefined;
|
|
346
361
|
}
|
|
347
362
|
}
|
|
363
|
+
|
|
364
|
+
public async updateUserAccount(
|
|
365
|
+
key: string,
|
|
366
|
+
userAccount: UserAccount,
|
|
367
|
+
slot: number
|
|
368
|
+
) {
|
|
369
|
+
if (!this.userMap.has(key)) {
|
|
370
|
+
this.addPubkey(new PublicKey(key), userAccount, slot);
|
|
371
|
+
} else {
|
|
372
|
+
const user = this.userMap.get(key);
|
|
373
|
+
user.accountSubscriber.updateData(userAccount, slot);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
348
376
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Commitment, Connection } from '@solana/web3.js';
|
|
2
|
+
import { DriftClient } from '../driftClient';
|
|
3
|
+
|
|
4
|
+
// passed into UserMap.getUniqueAuthorities to filter users
|
|
5
|
+
export type UserAccountFilterCriteria = {
|
|
6
|
+
// only return users that have open orders
|
|
7
|
+
hasOpenOrders: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type UserMapConfig = {
|
|
11
|
+
driftClient: DriftClient;
|
|
12
|
+
// connection object to use specifically for the UserMap. If undefined, will use the driftClient's connection
|
|
13
|
+
connection?: Connection;
|
|
14
|
+
subscriptionConfig:
|
|
15
|
+
| {
|
|
16
|
+
type: 'polling';
|
|
17
|
+
frequency: number;
|
|
18
|
+
commitment?: Commitment;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
type: 'websocket';
|
|
22
|
+
resubTimeoutMs?: number;
|
|
23
|
+
commitment?: Commitment;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// True to skip the initial load of userAccounts via getProgramAccounts
|
|
27
|
+
skipInitialLoad?: boolean;
|
|
28
|
+
|
|
29
|
+
// True to include idle users when loading. Defaults to false to decrease # of accounts subscribed to.
|
|
30
|
+
includeIdle?: boolean;
|
|
31
|
+
};
|
package/tests/amm/test.ts
CHANGED
|
@@ -361,7 +361,10 @@ describe('AMM Tests', () => {
|
|
|
361
361
|
|
|
362
362
|
console.log(terms2);
|
|
363
363
|
assert(terms2.effectiveLeverageCapped <= 1.000001);
|
|
364
|
-
assert(
|
|
364
|
+
assert(
|
|
365
|
+
terms2.inventorySpreadScale == 1.013527,
|
|
366
|
+
`got: ${terms2.inventorySpreadScale}`
|
|
367
|
+
);
|
|
365
368
|
assert(terms2.longSpread == 1146);
|
|
366
369
|
assert(terms2.shortSpread == 6686);
|
|
367
370
|
});
|
|
@@ -466,7 +469,7 @@ describe('AMM Tests', () => {
|
|
|
466
469
|
|
|
467
470
|
assert(markTwapLive.eq(new BN('1949826')));
|
|
468
471
|
assert(oracleTwapLive.eq(new BN('1942510')));
|
|
469
|
-
assert(est1.eq(new BN('15692')));
|
|
472
|
+
assert(est1.eq(new BN('15692')), `got: ${est1}`);
|
|
470
473
|
assert(est2.eq(new BN('15692')));
|
|
471
474
|
});
|
|
472
475
|
|
|
@@ -556,7 +559,7 @@ describe('AMM Tests', () => {
|
|
|
556
559
|
assert(markTwapLive.eq(new BN('1222131')));
|
|
557
560
|
assert(oracleTwapLive.eq(new BN('1222586')));
|
|
558
561
|
assert(est1.eq(est2));
|
|
559
|
-
assert(est2.eq(new BN('-1550')));
|
|
562
|
+
assert(est2.eq(new BN('-1550')), `got: ${est2}`);
|
|
560
563
|
});
|
|
561
564
|
|
|
562
565
|
it('orderbook L2 gen (no topOfBookQuoteAmounts, 10 numOrders, low liquidity)', async () => {
|
package/tests/dlob/helpers.ts
CHANGED
|
@@ -539,15 +539,13 @@ export const mockStateAccount: StateAccount = {
|
|
|
539
539
|
feeNumerator: 0,
|
|
540
540
|
feeDenominator: 0,
|
|
541
541
|
makerRebateNumerator: 0,
|
|
542
|
-
makerRebateDenominator:
|
|
542
|
+
makerRebateDenominator: 1,
|
|
543
543
|
referrerRewardNumerator: 0,
|
|
544
544
|
referrerRewardDenominator: 0,
|
|
545
545
|
refereeFeeNumerator: 0,
|
|
546
546
|
refereeFeeDenominator: 0,
|
|
547
547
|
},
|
|
548
548
|
],
|
|
549
|
-
makerRebateNumerator: new BN(0),
|
|
550
|
-
makerRebateDenominator: new BN(0),
|
|
551
549
|
fillerRewardStructure: {
|
|
552
550
|
rewardNumerator: new BN(0),
|
|
553
551
|
rewardDenominator: new BN(0),
|
|
@@ -565,15 +563,13 @@ export const mockStateAccount: StateAccount = {
|
|
|
565
563
|
feeNumerator: 0,
|
|
566
564
|
feeDenominator: 0,
|
|
567
565
|
makerRebateNumerator: 0,
|
|
568
|
-
makerRebateDenominator:
|
|
566
|
+
makerRebateDenominator: 1,
|
|
569
567
|
referrerRewardNumerator: 0,
|
|
570
568
|
referrerRewardDenominator: 0,
|
|
571
569
|
refereeFeeNumerator: 0,
|
|
572
570
|
refereeFeeDenominator: 0,
|
|
573
571
|
},
|
|
574
572
|
],
|
|
575
|
-
makerRebateNumerator: new BN(0),
|
|
576
|
-
makerRebateDenominator: new BN(0),
|
|
577
573
|
fillerRewardStructure: {
|
|
578
574
|
rewardNumerator: new BN(0),
|
|
579
575
|
rewardDenominator: new BN(0),
|
package/tests/dlob/test.ts
CHANGED
|
@@ -1914,6 +1914,8 @@ describe('DLOB Perp Tests', () => {
|
|
|
1914
1914
|
},
|
|
1915
1915
|
false,
|
|
1916
1916
|
10,
|
|
1917
|
+
0,
|
|
1918
|
+
1,
|
|
1917
1919
|
undefined,
|
|
1918
1920
|
undefined
|
|
1919
1921
|
);
|
|
@@ -2059,6 +2061,8 @@ describe('DLOB Perp Tests', () => {
|
|
|
2059
2061
|
},
|
|
2060
2062
|
false,
|
|
2061
2063
|
10,
|
|
2064
|
+
0,
|
|
2065
|
+
1,
|
|
2062
2066
|
undefined,
|
|
2063
2067
|
undefined
|
|
2064
2068
|
);
|
|
@@ -2267,6 +2271,194 @@ describe('DLOB Perp Tests', () => {
|
|
|
2267
2271
|
expect(nodesToFillAfter[1].makerNodes[0]?.order?.orderId).to.equal(3);
|
|
2268
2272
|
});
|
|
2269
2273
|
|
|
2274
|
+
it('Test post only bid fills against fallback', async () => {
|
|
2275
|
+
const vAsk = new BN(150);
|
|
2276
|
+
const vBid = new BN(100);
|
|
2277
|
+
|
|
2278
|
+
const user0 = Keypair.generate();
|
|
2279
|
+
|
|
2280
|
+
const dlob = new DLOB();
|
|
2281
|
+
const marketIndex = 0;
|
|
2282
|
+
|
|
2283
|
+
const makerRebateNumerator = 1;
|
|
2284
|
+
const makerRebateDenominator = 10;
|
|
2285
|
+
|
|
2286
|
+
// post only bid same as ask
|
|
2287
|
+
insertOrderToDLOB(
|
|
2288
|
+
dlob,
|
|
2289
|
+
user0.publicKey,
|
|
2290
|
+
OrderType.LIMIT,
|
|
2291
|
+
MarketType.PERP,
|
|
2292
|
+
1, // orderId
|
|
2293
|
+
marketIndex,
|
|
2294
|
+
vAsk, // same price as vAsk
|
|
2295
|
+
BASE_PRECISION, // quantity
|
|
2296
|
+
PositionDirection.LONG,
|
|
2297
|
+
vBid,
|
|
2298
|
+
vAsk,
|
|
2299
|
+
undefined,
|
|
2300
|
+
undefined,
|
|
2301
|
+
undefined,
|
|
2302
|
+
true
|
|
2303
|
+
);
|
|
2304
|
+
|
|
2305
|
+
// should have no crossing orders
|
|
2306
|
+
const nodesToFillBefore = dlob.findRestingLimitOrderNodesToFill(
|
|
2307
|
+
marketIndex,
|
|
2308
|
+
12, // auction over
|
|
2309
|
+
MarketType.PERP,
|
|
2310
|
+
{
|
|
2311
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2312
|
+
slot: new BN(12),
|
|
2313
|
+
confidence: new BN(1),
|
|
2314
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2315
|
+
},
|
|
2316
|
+
false,
|
|
2317
|
+
10,
|
|
2318
|
+
makerRebateNumerator,
|
|
2319
|
+
makerRebateDenominator,
|
|
2320
|
+
vAsk,
|
|
2321
|
+
vBid
|
|
2322
|
+
);
|
|
2323
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
2324
|
+
|
|
2325
|
+
// post only bid crosses ask
|
|
2326
|
+
const price = vAsk.add(
|
|
2327
|
+
vAsk.muln(makerRebateNumerator).divn(makerRebateDenominator)
|
|
2328
|
+
);
|
|
2329
|
+
insertOrderToDLOB(
|
|
2330
|
+
dlob,
|
|
2331
|
+
user0.publicKey,
|
|
2332
|
+
OrderType.LIMIT,
|
|
2333
|
+
MarketType.PERP,
|
|
2334
|
+
2, // orderId
|
|
2335
|
+
marketIndex,
|
|
2336
|
+
price, // crosses vask
|
|
2337
|
+
BASE_PRECISION, // quantity
|
|
2338
|
+
PositionDirection.LONG,
|
|
2339
|
+
vBid,
|
|
2340
|
+
vAsk,
|
|
2341
|
+
undefined,
|
|
2342
|
+
undefined,
|
|
2343
|
+
undefined,
|
|
2344
|
+
true
|
|
2345
|
+
);
|
|
2346
|
+
|
|
2347
|
+
// should have no crossing orders
|
|
2348
|
+
const nodesToFillAfter = dlob.findRestingLimitOrderNodesToFill(
|
|
2349
|
+
marketIndex,
|
|
2350
|
+
12, // auction over
|
|
2351
|
+
MarketType.PERP,
|
|
2352
|
+
{
|
|
2353
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2354
|
+
slot: new BN(12),
|
|
2355
|
+
confidence: new BN(1),
|
|
2356
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2357
|
+
},
|
|
2358
|
+
false,
|
|
2359
|
+
10,
|
|
2360
|
+
makerRebateNumerator,
|
|
2361
|
+
makerRebateDenominator,
|
|
2362
|
+
vAsk,
|
|
2363
|
+
vBid
|
|
2364
|
+
);
|
|
2365
|
+
expect(nodesToFillAfter.length).to.equal(1);
|
|
2366
|
+
});
|
|
2367
|
+
|
|
2368
|
+
it('Test post only ask fills against fallback', async () => {
|
|
2369
|
+
const vAsk = new BN(150);
|
|
2370
|
+
const vBid = new BN(100);
|
|
2371
|
+
|
|
2372
|
+
const user0 = Keypair.generate();
|
|
2373
|
+
|
|
2374
|
+
const dlob = new DLOB();
|
|
2375
|
+
const marketIndex = 0;
|
|
2376
|
+
|
|
2377
|
+
const makerRebateNumerator = 1;
|
|
2378
|
+
const makerRebateDenominator = 10;
|
|
2379
|
+
|
|
2380
|
+
// post only bid same as ask
|
|
2381
|
+
insertOrderToDLOB(
|
|
2382
|
+
dlob,
|
|
2383
|
+
user0.publicKey,
|
|
2384
|
+
OrderType.LIMIT,
|
|
2385
|
+
MarketType.PERP,
|
|
2386
|
+
1, // orderId
|
|
2387
|
+
marketIndex,
|
|
2388
|
+
vBid, // same price as vAsk
|
|
2389
|
+
BASE_PRECISION, // quantity
|
|
2390
|
+
PositionDirection.SHORT,
|
|
2391
|
+
vBid,
|
|
2392
|
+
vAsk,
|
|
2393
|
+
undefined,
|
|
2394
|
+
undefined,
|
|
2395
|
+
undefined,
|
|
2396
|
+
true
|
|
2397
|
+
);
|
|
2398
|
+
|
|
2399
|
+
// should have no crossing orders
|
|
2400
|
+
const nodesToFillBefore = dlob.findRestingLimitOrderNodesToFill(
|
|
2401
|
+
marketIndex,
|
|
2402
|
+
12, // auction over
|
|
2403
|
+
MarketType.PERP,
|
|
2404
|
+
{
|
|
2405
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2406
|
+
slot: new BN(12),
|
|
2407
|
+
confidence: new BN(1),
|
|
2408
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2409
|
+
},
|
|
2410
|
+
false,
|
|
2411
|
+
10,
|
|
2412
|
+
makerRebateNumerator,
|
|
2413
|
+
makerRebateDenominator,
|
|
2414
|
+
vAsk,
|
|
2415
|
+
vBid
|
|
2416
|
+
);
|
|
2417
|
+
expect(nodesToFillBefore.length).to.equal(0);
|
|
2418
|
+
|
|
2419
|
+
// post only bid crosses ask
|
|
2420
|
+
const price = vBid.sub(
|
|
2421
|
+
vAsk.muln(makerRebateNumerator).divn(makerRebateDenominator)
|
|
2422
|
+
);
|
|
2423
|
+
insertOrderToDLOB(
|
|
2424
|
+
dlob,
|
|
2425
|
+
user0.publicKey,
|
|
2426
|
+
OrderType.LIMIT,
|
|
2427
|
+
MarketType.PERP,
|
|
2428
|
+
2, // orderId
|
|
2429
|
+
marketIndex,
|
|
2430
|
+
price, // crosses vask
|
|
2431
|
+
BASE_PRECISION, // quantity
|
|
2432
|
+
PositionDirection.SHORT,
|
|
2433
|
+
vBid,
|
|
2434
|
+
vAsk,
|
|
2435
|
+
undefined,
|
|
2436
|
+
undefined,
|
|
2437
|
+
undefined,
|
|
2438
|
+
true
|
|
2439
|
+
);
|
|
2440
|
+
|
|
2441
|
+
// should have no crossing orders
|
|
2442
|
+
const nodesToFillAfter = dlob.findRestingLimitOrderNodesToFill(
|
|
2443
|
+
marketIndex,
|
|
2444
|
+
12, // auction over
|
|
2445
|
+
MarketType.PERP,
|
|
2446
|
+
{
|
|
2447
|
+
price: vBid.add(vAsk).div(new BN(2)),
|
|
2448
|
+
slot: new BN(12),
|
|
2449
|
+
confidence: new BN(1),
|
|
2450
|
+
hasSufficientNumberOfDataPoints: true,
|
|
2451
|
+
},
|
|
2452
|
+
false,
|
|
2453
|
+
10,
|
|
2454
|
+
makerRebateNumerator,
|
|
2455
|
+
makerRebateDenominator,
|
|
2456
|
+
vAsk,
|
|
2457
|
+
vBid
|
|
2458
|
+
);
|
|
2459
|
+
expect(nodesToFillAfter.length).to.equal(1);
|
|
2460
|
+
});
|
|
2461
|
+
|
|
2270
2462
|
it('Test trigger orders', () => {
|
|
2271
2463
|
const vAsk = new BN(15);
|
|
2272
2464
|
const vBid = new BN(8);
|
|
@@ -2901,6 +3093,8 @@ describe('DLOB Perp Tests', () => {
|
|
|
2901
3093
|
oracle,
|
|
2902
3094
|
false,
|
|
2903
3095
|
10,
|
|
3096
|
+
0,
|
|
3097
|
+
1,
|
|
2904
3098
|
undefined,
|
|
2905
3099
|
undefined
|
|
2906
3100
|
);
|