@drift-labs/sdk 2.112.0-beta.2 → 2.112.0-beta.4

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.
Files changed (33) hide show
  1. package/VERSION +1 -1
  2. package/lib/browser/dlob/DLOB.js +8 -1
  3. package/lib/browser/fastlane/grpcSignedMsgUserAccountSubscriber.d.ts +22 -0
  4. package/lib/browser/fastlane/grpcSignedMsgUserAccountSubscriber.js +57 -0
  5. package/lib/browser/fastlane/index.d.ts +3 -0
  6. package/lib/browser/fastlane/index.js +19 -0
  7. package/lib/browser/fastlane/signedMsgUserAccountSubscriber.d.ts +43 -0
  8. package/lib/browser/fastlane/signedMsgUserAccountSubscriber.js +116 -0
  9. package/lib/browser/index.d.ts +1 -0
  10. package/lib/browser/index.js +1 -0
  11. package/lib/browser/memcmp.d.ts +1 -0
  12. package/lib/browser/memcmp.js +10 -1
  13. package/lib/browser/types.d.ts +9 -0
  14. package/lib/node/dlob/DLOB.js +8 -1
  15. package/lib/node/fastlane/grpcSignedMsgUserAccountSubscriber.d.ts +22 -0
  16. package/lib/node/fastlane/grpcSignedMsgUserAccountSubscriber.js +57 -0
  17. package/lib/node/fastlane/index.d.ts +3 -0
  18. package/lib/node/fastlane/index.js +19 -0
  19. package/lib/node/fastlane/signedMsgUserAccountSubscriber.d.ts +43 -0
  20. package/lib/node/fastlane/signedMsgUserAccountSubscriber.js +116 -0
  21. package/lib/node/index.d.ts +1 -0
  22. package/lib/node/index.js +1 -0
  23. package/lib/node/memcmp.d.ts +1 -0
  24. package/lib/node/memcmp.js +10 -1
  25. package/lib/node/types.d.ts +9 -0
  26. package/package.json +1 -1
  27. package/src/dlob/DLOB.ts +9 -1
  28. package/src/fastlane/grpcSignedMsgUserAccountSubscriber.ts +95 -0
  29. package/src/fastlane/index.ts +3 -0
  30. package/src/fastlane/signedMsgUserAccountSubscriber.ts +234 -0
  31. package/src/index.ts +1 -0
  32. package/src/memcmp.ts +11 -0
  33. package/src/types.ts +11 -0
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.112.0-beta.2
1
+ 2.112.0-beta.4
@@ -478,7 +478,14 @@ class DLOB {
478
478
  }
479
479
  for (const askGenerator of askGenerators) {
480
480
  for (const ask of askGenerator) {
481
- if ((0, __1.isOrderExpired)(ask.order, ts, true, 25)) {
481
+ if (ask.isSignedMsg &&
482
+ slot.gt(ask.order.slot.addn(ask.order.auctionDuration))) {
483
+ this.orderLists
484
+ .get(marketTypeStr)
485
+ .get(marketIndex)
486
+ .signedMsg.bid.remove(ask.order, ask.userAccount);
487
+ }
488
+ else if ((0, __1.isOrderExpired)(ask.order, ts, true, 25)) {
482
489
  nodesToFill.push({
483
490
  node: ask,
484
491
  makerNodes: [],
@@ -0,0 +1,22 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import { Commitment } from '@solana/web3.js';
4
+ import { grpcProgramAccountSubscriber } from '../accounts/grpcProgramAccountSubscriber';
5
+ import { GrpcConfigs, ResubOpts } from '../accounts/types';
6
+ import { SignedMsgUserOrdersAccount } from '../types';
7
+ import { SignedMsgUserOrdersAccountSubscriber } from './signedMsgUserAccountSubscriber';
8
+ import { DriftClient } from '../driftClient';
9
+ export declare class grpcSignedMsgUserOrdersAccountSubscriber extends SignedMsgUserOrdersAccountSubscriber {
10
+ private grpcConfigs;
11
+ subscriber: grpcProgramAccountSubscriber<SignedMsgUserOrdersAccount>;
12
+ constructor({ grpcConfigs, driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }: {
13
+ grpcConfigs: GrpcConfigs;
14
+ driftClient: DriftClient;
15
+ commitment: Commitment;
16
+ resubOpts?: ResubOpts;
17
+ decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
18
+ resyncIntervalMs?: number;
19
+ });
20
+ subscribe(): Promise<void>;
21
+ unsubscribe(): Promise<void>;
22
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grpcSignedMsgUserOrdersAccountSubscriber = void 0;
4
+ const grpcProgramAccountSubscriber_1 = require("../accounts/grpcProgramAccountSubscriber");
5
+ const memcmp_1 = require("../memcmp");
6
+ const signedMsgUserAccountSubscriber_1 = require("./signedMsgUserAccountSubscriber");
7
+ class grpcSignedMsgUserOrdersAccountSubscriber extends signedMsgUserAccountSubscriber_1.SignedMsgUserOrdersAccountSubscriber {
8
+ constructor({ grpcConfigs, driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }) {
9
+ super({
10
+ driftClient,
11
+ commitment,
12
+ resubOpts,
13
+ decodeFn,
14
+ resyncIntervalMs,
15
+ });
16
+ this.grpcConfigs = grpcConfigs;
17
+ }
18
+ async subscribe() {
19
+ if (!this.subscriber) {
20
+ this.subscriber =
21
+ await grpcProgramAccountSubscriber_1.grpcProgramAccountSubscriber.create(this.grpcConfigs, 'OrderSubscriber', 'User', this.driftClient.program, this.decodeFn, {
22
+ filters: [(0, memcmp_1.getSignedMsgUserOrdersFilter)()],
23
+ }, this.resubOpts);
24
+ }
25
+ await this.subscriber.subscribe((_accountId, account, context) => {
26
+ this.tryUpdateSignedMsgUserOrdersAccount(account, 'decoded', context.slot);
27
+ });
28
+ if (this.resyncIntervalMs) {
29
+ const recursiveResync = () => {
30
+ this.resyncTimeoutId = setTimeout(() => {
31
+ this.fetch()
32
+ .catch((e) => {
33
+ console.error('Failed to resync in OrderSubscriber');
34
+ console.log(e);
35
+ })
36
+ .finally(() => {
37
+ if (!this.resyncTimeoutId)
38
+ return;
39
+ recursiveResync();
40
+ });
41
+ }, this.resyncIntervalMs);
42
+ };
43
+ recursiveResync();
44
+ }
45
+ }
46
+ async unsubscribe() {
47
+ if (!this.subscriber)
48
+ return;
49
+ await this.subscriber.unsubscribe();
50
+ this.subscriber = undefined;
51
+ if (this.resyncTimeoutId !== undefined) {
52
+ clearTimeout(this.resyncTimeoutId);
53
+ this.resyncTimeoutId = undefined;
54
+ }
55
+ }
56
+ }
57
+ exports.grpcSignedMsgUserOrdersAccountSubscriber = grpcSignedMsgUserOrdersAccountSubscriber;
@@ -0,0 +1,3 @@
1
+ export * from './fastlaneOrderSubscriber';
2
+ export * from './signedMsgUserAccountSubscriber';
3
+ export * from './grpcSignedMsgUserAccountSubscriber';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./fastlaneOrderSubscriber"), exports);
18
+ __exportStar(require("./signedMsgUserAccountSubscriber"), exports);
19
+ __exportStar(require("./grpcSignedMsgUserAccountSubscriber"), exports);
@@ -0,0 +1,43 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
6
+ import { SignedMsgOrderId, SignedMsgUserOrdersAccount } from '../types';
7
+ import { Commitment, PublicKey } from '@solana/web3.js';
8
+ import { ResubOpts } from '../accounts/types';
9
+ import { DriftClient } from '../driftClient';
10
+ import StrictEventEmitter from 'strict-event-emitter-types';
11
+ import { EventEmitter } from 'events';
12
+ export interface SignedMsgUserOrdersAccountSubscriberEvents {
13
+ onAccountUpdate: (activeSignedMsgOrderIds: SignedMsgOrderId[], authorityPubkey: PublicKey, slot: number) => void;
14
+ newSignedMsgOrderIds: (newSignedMsgOrderIds: SignedMsgOrderId[], authorityPubkey: PublicKey, slot: number) => void;
15
+ }
16
+ export declare class SignedMsgUserOrdersAccountSubscriber {
17
+ protected driftClient: DriftClient;
18
+ protected commitment: Commitment;
19
+ protected resubOpts?: ResubOpts;
20
+ protected resyncTimeoutId?: NodeJS.Timeout;
21
+ protected resyncIntervalMs?: number;
22
+ protected decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
23
+ protected signedMsgUserOrderAccounts: Map<string, {
24
+ slot: number;
25
+ signedMsgUserOrdersAccount: SignedMsgUserOrdersAccount;
26
+ }>;
27
+ mostRecentSlot: number;
28
+ fetchPromise?: Promise<void>;
29
+ fetchPromiseResolver: () => void;
30
+ protected subscriber: WebSocketProgramAccountSubscriber<SignedMsgUserOrdersAccount>;
31
+ eventEmitter: StrictEventEmitter<EventEmitter, SignedMsgUserOrdersAccountSubscriberEvents>;
32
+ constructor({ driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }: {
33
+ driftClient: DriftClient;
34
+ commitment: Commitment;
35
+ resubOpts?: ResubOpts;
36
+ decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
37
+ resyncIntervalMs?: number;
38
+ });
39
+ subscribe(): Promise<void>;
40
+ fetch(): Promise<void>;
41
+ tryUpdateSignedMsgUserOrdersAccount(data: Buffer | SignedMsgUserOrdersAccount, dataType: 'buffer' | 'decoded', slot: number, skipEventEmitting?: boolean): void;
42
+ unsubscribe(): Promise<void>;
43
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SignedMsgUserOrdersAccountSubscriber = void 0;
4
+ const memcmp_1 = require("../memcmp");
5
+ const webSocketProgramAccountSubscriber_1 = require("../accounts/webSocketProgramAccountSubscriber");
6
+ const events_1 = require("events");
7
+ class SignedMsgUserOrdersAccountSubscriber {
8
+ constructor({ driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }) {
9
+ this.signedMsgUserOrderAccounts = new Map();
10
+ this.commitment = commitment;
11
+ this.resubOpts = resubOpts;
12
+ this.decodeFn = decodeFn;
13
+ this.driftClient = driftClient;
14
+ this.resyncIntervalMs = resyncIntervalMs;
15
+ this.eventEmitter = new events_1.EventEmitter();
16
+ this.resubOpts = resubOpts;
17
+ }
18
+ async subscribe() {
19
+ if (!this.subscriber) {
20
+ const filters = [(0, memcmp_1.getSignedMsgUserOrdersFilter)()];
21
+ this.subscriber =
22
+ new webSocketProgramAccountSubscriber_1.WebSocketProgramAccountSubscriber('SingedMsgUserOrdersAccountMap', 'SignedMsgUserOrders', this.driftClient.program, this.decodeFn, {
23
+ filters,
24
+ commitment: this.commitment,
25
+ }, this.resubOpts);
26
+ }
27
+ await this.subscriber.subscribe((_accountId, account, context) => {
28
+ this.tryUpdateSignedMsgUserOrdersAccount(account, 'decoded', context.slot);
29
+ });
30
+ await this.fetch();
31
+ if (this.resyncIntervalMs) {
32
+ const recursiveResync = () => {
33
+ this.resyncTimeoutId = setTimeout(() => {
34
+ this.fetch()
35
+ .catch((e) => {
36
+ console.error('Failed to resync in OrderSubscriber');
37
+ console.log(e);
38
+ })
39
+ .finally(() => {
40
+ if (!this.resyncTimeoutId)
41
+ return;
42
+ recursiveResync();
43
+ });
44
+ }, this.resyncIntervalMs);
45
+ };
46
+ recursiveResync();
47
+ }
48
+ }
49
+ async fetch() {
50
+ if (this.fetchPromise) {
51
+ return this.fetchPromise;
52
+ }
53
+ this.fetchPromise = new Promise((resolver) => {
54
+ this.fetchPromiseResolver = resolver;
55
+ });
56
+ const skipEventEmitting = this.signedMsgUserOrderAccounts.size === 0;
57
+ try {
58
+ const rpcResponseAndContext = await this.driftClient.connection.getProgramAccounts(this.driftClient.program.programId, {
59
+ commitment: this.commitment,
60
+ filters: [(0, memcmp_1.getSignedMsgUserOrdersFilter)()],
61
+ encoding: 'base64',
62
+ withContext: true,
63
+ });
64
+ const slot = rpcResponseAndContext.context.slot;
65
+ for (const programAccount of rpcResponseAndContext.value) {
66
+ this.tryUpdateSignedMsgUserOrdersAccount(programAccount.account.data, 'buffer', slot, skipEventEmitting);
67
+ await new Promise((resolve) => setTimeout(resolve, 0));
68
+ }
69
+ }
70
+ catch (e) {
71
+ console.error(e);
72
+ }
73
+ finally {
74
+ this.fetchPromiseResolver();
75
+ this.fetchPromise = undefined;
76
+ }
77
+ }
78
+ tryUpdateSignedMsgUserOrdersAccount(data, dataType, slot, skipEventEmitting = false) {
79
+ var _a;
80
+ if (!this.mostRecentSlot || slot > this.mostRecentSlot) {
81
+ this.mostRecentSlot = slot;
82
+ }
83
+ const signedMsgUserOrdersAccount = dataType === 'buffer'
84
+ ? this.decodeFn('SignedMsgUserOrders', data)
85
+ : data;
86
+ const key = signedMsgUserOrdersAccount.authorityPubkey.toBase58();
87
+ const slotAndSignedMsgUserOrdersAccount = this.signedMsgUserOrderAccounts.get(key);
88
+ if (!slotAndSignedMsgUserOrdersAccount ||
89
+ slotAndSignedMsgUserOrdersAccount.slot <= slot) {
90
+ if (!skipEventEmitting) {
91
+ this.eventEmitter.emit('onAccountUpdate', signedMsgUserOrdersAccount.signedMsgOrderData.filter((signedMsgOrderId) => signedMsgOrderId.orderId !== 0), signedMsgUserOrdersAccount.authorityPubkey, slot);
92
+ }
93
+ const existingSignedMsgOrderIds = (_a = slotAndSignedMsgUserOrdersAccount === null || slotAndSignedMsgUserOrdersAccount === void 0 ? void 0 : slotAndSignedMsgUserOrdersAccount.signedMsgUserOrdersAccount.signedMsgOrderData.map((signedMsgOrderId) => signedMsgOrderId.orderId)) !== null && _a !== void 0 ? _a : [];
94
+ const newSignedMsgOrderIds = signedMsgUserOrdersAccount.signedMsgOrderData.filter((signedMsgOrderId) => !existingSignedMsgOrderIds.includes(signedMsgOrderId.orderId) &&
95
+ signedMsgOrderId.orderId !== 0);
96
+ if (newSignedMsgOrderIds.length > 0 && !skipEventEmitting) {
97
+ this.eventEmitter.emit('newSignedMsgOrderIds', newSignedMsgOrderIds, signedMsgUserOrdersAccount.authorityPubkey, slot);
98
+ }
99
+ this.signedMsgUserOrderAccounts.set(key, {
100
+ slot,
101
+ signedMsgUserOrdersAccount,
102
+ });
103
+ }
104
+ }
105
+ async unsubscribe() {
106
+ if (!this.subscriber)
107
+ return;
108
+ await this.subscriber.unsubscribe();
109
+ this.subscriber = undefined;
110
+ if (this.resyncTimeoutId !== undefined) {
111
+ clearTimeout(this.resyncTimeoutId);
112
+ this.resyncTimeoutId = undefined;
113
+ }
114
+ }
115
+ }
116
+ exports.SignedMsgUserOrdersAccountSubscriber = SignedMsgUserOrdersAccountSubscriber;
@@ -88,6 +88,7 @@ export * from './oracles/pythLazerClient';
88
88
  export * from './oracles/switchboardOnDemandClient';
89
89
  export * from './oracles/oracleId';
90
90
  export * from './fastlane/fastlaneOrderSubscriber';
91
+ export * from './fastlane/signedMsgUserAccountSubscriber';
91
92
  export * from './tx/fastSingleTxSender';
92
93
  export * from './tx/retryTxSender';
93
94
  export * from './tx/whileValidTxSender';
@@ -111,6 +111,7 @@ __exportStar(require("./oracles/pythLazerClient"), exports);
111
111
  __exportStar(require("./oracles/switchboardOnDemandClient"), exports);
112
112
  __exportStar(require("./oracles/oracleId"), exports);
113
113
  __exportStar(require("./fastlane/fastlaneOrderSubscriber"), exports);
114
+ __exportStar(require("./fastlane/signedMsgUserAccountSubscriber"), exports);
114
115
  __exportStar(require("./tx/fastSingleTxSender"), exports);
115
116
  __exportStar(require("./tx/retryTxSender"), exports);
116
117
  __exportStar(require("./tx/whileValidTxSender"), exports);
@@ -9,3 +9,4 @@ export declare function getUserWithName(name: string): MemcmpFilter;
9
9
  export declare function getUserStatsFilter(): MemcmpFilter;
10
10
  export declare function getUserStatsIsReferredFilter(): MemcmpFilter;
11
11
  export declare function getUserStatsIsReferredOrReferrerFilter(): MemcmpFilter;
12
+ export declare function getSignedMsgUserOrdersFilter(): MemcmpFilter;
@@ -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.getUserStatsIsReferredOrReferrerFilter = exports.getUserStatsIsReferredFilter = exports.getUserStatsFilter = exports.getUserWithName = exports.getUserThatHasBeenLP = exports.getUserWithAuctionFilter = exports.getUserWithoutOrderFilter = exports.getUserWithOrderFilter = exports.getNonIdleUserFilter = exports.getUserFilter = void 0;
6
+ exports.getSignedMsgUserOrdersFilter = exports.getUserStatsIsReferredOrReferrerFilter = exports.getUserStatsIsReferredFilter = exports.getUserStatsFilter = exports.getUserWithName = exports.getUserThatHasBeenLP = exports.getUserWithAuctionFilter = exports.getUserWithoutOrderFilter = exports.getUserWithOrderFilter = exports.getNonIdleUserFilter = exports.getUserFilter = void 0;
7
7
  const bs58_1 = __importDefault(require("bs58"));
8
8
  const anchor_1 = require("@coral-xyz/anchor");
9
9
  const userName_1 = require("./userName");
@@ -97,3 +97,12 @@ function getUserStatsIsReferredOrReferrerFilter() {
97
97
  };
98
98
  }
99
99
  exports.getUserStatsIsReferredOrReferrerFilter = getUserStatsIsReferredOrReferrerFilter;
100
+ function getSignedMsgUserOrdersFilter() {
101
+ return {
102
+ memcmp: {
103
+ offset: 0,
104
+ bytes: bs58_1.default.encode(anchor_1.BorshAccountsCoder.accountDiscriminator('SignedMsgUserOrders')),
105
+ },
106
+ };
107
+ }
108
+ exports.getSignedMsgUserOrdersFilter = getSignedMsgUserOrdersFilter;
@@ -1427,4 +1427,13 @@ export interface SignedMsgOrderParams {
1427
1427
  */
1428
1428
  signature: Buffer;
1429
1429
  }
1430
+ export type SignedMsgOrderId = {
1431
+ maxSlot: BN;
1432
+ uuid: Uint8Array;
1433
+ orderId: number;
1434
+ };
1435
+ export type SignedMsgUserOrdersAccount = {
1436
+ authorityPubkey: PublicKey;
1437
+ signedMsgOrderData: SignedMsgOrderId[];
1438
+ };
1430
1439
  export {};
@@ -478,7 +478,14 @@ class DLOB {
478
478
  }
479
479
  for (const askGenerator of askGenerators) {
480
480
  for (const ask of askGenerator) {
481
- if ((0, __1.isOrderExpired)(ask.order, ts, true, 25)) {
481
+ if (ask.isSignedMsg &&
482
+ slot.gt(ask.order.slot.addn(ask.order.auctionDuration))) {
483
+ this.orderLists
484
+ .get(marketTypeStr)
485
+ .get(marketIndex)
486
+ .signedMsg.bid.remove(ask.order, ask.userAccount);
487
+ }
488
+ else if ((0, __1.isOrderExpired)(ask.order, ts, true, 25)) {
482
489
  nodesToFill.push({
483
490
  node: ask,
484
491
  makerNodes: [],
@@ -0,0 +1,22 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import { Commitment } from '@solana/web3.js';
4
+ import { grpcProgramAccountSubscriber } from '../accounts/grpcProgramAccountSubscriber';
5
+ import { GrpcConfigs, ResubOpts } from '../accounts/types';
6
+ import { SignedMsgUserOrdersAccount } from '../types';
7
+ import { SignedMsgUserOrdersAccountSubscriber } from './signedMsgUserAccountSubscriber';
8
+ import { DriftClient } from '../driftClient';
9
+ export declare class grpcSignedMsgUserOrdersAccountSubscriber extends SignedMsgUserOrdersAccountSubscriber {
10
+ private grpcConfigs;
11
+ subscriber: grpcProgramAccountSubscriber<SignedMsgUserOrdersAccount>;
12
+ constructor({ grpcConfigs, driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }: {
13
+ grpcConfigs: GrpcConfigs;
14
+ driftClient: DriftClient;
15
+ commitment: Commitment;
16
+ resubOpts?: ResubOpts;
17
+ decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
18
+ resyncIntervalMs?: number;
19
+ });
20
+ subscribe(): Promise<void>;
21
+ unsubscribe(): Promise<void>;
22
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.grpcSignedMsgUserOrdersAccountSubscriber = void 0;
4
+ const grpcProgramAccountSubscriber_1 = require("../accounts/grpcProgramAccountSubscriber");
5
+ const memcmp_1 = require("../memcmp");
6
+ const signedMsgUserAccountSubscriber_1 = require("./signedMsgUserAccountSubscriber");
7
+ class grpcSignedMsgUserOrdersAccountSubscriber extends signedMsgUserAccountSubscriber_1.SignedMsgUserOrdersAccountSubscriber {
8
+ constructor({ grpcConfigs, driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }) {
9
+ super({
10
+ driftClient,
11
+ commitment,
12
+ resubOpts,
13
+ decodeFn,
14
+ resyncIntervalMs,
15
+ });
16
+ this.grpcConfigs = grpcConfigs;
17
+ }
18
+ async subscribe() {
19
+ if (!this.subscriber) {
20
+ this.subscriber =
21
+ await grpcProgramAccountSubscriber_1.grpcProgramAccountSubscriber.create(this.grpcConfigs, 'OrderSubscriber', 'User', this.driftClient.program, this.decodeFn, {
22
+ filters: [(0, memcmp_1.getSignedMsgUserOrdersFilter)()],
23
+ }, this.resubOpts);
24
+ }
25
+ await this.subscriber.subscribe((_accountId, account, context) => {
26
+ this.tryUpdateSignedMsgUserOrdersAccount(account, 'decoded', context.slot);
27
+ });
28
+ if (this.resyncIntervalMs) {
29
+ const recursiveResync = () => {
30
+ this.resyncTimeoutId = setTimeout(() => {
31
+ this.fetch()
32
+ .catch((e) => {
33
+ console.error('Failed to resync in OrderSubscriber');
34
+ console.log(e);
35
+ })
36
+ .finally(() => {
37
+ if (!this.resyncTimeoutId)
38
+ return;
39
+ recursiveResync();
40
+ });
41
+ }, this.resyncIntervalMs);
42
+ };
43
+ recursiveResync();
44
+ }
45
+ }
46
+ async unsubscribe() {
47
+ if (!this.subscriber)
48
+ return;
49
+ await this.subscriber.unsubscribe();
50
+ this.subscriber = undefined;
51
+ if (this.resyncTimeoutId !== undefined) {
52
+ clearTimeout(this.resyncTimeoutId);
53
+ this.resyncTimeoutId = undefined;
54
+ }
55
+ }
56
+ }
57
+ exports.grpcSignedMsgUserOrdersAccountSubscriber = grpcSignedMsgUserOrdersAccountSubscriber;
@@ -0,0 +1,3 @@
1
+ export * from './fastlaneOrderSubscriber';
2
+ export * from './signedMsgUserAccountSubscriber';
3
+ export * from './grpcSignedMsgUserAccountSubscriber';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./fastlaneOrderSubscriber"), exports);
18
+ __exportStar(require("./signedMsgUserAccountSubscriber"), exports);
19
+ __exportStar(require("./grpcSignedMsgUserAccountSubscriber"), exports);
@@ -0,0 +1,43 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
6
+ import { SignedMsgOrderId, SignedMsgUserOrdersAccount } from '../types';
7
+ import { Commitment, PublicKey } from '@solana/web3.js';
8
+ import { ResubOpts } from '../accounts/types';
9
+ import { DriftClient } from '../driftClient';
10
+ import StrictEventEmitter from 'strict-event-emitter-types';
11
+ import { EventEmitter } from 'events';
12
+ export interface SignedMsgUserOrdersAccountSubscriberEvents {
13
+ onAccountUpdate: (activeSignedMsgOrderIds: SignedMsgOrderId[], authorityPubkey: PublicKey, slot: number) => void;
14
+ newSignedMsgOrderIds: (newSignedMsgOrderIds: SignedMsgOrderId[], authorityPubkey: PublicKey, slot: number) => void;
15
+ }
16
+ export declare class SignedMsgUserOrdersAccountSubscriber {
17
+ protected driftClient: DriftClient;
18
+ protected commitment: Commitment;
19
+ protected resubOpts?: ResubOpts;
20
+ protected resyncTimeoutId?: NodeJS.Timeout;
21
+ protected resyncIntervalMs?: number;
22
+ protected decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
23
+ protected signedMsgUserOrderAccounts: Map<string, {
24
+ slot: number;
25
+ signedMsgUserOrdersAccount: SignedMsgUserOrdersAccount;
26
+ }>;
27
+ mostRecentSlot: number;
28
+ fetchPromise?: Promise<void>;
29
+ fetchPromiseResolver: () => void;
30
+ protected subscriber: WebSocketProgramAccountSubscriber<SignedMsgUserOrdersAccount>;
31
+ eventEmitter: StrictEventEmitter<EventEmitter, SignedMsgUserOrdersAccountSubscriberEvents>;
32
+ constructor({ driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }: {
33
+ driftClient: DriftClient;
34
+ commitment: Commitment;
35
+ resubOpts?: ResubOpts;
36
+ decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
37
+ resyncIntervalMs?: number;
38
+ });
39
+ subscribe(): Promise<void>;
40
+ fetch(): Promise<void>;
41
+ tryUpdateSignedMsgUserOrdersAccount(data: Buffer | SignedMsgUserOrdersAccount, dataType: 'buffer' | 'decoded', slot: number, skipEventEmitting?: boolean): void;
42
+ unsubscribe(): Promise<void>;
43
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SignedMsgUserOrdersAccountSubscriber = void 0;
4
+ const memcmp_1 = require("../memcmp");
5
+ const webSocketProgramAccountSubscriber_1 = require("../accounts/webSocketProgramAccountSubscriber");
6
+ const events_1 = require("events");
7
+ class SignedMsgUserOrdersAccountSubscriber {
8
+ constructor({ driftClient, commitment, resubOpts, decodeFn, resyncIntervalMs, }) {
9
+ this.signedMsgUserOrderAccounts = new Map();
10
+ this.commitment = commitment;
11
+ this.resubOpts = resubOpts;
12
+ this.decodeFn = decodeFn;
13
+ this.driftClient = driftClient;
14
+ this.resyncIntervalMs = resyncIntervalMs;
15
+ this.eventEmitter = new events_1.EventEmitter();
16
+ this.resubOpts = resubOpts;
17
+ }
18
+ async subscribe() {
19
+ if (!this.subscriber) {
20
+ const filters = [(0, memcmp_1.getSignedMsgUserOrdersFilter)()];
21
+ this.subscriber =
22
+ new webSocketProgramAccountSubscriber_1.WebSocketProgramAccountSubscriber('SingedMsgUserOrdersAccountMap', 'SignedMsgUserOrders', this.driftClient.program, this.decodeFn, {
23
+ filters,
24
+ commitment: this.commitment,
25
+ }, this.resubOpts);
26
+ }
27
+ await this.subscriber.subscribe((_accountId, account, context) => {
28
+ this.tryUpdateSignedMsgUserOrdersAccount(account, 'decoded', context.slot);
29
+ });
30
+ await this.fetch();
31
+ if (this.resyncIntervalMs) {
32
+ const recursiveResync = () => {
33
+ this.resyncTimeoutId = setTimeout(() => {
34
+ this.fetch()
35
+ .catch((e) => {
36
+ console.error('Failed to resync in OrderSubscriber');
37
+ console.log(e);
38
+ })
39
+ .finally(() => {
40
+ if (!this.resyncTimeoutId)
41
+ return;
42
+ recursiveResync();
43
+ });
44
+ }, this.resyncIntervalMs);
45
+ };
46
+ recursiveResync();
47
+ }
48
+ }
49
+ async fetch() {
50
+ if (this.fetchPromise) {
51
+ return this.fetchPromise;
52
+ }
53
+ this.fetchPromise = new Promise((resolver) => {
54
+ this.fetchPromiseResolver = resolver;
55
+ });
56
+ const skipEventEmitting = this.signedMsgUserOrderAccounts.size === 0;
57
+ try {
58
+ const rpcResponseAndContext = await this.driftClient.connection.getProgramAccounts(this.driftClient.program.programId, {
59
+ commitment: this.commitment,
60
+ filters: [(0, memcmp_1.getSignedMsgUserOrdersFilter)()],
61
+ encoding: 'base64',
62
+ withContext: true,
63
+ });
64
+ const slot = rpcResponseAndContext.context.slot;
65
+ for (const programAccount of rpcResponseAndContext.value) {
66
+ this.tryUpdateSignedMsgUserOrdersAccount(programAccount.account.data, 'buffer', slot, skipEventEmitting);
67
+ await new Promise((resolve) => setTimeout(resolve, 0));
68
+ }
69
+ }
70
+ catch (e) {
71
+ console.error(e);
72
+ }
73
+ finally {
74
+ this.fetchPromiseResolver();
75
+ this.fetchPromise = undefined;
76
+ }
77
+ }
78
+ tryUpdateSignedMsgUserOrdersAccount(data, dataType, slot, skipEventEmitting = false) {
79
+ var _a;
80
+ if (!this.mostRecentSlot || slot > this.mostRecentSlot) {
81
+ this.mostRecentSlot = slot;
82
+ }
83
+ const signedMsgUserOrdersAccount = dataType === 'buffer'
84
+ ? this.decodeFn('SignedMsgUserOrders', data)
85
+ : data;
86
+ const key = signedMsgUserOrdersAccount.authorityPubkey.toBase58();
87
+ const slotAndSignedMsgUserOrdersAccount = this.signedMsgUserOrderAccounts.get(key);
88
+ if (!slotAndSignedMsgUserOrdersAccount ||
89
+ slotAndSignedMsgUserOrdersAccount.slot <= slot) {
90
+ if (!skipEventEmitting) {
91
+ this.eventEmitter.emit('onAccountUpdate', signedMsgUserOrdersAccount.signedMsgOrderData.filter((signedMsgOrderId) => signedMsgOrderId.orderId !== 0), signedMsgUserOrdersAccount.authorityPubkey, slot);
92
+ }
93
+ const existingSignedMsgOrderIds = (_a = slotAndSignedMsgUserOrdersAccount === null || slotAndSignedMsgUserOrdersAccount === void 0 ? void 0 : slotAndSignedMsgUserOrdersAccount.signedMsgUserOrdersAccount.signedMsgOrderData.map((signedMsgOrderId) => signedMsgOrderId.orderId)) !== null && _a !== void 0 ? _a : [];
94
+ const newSignedMsgOrderIds = signedMsgUserOrdersAccount.signedMsgOrderData.filter((signedMsgOrderId) => !existingSignedMsgOrderIds.includes(signedMsgOrderId.orderId) &&
95
+ signedMsgOrderId.orderId !== 0);
96
+ if (newSignedMsgOrderIds.length > 0 && !skipEventEmitting) {
97
+ this.eventEmitter.emit('newSignedMsgOrderIds', newSignedMsgOrderIds, signedMsgUserOrdersAccount.authorityPubkey, slot);
98
+ }
99
+ this.signedMsgUserOrderAccounts.set(key, {
100
+ slot,
101
+ signedMsgUserOrdersAccount,
102
+ });
103
+ }
104
+ }
105
+ async unsubscribe() {
106
+ if (!this.subscriber)
107
+ return;
108
+ await this.subscriber.unsubscribe();
109
+ this.subscriber = undefined;
110
+ if (this.resyncTimeoutId !== undefined) {
111
+ clearTimeout(this.resyncTimeoutId);
112
+ this.resyncTimeoutId = undefined;
113
+ }
114
+ }
115
+ }
116
+ exports.SignedMsgUserOrdersAccountSubscriber = SignedMsgUserOrdersAccountSubscriber;
@@ -88,6 +88,7 @@ export * from './oracles/pythLazerClient';
88
88
  export * from './oracles/switchboardOnDemandClient';
89
89
  export * from './oracles/oracleId';
90
90
  export * from './fastlane/fastlaneOrderSubscriber';
91
+ export * from './fastlane/signedMsgUserAccountSubscriber';
91
92
  export * from './tx/fastSingleTxSender';
92
93
  export * from './tx/retryTxSender';
93
94
  export * from './tx/whileValidTxSender';
package/lib/node/index.js CHANGED
@@ -111,6 +111,7 @@ __exportStar(require("./oracles/pythLazerClient"), exports);
111
111
  __exportStar(require("./oracles/switchboardOnDemandClient"), exports);
112
112
  __exportStar(require("./oracles/oracleId"), exports);
113
113
  __exportStar(require("./fastlane/fastlaneOrderSubscriber"), exports);
114
+ __exportStar(require("./fastlane/signedMsgUserAccountSubscriber"), exports);
114
115
  __exportStar(require("./tx/fastSingleTxSender"), exports);
115
116
  __exportStar(require("./tx/retryTxSender"), exports);
116
117
  __exportStar(require("./tx/whileValidTxSender"), exports);
@@ -9,3 +9,4 @@ export declare function getUserWithName(name: string): MemcmpFilter;
9
9
  export declare function getUserStatsFilter(): MemcmpFilter;
10
10
  export declare function getUserStatsIsReferredFilter(): MemcmpFilter;
11
11
  export declare function getUserStatsIsReferredOrReferrerFilter(): MemcmpFilter;
12
+ export declare function getSignedMsgUserOrdersFilter(): MemcmpFilter;
@@ -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.getUserStatsIsReferredOrReferrerFilter = exports.getUserStatsIsReferredFilter = exports.getUserStatsFilter = exports.getUserWithName = exports.getUserThatHasBeenLP = exports.getUserWithAuctionFilter = exports.getUserWithoutOrderFilter = exports.getUserWithOrderFilter = exports.getNonIdleUserFilter = exports.getUserFilter = void 0;
6
+ exports.getSignedMsgUserOrdersFilter = exports.getUserStatsIsReferredOrReferrerFilter = exports.getUserStatsIsReferredFilter = exports.getUserStatsFilter = exports.getUserWithName = exports.getUserThatHasBeenLP = exports.getUserWithAuctionFilter = exports.getUserWithoutOrderFilter = exports.getUserWithOrderFilter = exports.getNonIdleUserFilter = exports.getUserFilter = void 0;
7
7
  const bs58_1 = __importDefault(require("bs58"));
8
8
  const anchor_1 = require("@coral-xyz/anchor");
9
9
  const userName_1 = require("./userName");
@@ -97,3 +97,12 @@ function getUserStatsIsReferredOrReferrerFilter() {
97
97
  };
98
98
  }
99
99
  exports.getUserStatsIsReferredOrReferrerFilter = getUserStatsIsReferredOrReferrerFilter;
100
+ function getSignedMsgUserOrdersFilter() {
101
+ return {
102
+ memcmp: {
103
+ offset: 0,
104
+ bytes: bs58_1.default.encode(anchor_1.BorshAccountsCoder.accountDiscriminator('SignedMsgUserOrders')),
105
+ },
106
+ };
107
+ }
108
+ exports.getSignedMsgUserOrdersFilter = getSignedMsgUserOrdersFilter;
@@ -1427,4 +1427,13 @@ export interface SignedMsgOrderParams {
1427
1427
  */
1428
1428
  signature: Buffer;
1429
1429
  }
1430
+ export type SignedMsgOrderId = {
1431
+ maxSlot: BN;
1432
+ uuid: Uint8Array;
1433
+ orderId: number;
1434
+ };
1435
+ export type SignedMsgUserOrdersAccount = {
1436
+ authorityPubkey: PublicKey;
1437
+ signedMsgOrderData: SignedMsgOrderId[];
1438
+ };
1430
1439
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.112.0-beta.2",
3
+ "version": "2.112.0-beta.4",
4
4
  "main": "lib/node/index.js",
5
5
  "types": "lib/node/index.d.ts",
6
6
  "browser": "./lib/browser/index.js",
package/src/dlob/DLOB.ts CHANGED
@@ -934,7 +934,15 @@ export class DLOB {
934
934
 
935
935
  for (const askGenerator of askGenerators) {
936
936
  for (const ask of askGenerator) {
937
- if (isOrderExpired(ask.order, ts, true, 25)) {
937
+ if (
938
+ ask.isSignedMsg &&
939
+ slot.gt(ask.order.slot.addn(ask.order.auctionDuration))
940
+ ) {
941
+ this.orderLists
942
+ .get(marketTypeStr)
943
+ .get(marketIndex)
944
+ .signedMsg.bid.remove(ask.order, ask.userAccount);
945
+ } else if (isOrderExpired(ask.order, ts, true, 25)) {
938
946
  nodesToFill.push({
939
947
  node: ask,
940
948
  makerNodes: [],
@@ -0,0 +1,95 @@
1
+ import { Commitment, Context, PublicKey } from '@solana/web3.js';
2
+ import { grpcProgramAccountSubscriber } from '../accounts/grpcProgramAccountSubscriber';
3
+ import { GrpcConfigs, ResubOpts } from '../accounts/types';
4
+ import { SignedMsgUserOrdersAccount } from '../types';
5
+ import { getSignedMsgUserOrdersFilter } from '../memcmp';
6
+ import { SignedMsgUserOrdersAccountSubscriber } from './signedMsgUserAccountSubscriber';
7
+ import { DriftClient } from '../driftClient';
8
+
9
+ export class grpcSignedMsgUserOrdersAccountSubscriber extends SignedMsgUserOrdersAccountSubscriber {
10
+ private grpcConfigs: GrpcConfigs;
11
+ override subscriber: grpcProgramAccountSubscriber<SignedMsgUserOrdersAccount>;
12
+
13
+ constructor({
14
+ grpcConfigs,
15
+ driftClient,
16
+ commitment,
17
+ resubOpts,
18
+ decodeFn,
19
+ resyncIntervalMs,
20
+ }: {
21
+ grpcConfigs: GrpcConfigs;
22
+ driftClient: DriftClient;
23
+ commitment: Commitment;
24
+ resubOpts?: ResubOpts;
25
+ decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
26
+ resyncIntervalMs?: number;
27
+ }) {
28
+ super({
29
+ driftClient,
30
+ commitment,
31
+ resubOpts,
32
+ decodeFn,
33
+ resyncIntervalMs,
34
+ });
35
+ this.grpcConfigs = grpcConfigs;
36
+ }
37
+
38
+ public async subscribe(): Promise<void> {
39
+ if (!this.subscriber) {
40
+ this.subscriber =
41
+ await grpcProgramAccountSubscriber.create<SignedMsgUserOrdersAccount>(
42
+ this.grpcConfigs,
43
+ 'OrderSubscriber',
44
+ 'User',
45
+ this.driftClient.program,
46
+ this.decodeFn,
47
+ {
48
+ filters: [getSignedMsgUserOrdersFilter()],
49
+ },
50
+ this.resubOpts
51
+ );
52
+ }
53
+
54
+ await this.subscriber.subscribe(
55
+ (
56
+ _accountId: PublicKey,
57
+ account: SignedMsgUserOrdersAccount,
58
+ context: Context
59
+ ) => {
60
+ this.tryUpdateSignedMsgUserOrdersAccount(
61
+ account,
62
+ 'decoded',
63
+ context.slot
64
+ );
65
+ }
66
+ );
67
+
68
+ if (this.resyncIntervalMs) {
69
+ const recursiveResync = () => {
70
+ this.resyncTimeoutId = setTimeout(() => {
71
+ this.fetch()
72
+ .catch((e) => {
73
+ console.error('Failed to resync in OrderSubscriber');
74
+ console.log(e);
75
+ })
76
+ .finally(() => {
77
+ if (!this.resyncTimeoutId) return;
78
+ recursiveResync();
79
+ });
80
+ }, this.resyncIntervalMs);
81
+ };
82
+ recursiveResync();
83
+ }
84
+ }
85
+
86
+ public async unsubscribe(): Promise<void> {
87
+ if (!this.subscriber) return;
88
+ await this.subscriber.unsubscribe();
89
+ this.subscriber = undefined;
90
+ if (this.resyncTimeoutId !== undefined) {
91
+ clearTimeout(this.resyncTimeoutId);
92
+ this.resyncTimeoutId = undefined;
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,3 @@
1
+ export * from './fastlaneOrderSubscriber';
2
+ export * from './signedMsgUserAccountSubscriber';
3
+ export * from './grpcSignedMsgUserAccountSubscriber';
@@ -0,0 +1,234 @@
1
+ import { getSignedMsgUserOrdersFilter } from '../memcmp';
2
+ import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
3
+ import { SignedMsgOrderId, SignedMsgUserOrdersAccount } from '../types';
4
+ import { Commitment, Context, PublicKey } from '@solana/web3.js';
5
+ import { ResubOpts } from '../accounts/types';
6
+ import { DriftClient } from '../driftClient';
7
+ import StrictEventEmitter from 'strict-event-emitter-types';
8
+ import { EventEmitter } from 'events';
9
+
10
+ export interface SignedMsgUserOrdersAccountSubscriberEvents {
11
+ onAccountUpdate: (
12
+ activeSignedMsgOrderIds: SignedMsgOrderId[],
13
+ authorityPubkey: PublicKey,
14
+ slot: number
15
+ ) => void;
16
+
17
+ newSignedMsgOrderIds: (
18
+ newSignedMsgOrderIds: SignedMsgOrderId[],
19
+ authorityPubkey: PublicKey,
20
+ slot: number
21
+ ) => void;
22
+ }
23
+
24
+ export class SignedMsgUserOrdersAccountSubscriber {
25
+ protected driftClient: DriftClient;
26
+ protected commitment: Commitment;
27
+ protected resubOpts?: ResubOpts;
28
+ protected resyncTimeoutId?: NodeJS.Timeout;
29
+ protected resyncIntervalMs?: number;
30
+ protected decodeFn: (
31
+ name: string,
32
+ data: Buffer
33
+ ) => SignedMsgUserOrdersAccount;
34
+ protected signedMsgUserOrderAccounts = new Map<
35
+ string,
36
+ { slot: number; signedMsgUserOrdersAccount: SignedMsgUserOrdersAccount }
37
+ >();
38
+ mostRecentSlot: number;
39
+
40
+ fetchPromise?: Promise<void>;
41
+ fetchPromiseResolver: () => void;
42
+
43
+ protected subscriber: WebSocketProgramAccountSubscriber<SignedMsgUserOrdersAccount>;
44
+ public eventEmitter: StrictEventEmitter<
45
+ EventEmitter,
46
+ SignedMsgUserOrdersAccountSubscriberEvents
47
+ >;
48
+
49
+ constructor({
50
+ driftClient,
51
+ commitment,
52
+ resubOpts,
53
+ decodeFn,
54
+ resyncIntervalMs,
55
+ }: {
56
+ driftClient: DriftClient;
57
+ commitment: Commitment;
58
+ resubOpts?: ResubOpts;
59
+ decodeFn: (name: string, data: Buffer) => SignedMsgUserOrdersAccount;
60
+ resyncIntervalMs?: number;
61
+ }) {
62
+ this.commitment = commitment;
63
+ this.resubOpts = resubOpts;
64
+ this.decodeFn = decodeFn;
65
+ this.driftClient = driftClient;
66
+ this.resyncIntervalMs = resyncIntervalMs;
67
+ this.eventEmitter = new EventEmitter();
68
+ this.resubOpts = resubOpts;
69
+ }
70
+
71
+ public async subscribe(): Promise<void> {
72
+ if (!this.subscriber) {
73
+ const filters = [getSignedMsgUserOrdersFilter()];
74
+ this.subscriber =
75
+ new WebSocketProgramAccountSubscriber<SignedMsgUserOrdersAccount>(
76
+ 'SingedMsgUserOrdersAccountMap',
77
+ 'SignedMsgUserOrders',
78
+ this.driftClient.program,
79
+ this.decodeFn,
80
+ {
81
+ filters,
82
+ commitment: this.commitment,
83
+ },
84
+ this.resubOpts
85
+ );
86
+ }
87
+
88
+ await this.subscriber.subscribe(
89
+ (
90
+ _accountId: PublicKey,
91
+ account: SignedMsgUserOrdersAccount,
92
+ context: Context
93
+ ) => {
94
+ this.tryUpdateSignedMsgUserOrdersAccount(
95
+ account,
96
+ 'decoded',
97
+ context.slot
98
+ );
99
+ }
100
+ );
101
+
102
+ await this.fetch();
103
+
104
+ if (this.resyncIntervalMs) {
105
+ const recursiveResync = () => {
106
+ this.resyncTimeoutId = setTimeout(() => {
107
+ this.fetch()
108
+ .catch((e) => {
109
+ console.error('Failed to resync in OrderSubscriber');
110
+ console.log(e);
111
+ })
112
+ .finally(() => {
113
+ if (!this.resyncTimeoutId) return;
114
+ recursiveResync();
115
+ });
116
+ }, this.resyncIntervalMs);
117
+ };
118
+ recursiveResync();
119
+ }
120
+ }
121
+
122
+ async fetch(): Promise<void> {
123
+ if (this.fetchPromise) {
124
+ return this.fetchPromise;
125
+ }
126
+
127
+ this.fetchPromise = new Promise((resolver) => {
128
+ this.fetchPromiseResolver = resolver;
129
+ });
130
+
131
+ const skipEventEmitting = this.signedMsgUserOrderAccounts.size === 0;
132
+
133
+ try {
134
+ const rpcResponseAndContext =
135
+ await this.driftClient.connection.getProgramAccounts(
136
+ this.driftClient.program.programId,
137
+ {
138
+ commitment: this.commitment,
139
+ filters: [getSignedMsgUserOrdersFilter()],
140
+ encoding: 'base64',
141
+ withContext: true,
142
+ }
143
+ );
144
+
145
+ const slot: number = rpcResponseAndContext.context.slot;
146
+
147
+ for (const programAccount of rpcResponseAndContext.value) {
148
+ this.tryUpdateSignedMsgUserOrdersAccount(
149
+ programAccount.account.data,
150
+ 'buffer',
151
+ slot,
152
+ skipEventEmitting
153
+ );
154
+ await new Promise((resolve) => setTimeout(resolve, 0));
155
+ }
156
+ } catch (e) {
157
+ console.error(e);
158
+ } finally {
159
+ this.fetchPromiseResolver();
160
+ this.fetchPromise = undefined;
161
+ }
162
+ }
163
+
164
+ tryUpdateSignedMsgUserOrdersAccount(
165
+ data: Buffer | SignedMsgUserOrdersAccount,
166
+ dataType: 'buffer' | 'decoded',
167
+ slot: number,
168
+ skipEventEmitting = false
169
+ ): void {
170
+ if (!this.mostRecentSlot || slot > this.mostRecentSlot) {
171
+ this.mostRecentSlot = slot;
172
+ }
173
+
174
+ const signedMsgUserOrdersAccount =
175
+ dataType === 'buffer'
176
+ ? this.decodeFn('SignedMsgUserOrders', data as Buffer)
177
+ : (data as SignedMsgUserOrdersAccount);
178
+
179
+ const key = signedMsgUserOrdersAccount.authorityPubkey.toBase58();
180
+
181
+ const slotAndSignedMsgUserOrdersAccount =
182
+ this.signedMsgUserOrderAccounts.get(key);
183
+ if (
184
+ !slotAndSignedMsgUserOrdersAccount ||
185
+ slotAndSignedMsgUserOrdersAccount.slot <= slot
186
+ ) {
187
+ if (!skipEventEmitting) {
188
+ this.eventEmitter.emit(
189
+ 'onAccountUpdate',
190
+ signedMsgUserOrdersAccount.signedMsgOrderData.filter(
191
+ (signedMsgOrderId) => signedMsgOrderId.orderId !== 0
192
+ ),
193
+ signedMsgUserOrdersAccount.authorityPubkey,
194
+ slot
195
+ );
196
+ }
197
+
198
+ const existingSignedMsgOrderIds =
199
+ slotAndSignedMsgUserOrdersAccount?.signedMsgUserOrdersAccount.signedMsgOrderData.map(
200
+ (signedMsgOrderId) => signedMsgOrderId.orderId
201
+ ) ?? [];
202
+
203
+ const newSignedMsgOrderIds =
204
+ signedMsgUserOrdersAccount.signedMsgOrderData.filter(
205
+ (signedMsgOrderId: SignedMsgOrderId) =>
206
+ !existingSignedMsgOrderIds.includes(signedMsgOrderId.orderId) &&
207
+ signedMsgOrderId.orderId !== 0
208
+ );
209
+ if (newSignedMsgOrderIds.length > 0 && !skipEventEmitting) {
210
+ this.eventEmitter.emit(
211
+ 'newSignedMsgOrderIds',
212
+ newSignedMsgOrderIds,
213
+ signedMsgUserOrdersAccount.authorityPubkey,
214
+ slot
215
+ );
216
+ }
217
+
218
+ this.signedMsgUserOrderAccounts.set(key, {
219
+ slot,
220
+ signedMsgUserOrdersAccount,
221
+ });
222
+ }
223
+ }
224
+
225
+ public async unsubscribe(): Promise<void> {
226
+ if (!this.subscriber) return;
227
+ await this.subscriber.unsubscribe();
228
+ this.subscriber = undefined;
229
+ if (this.resyncTimeoutId !== undefined) {
230
+ clearTimeout(this.resyncTimeoutId);
231
+ this.resyncTimeoutId = undefined;
232
+ }
233
+ }
234
+ }
package/src/index.ts CHANGED
@@ -89,6 +89,7 @@ export * from './oracles/pythLazerClient';
89
89
  export * from './oracles/switchboardOnDemandClient';
90
90
  export * from './oracles/oracleId';
91
91
  export * from './fastlane/fastlaneOrderSubscriber';
92
+ export * from './fastlane/signedMsgUserAccountSubscriber';
92
93
  export * from './tx/fastSingleTxSender';
93
94
  export * from './tx/retryTxSender';
94
95
  export * from './tx/whileValidTxSender';
package/src/memcmp.ts CHANGED
@@ -92,3 +92,14 @@ export function getUserStatsIsReferredOrReferrerFilter(): MemcmpFilter {
92
92
  },
93
93
  };
94
94
  }
95
+
96
+ export function getSignedMsgUserOrdersFilter(): MemcmpFilter {
97
+ return {
98
+ memcmp: {
99
+ offset: 0,
100
+ bytes: bs58.encode(
101
+ BorshAccountsCoder.accountDiscriminator('SignedMsgUserOrders')
102
+ ),
103
+ },
104
+ };
105
+ }
package/src/types.ts CHANGED
@@ -1426,3 +1426,14 @@ export interface SignedMsgOrderParams {
1426
1426
  */
1427
1427
  signature: Buffer;
1428
1428
  }
1429
+
1430
+ export type SignedMsgOrderId = {
1431
+ maxSlot: BN;
1432
+ uuid: Uint8Array;
1433
+ orderId: number;
1434
+ };
1435
+
1436
+ export type SignedMsgUserOrdersAccount = {
1437
+ authorityPubkey: PublicKey;
1438
+ signedMsgOrderData: SignedMsgOrderId[];
1439
+ };