@drift-labs/sdk 2.31.0-beta.1 → 2.31.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 (61) hide show
  1. package/lib/accounts/bulkAccountLoader.js +5 -0
  2. package/lib/auctionSubscriber/auctionSubscriber.d.ts +13 -0
  3. package/lib/auctionSubscriber/auctionSubscriber.js +22 -0
  4. package/lib/auctionSubscriber/index.d.ts +2 -0
  5. package/lib/auctionSubscriber/index.js +18 -0
  6. package/lib/auctionSubscriber/types.d.ts +10 -0
  7. package/lib/auctionSubscriber/types.js +2 -0
  8. package/lib/driftClient.d.ts +2 -0
  9. package/lib/driftClient.js +22 -9
  10. package/lib/events/eventSubscriber.d.ts +1 -0
  11. package/lib/events/eventSubscriber.js +5 -3
  12. package/lib/events/fetchLogs.d.ts +1 -1
  13. package/lib/events/fetchLogs.js +2 -2
  14. package/lib/events/pollingLogProvider.d.ts +2 -2
  15. package/lib/events/pollingLogProvider.js +3 -3
  16. package/lib/events/types.d.ts +2 -1
  17. package/lib/events/webSocketLogProvider.d.ts +2 -2
  18. package/lib/events/webSocketLogProvider.js +3 -3
  19. package/lib/idl/drift.json +61 -2
  20. package/lib/index.d.ts +1 -0
  21. package/lib/index.js +1 -0
  22. package/lib/math/spotBalance.js +1 -1
  23. package/lib/memcmp.d.ts +5 -0
  24. package/lib/memcmp.js +44 -0
  25. package/lib/orderSubscriber/OrderSubscriber.d.ts +24 -0
  26. package/lib/orderSubscriber/OrderSubscriber.js +100 -0
  27. package/lib/orderSubscriber/PollingSubscription.d.ts +13 -0
  28. package/lib/orderSubscriber/PollingSubscription.js +23 -0
  29. package/lib/orderSubscriber/WebsocketSubscription.d.ts +12 -0
  30. package/lib/orderSubscriber/WebsocketSubscription.js +30 -0
  31. package/lib/orderSubscriber/index.d.ts +2 -0
  32. package/lib/orderSubscriber/index.js +18 -0
  33. package/lib/orderSubscriber/types.d.ts +11 -0
  34. package/lib/orderSubscriber/types.js +2 -0
  35. package/lib/tx/retryTxSender.js +5 -2
  36. package/lib/types.d.ts +5 -1
  37. package/lib/types.js +1 -1
  38. package/lib/userMap/userMap.js +4 -19
  39. package/package.json +1 -1
  40. package/src/accounts/bulkAccountLoader.ts +5 -0
  41. package/src/auctionSubscriber/auctionSubscriber.ts +50 -0
  42. package/src/auctionSubscriber/index.ts +2 -0
  43. package/src/auctionSubscriber/types.ts +16 -0
  44. package/src/driftClient.ts +41 -10
  45. package/src/events/eventSubscriber.ts +6 -4
  46. package/src/events/fetchLogs.ts +2 -2
  47. package/src/events/pollingLogProvider.ts +2 -2
  48. package/src/events/types.ts +2 -1
  49. package/src/events/webSocketLogProvider.ts +2 -2
  50. package/src/idl/drift.json +61 -2
  51. package/src/index.ts +1 -0
  52. package/src/math/spotBalance.ts +1 -3
  53. package/src/memcmp.ts +39 -0
  54. package/src/orderSubscriber/OrderSubscriber.ts +132 -0
  55. package/src/orderSubscriber/PollingSubscription.ts +39 -0
  56. package/src/orderSubscriber/WebsocketSubscription.ts +54 -0
  57. package/src/orderSubscriber/index.ts +2 -0
  58. package/src/orderSubscriber/types.ts +14 -0
  59. package/src/tx/retryTxSender.ts +8 -2
  60. package/src/types.ts +5 -1
  61. package/src/userMap/userMap.ts +4 -16
@@ -124,6 +124,11 @@ class BulkAccountLoader {
124
124
  }
125
125
  for (const i in rpcResponses) {
126
126
  const rpcResponse = rpcResponses[i];
127
+ if (!rpcResponse.result) {
128
+ console.error('rpc response missing result:');
129
+ console.log(JSON.stringify(rpcResponse));
130
+ continue;
131
+ }
127
132
  const newSlot = rpcResponse.result.context.slot;
128
133
  if (newSlot > this.mostRecentSlot) {
129
134
  this.mostRecentSlot = newSlot;
@@ -0,0 +1,13 @@
1
+ /// <reference types="node" />
2
+ import { AuctionSubscriberConfig, AuctionSubscriberEvents } from './types';
3
+ import StrictEventEmitter from 'strict-event-emitter-types';
4
+ import { EventEmitter } from 'events';
5
+ export declare class AuctionSubscriber {
6
+ private driftClient;
7
+ private opts;
8
+ eventEmitter: StrictEventEmitter<EventEmitter, AuctionSubscriberEvents>;
9
+ private websocketId;
10
+ constructor({ driftClient, opts }: AuctionSubscriberConfig);
11
+ subscribe(): Promise<void>;
12
+ unsubscribe(): Promise<void>;
13
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuctionSubscriber = void 0;
4
+ const memcmp_1 = require("../memcmp");
5
+ class AuctionSubscriber {
6
+ constructor({ driftClient, opts }) {
7
+ this.driftClient = driftClient;
8
+ this.opts = opts || this.driftClient.opts;
9
+ }
10
+ async subscribe() {
11
+ this.websocketId = this.driftClient.connection.onProgramAccountChange(this.driftClient.program.programId, (keyAccountInfo, context) => {
12
+ const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', keyAccountInfo.accountInfo.data);
13
+ this.eventEmitter.emit('onAccountUpdate', userAccount, keyAccountInfo.accountId, context.slot);
14
+ }, this.driftClient.opts.commitment, [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getUserWithAuctionFilter)()]);
15
+ }
16
+ async unsubscribe() {
17
+ if (this.websocketId) {
18
+ await this.driftClient.connection.removeProgramAccountChangeListener(this.websocketId);
19
+ }
20
+ }
21
+ }
22
+ exports.AuctionSubscriber = AuctionSubscriber;
@@ -0,0 +1,2 @@
1
+ export * from './types';
2
+ export * from './auctionSubscriber';
@@ -0,0 +1,18 @@
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("./types"), exports);
18
+ __exportStar(require("./auctionSubscriber"), exports);
@@ -0,0 +1,10 @@
1
+ import { DriftClient } from '../driftClient';
2
+ import { UserAccount } from '../types';
3
+ import { ConfirmOptions, PublicKey } from '@solana/web3.js';
4
+ export type AuctionSubscriberConfig = {
5
+ driftClient: DriftClient;
6
+ opts?: ConfirmOptions;
7
+ };
8
+ export interface AuctionSubscriberEvents {
9
+ onAccountUpdate: (account: UserAccount, pubkey: PublicKey, slot: number) => void;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -329,6 +329,8 @@ export declare class DriftClient {
329
329
  getForceCancelOrdersIx(userAccountPublicKey: PublicKey, userAccount: UserAccount): Promise<TransactionInstruction>;
330
330
  updateUserIdle(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams): Promise<TransactionSignature>;
331
331
  getUpdateUserIdleIx(userAccountPublicKey: PublicKey, userAccount: UserAccount): Promise<TransactionInstruction>;
332
+ updateUserOpenOrdersCount(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams): Promise<TransactionSignature>;
333
+ getUpdateUserOpenOrdersCountIx(userAccountPublicKey: PublicKey, userAccount: UserAccount): Promise<TransactionInstruction>;
332
334
  placeAndTakePerpOrder(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<TransactionSignature>;
333
335
  getPlaceAndTakePerpOrderIx(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo): Promise<TransactionInstruction>;
334
336
  placeAndMakePerpOrder(orderParams: OptionalOrderParams, takerInfo: TakerInfo, referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<TransactionSignature>;
@@ -51,6 +51,7 @@ const spotPosition_1 = require("./math/spotPosition");
51
51
  const market_1 = require("./math/market");
52
52
  const fetch_1 = require("./accounts/fetch");
53
53
  const spotMarket_1 = require("./math/spotMarket");
54
+ const memcmp_1 = require("./memcmp");
54
55
  /**
55
56
  * # DriftClient
56
57
  * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
@@ -515,14 +516,7 @@ class DriftClient {
515
516
  async fetchAllUserAccounts(includeIdle = true) {
516
517
  let filters = undefined;
517
518
  if (!includeIdle) {
518
- filters = [
519
- {
520
- memcmp: {
521
- offset: 4350,
522
- bytes: bs58_1.default.encode(Uint8Array.from([0])),
523
- },
524
- },
525
- ];
519
+ filters = [(0, memcmp_1.getNonIdleUserFilter)()];
526
520
  }
527
521
  return (await this.program.account.user.all(filters));
528
522
  }
@@ -2024,7 +2018,7 @@ class DriftClient {
2024
2018
  ...jupiterInstructions,
2025
2019
  endSwapIx,
2026
2020
  ];
2027
- const tx = await this.buildTransaction(instructions, txParams, 0, lookupTables);
2021
+ const tx = (await this.buildTransaction(instructions, txParams, 0, lookupTables));
2028
2022
  const { txSig, slot } = await this.sendTransaction(tx);
2029
2023
  this.spotMarketLastSlotCache.set(outMarketIndex, slot);
2030
2024
  this.spotMarketLastSlotCache.set(inMarketIndex, slot);
@@ -2152,6 +2146,25 @@ class DriftClient {
2152
2146
  remainingAccounts,
2153
2147
  });
2154
2148
  }
2149
+ async updateUserOpenOrdersCount(userAccountPublicKey, user, txParams) {
2150
+ const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getUpdateUserOpenOrdersCountIx(userAccountPublicKey, user), txParams), [], this.opts);
2151
+ return txSig;
2152
+ }
2153
+ async getUpdateUserOpenOrdersCountIx(userAccountPublicKey, userAccount) {
2154
+ const fillerPublicKey = await this.getUserAccountPublicKey();
2155
+ const remainingAccounts = this.getRemainingAccounts({
2156
+ userAccounts: [userAccount],
2157
+ });
2158
+ return await this.program.instruction.updateUserOpenOrdersCount({
2159
+ accounts: {
2160
+ state: await this.getStatePublicKey(),
2161
+ filler: fillerPublicKey,
2162
+ user: userAccountPublicKey,
2163
+ authority: this.wallet.publicKey,
2164
+ },
2165
+ remainingAccounts,
2166
+ });
2167
+ }
2155
2168
  async placeAndTakePerpOrder(orderParams, makerInfo, referrerInfo, txParams) {
2156
2169
  const { txSig, slot } = await this.sendTransaction(await this.buildTransaction(await this.getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo), txParams), [], this.opts);
2157
2170
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
@@ -9,6 +9,7 @@ export declare class EventSubscriber {
9
9
  private connection;
10
10
  private program;
11
11
  private options;
12
+ private address;
12
13
  private eventListMap;
13
14
  private txEventCache;
14
15
  private awaitTxPromises;
@@ -11,12 +11,14 @@ const events_1 = require("events");
11
11
  const sort_1 = require("./sort");
12
12
  class EventSubscriber {
13
13
  constructor(connection, program, options = types_1.DefaultEventSubscriptionOptions) {
14
+ var _a;
14
15
  this.connection = connection;
15
16
  this.program = program;
16
17
  this.options = options;
17
18
  this.awaitTxPromises = new Map();
18
19
  this.awaitTxResolver = new Map();
19
20
  this.options = Object.assign({}, types_1.DefaultEventSubscriptionOptions, options);
21
+ this.address = (_a = this.options.address) !== null && _a !== void 0 ? _a : program.programId;
20
22
  this.txEventCache = new txEventCache_1.TxEventCache(this.options.maxTx);
21
23
  this.eventListMap = new Map();
22
24
  for (const eventType of this.options.eventTypes) {
@@ -24,10 +26,10 @@ class EventSubscriber {
24
26
  }
25
27
  this.eventEmitter = new events_1.EventEmitter();
26
28
  if (this.options.logProviderConfig.type === 'websocket') {
27
- this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(this.connection, this.program.programId, this.options.commitment);
29
+ this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(this.connection, this.address, this.options.commitment);
28
30
  }
29
31
  else {
30
- this.logProvider = new pollingLogProvider_1.PollingLogProvider(this.connection, this.program.programId, options.commitment, this.options.logProviderConfig.frequency);
32
+ this.logProvider = new pollingLogProvider_1.PollingLogProvider(this.connection, this.address, options.commitment, this.options.logProviderConfig.frequency);
31
33
  }
32
34
  }
33
35
  async subscribe() {
@@ -80,7 +82,7 @@ class EventSubscriber {
80
82
  let beforeTx = undefined;
81
83
  const untilTx = this.options.untilTx;
82
84
  while (txFetched < this.options.maxTx) {
83
- const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.program.programId, this.options.commitment === 'finalized' ? 'finalized' : 'confirmed', beforeTx, untilTx);
85
+ const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.address, this.options.commitment === 'finalized' ? 'finalized' : 'confirmed', beforeTx, untilTx);
84
86
  if (response === undefined) {
85
87
  break;
86
88
  }
@@ -14,7 +14,7 @@ type FetchLogsResponse = {
14
14
  transactionLogs: Log[];
15
15
  mostRecentBlockTime: number | undefined;
16
16
  };
17
- export declare function fetchLogs(connection: Connection, programId: PublicKey, finality: Finality, beforeTx?: TransactionSignature, untilTx?: TransactionSignature, limit?: number): Promise<FetchLogsResponse>;
17
+ export declare function fetchLogs(connection: Connection, address: PublicKey, finality: Finality, beforeTx?: TransactionSignature, untilTx?: TransactionSignature, limit?: number): Promise<FetchLogsResponse>;
18
18
  export declare class LogParser {
19
19
  private program;
20
20
  constructor(program: Program);
@@ -8,8 +8,8 @@ function mapTransactionResponseToLog(transaction) {
8
8
  logs: transaction.meta.logMessages,
9
9
  };
10
10
  }
11
- async function fetchLogs(connection, programId, finality, beforeTx, untilTx, limit) {
12
- const signatures = await connection.getSignaturesForAddress(programId, {
11
+ async function fetchLogs(connection, address, finality, beforeTx, untilTx, limit) {
12
+ const signatures = await connection.getSignaturesForAddress(address, {
13
13
  before: beforeTx,
14
14
  until: untilTx,
15
15
  limit,
@@ -2,14 +2,14 @@ import { LogProvider, logProviderCallback } from './types';
2
2
  import { Commitment, Connection, PublicKey } from '@solana/web3.js';
3
3
  export declare class PollingLogProvider implements LogProvider {
4
4
  private connection;
5
- private programId;
5
+ private address;
6
6
  private frequency;
7
7
  private finality;
8
8
  private intervalId;
9
9
  private mostRecentSeenTx?;
10
10
  private mutex;
11
11
  private firstFetch;
12
- constructor(connection: Connection, programId: PublicKey, commitment: Commitment, frequency?: number);
12
+ constructor(connection: Connection, address: PublicKey, commitment: Commitment, frequency?: number);
13
13
  subscribe(callback: logProviderCallback, skipHistory?: boolean): boolean;
14
14
  isSubscribed(): boolean;
15
15
  unsubscribe(): Promise<boolean>;
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PollingLogProvider = void 0;
4
4
  const fetchLogs_1 = require("./fetchLogs");
5
5
  class PollingLogProvider {
6
- constructor(connection, programId, commitment, frequency = 15 * 1000) {
6
+ constructor(connection, address, commitment, frequency = 15 * 1000) {
7
7
  this.connection = connection;
8
- this.programId = programId;
8
+ this.address = address;
9
9
  this.frequency = frequency;
10
10
  this.firstFetch = true;
11
11
  this.finality = commitment === 'finalized' ? 'finalized' : 'confirmed';
@@ -20,7 +20,7 @@ class PollingLogProvider {
20
20
  }
21
21
  this.mutex = 1;
22
22
  try {
23
- const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.programId, this.finality, undefined, this.mostRecentSeenTx,
23
+ const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.address, this.finality, undefined, this.mostRecentSeenTx,
24
24
  // If skipping history, only fetch one log back, not the maximum amount available
25
25
  skipHistory && this.firstFetch ? 1 : undefined);
26
26
  if (response === undefined) {
@@ -1,6 +1,7 @@
1
- import { Commitment, TransactionSignature } from '@solana/web3.js';
1
+ import { Commitment, PublicKey, TransactionSignature } from '@solana/web3.js';
2
2
  import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, NewUserRecord, OrderActionRecord, OrderRecord, SettlePnlRecord, LPRecord, InsuranceFundRecord, SpotInterestRecord, InsuranceFundStakeRecord, CurveRecord, SwapRecord } from '../index';
3
3
  export type EventSubscriptionOptions = {
4
+ address?: PublicKey;
4
5
  eventTypes?: EventType[];
5
6
  maxEventsPerType?: number;
6
7
  orderBy?: EventSubscriptionOrderBy;
@@ -2,10 +2,10 @@ import { LogProvider, logProviderCallback } from './types';
2
2
  import { Commitment, Connection, PublicKey } from '@solana/web3.js';
3
3
  export declare class WebSocketLogProvider implements LogProvider {
4
4
  private connection;
5
- private programId;
5
+ private address;
6
6
  private commitment;
7
7
  private subscriptionId;
8
- constructor(connection: Connection, programId: PublicKey, commitment: Commitment);
8
+ constructor(connection: Connection, address: PublicKey, commitment: Commitment);
9
9
  subscribe(callback: logProviderCallback): boolean;
10
10
  isSubscribed(): boolean;
11
11
  unsubscribe(): Promise<boolean>;
@@ -2,16 +2,16 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebSocketLogProvider = void 0;
4
4
  class WebSocketLogProvider {
5
- constructor(connection, programId, commitment) {
5
+ constructor(connection, address, commitment) {
6
6
  this.connection = connection;
7
- this.programId = programId;
7
+ this.address = address;
8
8
  this.commitment = commitment;
9
9
  }
10
10
  subscribe(callback) {
11
11
  if (this.subscriptionId) {
12
12
  return true;
13
13
  }
14
- this.subscriptionId = this.connection.onLogs(this.programId, (logs, ctx) => {
14
+ this.subscriptionId = this.connection.onLogs(this.address, (logs, ctx) => {
15
15
  callback(logs.signature, ctx.slot, logs.logs, undefined);
16
16
  }, this.commitment);
17
17
  return true;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.31.0-beta.1",
2
+ "version": "2.31.0-beta.4",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -1305,6 +1305,32 @@
1305
1305
  ],
1306
1306
  "args": []
1307
1307
  },
1308
+ {
1309
+ "name": "updateUserOpenOrdersCount",
1310
+ "accounts": [
1311
+ {
1312
+ "name": "state",
1313
+ "isMut": false,
1314
+ "isSigner": false
1315
+ },
1316
+ {
1317
+ "name": "authority",
1318
+ "isMut": false,
1319
+ "isSigner": true
1320
+ },
1321
+ {
1322
+ "name": "filler",
1323
+ "isMut": true,
1324
+ "isSigner": false
1325
+ },
1326
+ {
1327
+ "name": "user",
1328
+ "isMut": true,
1329
+ "isSigner": false
1330
+ }
1331
+ ],
1332
+ "args": []
1333
+ },
1308
1334
  {
1309
1335
  "name": "settlePnl",
1310
1336
  "accounts": [
@@ -5438,12 +5464,40 @@
5438
5464
  ],
5439
5465
  "type": "bool"
5440
5466
  },
5467
+ {
5468
+ "name": "openOrders",
5469
+ "docs": [
5470
+ "number of open orders"
5471
+ ],
5472
+ "type": "u8"
5473
+ },
5474
+ {
5475
+ "name": "hasOpenOrder",
5476
+ "docs": [
5477
+ "Whether or not user has open order"
5478
+ ],
5479
+ "type": "bool"
5480
+ },
5481
+ {
5482
+ "name": "openAuctions",
5483
+ "docs": [
5484
+ "number of open orders with auction"
5485
+ ],
5486
+ "type": "u8"
5487
+ },
5488
+ {
5489
+ "name": "hasOpenAuction",
5490
+ "docs": [
5491
+ "Whether or not user has open order with auction"
5492
+ ],
5493
+ "type": "bool"
5494
+ },
5441
5495
  {
5442
5496
  "name": "padding",
5443
5497
  "type": {
5444
5498
  "array": [
5445
5499
  "u8",
5446
- 25
5500
+ 21
5447
5501
  ]
5448
5502
  }
5449
5503
  }
@@ -10433,6 +10487,11 @@
10433
10487
  "code": 6250,
10434
10488
  "name": "SpotMarketReduceOnly",
10435
10489
  "msg": "SpotMarketReduceOnly"
10490
+ },
10491
+ {
10492
+ "code": 6251,
10493
+ "name": "FundingWasNotUpdated",
10494
+ "msg": "FundingWasNotUpdated"
10436
10495
  }
10437
10496
  ]
10438
10497
  }
package/lib/index.d.ts CHANGED
@@ -74,4 +74,5 @@ export * from './dlob/orderBookLevels';
74
74
  export * from './userMap/userMap';
75
75
  export * from './userMap/userStatsMap';
76
76
  export * from './math/bankruptcy';
77
+ export * from './orderSubscriber';
77
78
  export { BN, PublicKey, pyth };
package/lib/index.js CHANGED
@@ -98,3 +98,4 @@ __exportStar(require("./dlob/orderBookLevels"), exports);
98
98
  __exportStar(require("./userMap/userMap"), exports);
99
99
  __exportStar(require("./userMap/userStatsMap"), exports);
100
100
  __exportStar(require("./math/bankruptcy"), exports);
101
+ __exportStar(require("./orderSubscriber"), exports);
@@ -189,7 +189,7 @@ function calculateInterestRate(bank) {
189
189
  else {
190
190
  const borrowRateSlope = new anchor_1.BN(bank.optimalBorrowRate)
191
191
  .mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION)
192
- .div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION.sub(new anchor_1.BN(bank.optimalUtilization)));
192
+ .div(new anchor_1.BN(bank.optimalUtilization));
193
193
  interestRate = utilization
194
194
  .mul(borrowRateSlope)
195
195
  .div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION);
@@ -0,0 +1,5 @@
1
+ import { MemcmpFilter } from '@solana/web3.js';
2
+ export declare function getUserFilter(): MemcmpFilter;
3
+ export declare function getNonIdleUserFilter(): MemcmpFilter;
4
+ export declare function getUserWithOrderFilter(): MemcmpFilter;
5
+ export declare function getUserWithAuctionFilter(): MemcmpFilter;
package/lib/memcmp.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getUserWithAuctionFilter = exports.getUserWithOrderFilter = exports.getNonIdleUserFilter = exports.getUserFilter = void 0;
7
+ const bs58_1 = __importDefault(require("bs58"));
8
+ const anchor_1 = require("@coral-xyz/anchor");
9
+ function getUserFilter() {
10
+ return {
11
+ memcmp: {
12
+ offset: 0,
13
+ bytes: bs58_1.default.encode(anchor_1.BorshAccountsCoder.accountDiscriminator('User')),
14
+ },
15
+ };
16
+ }
17
+ exports.getUserFilter = getUserFilter;
18
+ function getNonIdleUserFilter() {
19
+ return {
20
+ memcmp: {
21
+ offset: 4350,
22
+ bytes: bs58_1.default.encode(Uint8Array.from([0])),
23
+ },
24
+ };
25
+ }
26
+ exports.getNonIdleUserFilter = getNonIdleUserFilter;
27
+ function getUserWithOrderFilter() {
28
+ return {
29
+ memcmp: {
30
+ offset: 4352,
31
+ bytes: bs58_1.default.encode(Uint8Array.from([1])),
32
+ },
33
+ };
34
+ }
35
+ exports.getUserWithOrderFilter = getUserWithOrderFilter;
36
+ function getUserWithAuctionFilter() {
37
+ return {
38
+ memcmp: {
39
+ offset: 4354,
40
+ bytes: bs58_1.default.encode(Uint8Array.from([1])),
41
+ },
42
+ };
43
+ }
44
+ exports.getUserWithAuctionFilter = getUserWithAuctionFilter;
@@ -0,0 +1,24 @@
1
+ /// <reference types="node" />
2
+ import { DriftClient } from '../driftClient';
3
+ import { UserAccount } from '../types';
4
+ import { Buffer } from 'buffer';
5
+ import { DLOB } from '../dlob/DLOB';
6
+ import { OrderSubscriberConfig } from './types';
7
+ import { PollingSubscription } from './PollingSubscription';
8
+ import { WebsocketSubscription } from './WebsocketSubscription';
9
+ export declare class OrderSubscriber {
10
+ driftClient: DriftClient;
11
+ usersAccounts: Map<string, {
12
+ slot: number;
13
+ userAccount: UserAccount;
14
+ }>;
15
+ subscription: PollingSubscription | WebsocketSubscription;
16
+ fetchPromise?: Promise<void>;
17
+ fetchPromiseResolver: () => void;
18
+ constructor(config: OrderSubscriberConfig);
19
+ subscribe(): Promise<void>;
20
+ fetch(): Promise<void>;
21
+ tryUpdateUserAccount(key: string, buffer: Buffer, slot: number): void;
22
+ getDLOB(slot: number): Promise<DLOB>;
23
+ unsubscribe(): Promise<void>;
24
+ }
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OrderSubscriber = void 0;
4
+ const memcmp_1 = require("../memcmp");
5
+ const web3_js_1 = require("@solana/web3.js");
6
+ const buffer_1 = require("buffer");
7
+ const DLOB_1 = require("../dlob/DLOB");
8
+ const PollingSubscription_1 = require("./PollingSubscription");
9
+ const WebsocketSubscription_1 = require("./WebsocketSubscription");
10
+ class OrderSubscriber {
11
+ constructor(config) {
12
+ this.usersAccounts = new Map();
13
+ this.driftClient = config.driftClient;
14
+ if (config.subscriptionConfig.type === 'polling') {
15
+ this.subscription = new PollingSubscription_1.PollingSubscription({
16
+ orderSubscriber: this,
17
+ frequency: config.subscriptionConfig.frequency,
18
+ });
19
+ }
20
+ else {
21
+ this.subscription = new WebsocketSubscription_1.WebsocketSubscription({
22
+ orderSubscriber: this,
23
+ skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
24
+ });
25
+ }
26
+ }
27
+ async subscribe() {
28
+ await this.subscription.subscribe();
29
+ }
30
+ async fetch() {
31
+ if (this.fetchPromise) {
32
+ return this.fetchPromise;
33
+ }
34
+ this.fetchPromise = new Promise((resolver) => {
35
+ this.fetchPromiseResolver = resolver;
36
+ });
37
+ try {
38
+ const rpcRequestArgs = [
39
+ this.driftClient.program.programId.toBase58(),
40
+ {
41
+ commitment: this.driftClient.opts.commitment,
42
+ filters: [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getUserWithOrderFilter)()],
43
+ encoding: 'base64',
44
+ withContext: true,
45
+ },
46
+ ];
47
+ const rpcJSONResponse =
48
+ // @ts-ignore
49
+ await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
50
+ const rpcResponseAndContext = rpcJSONResponse.result;
51
+ const slot = rpcResponseAndContext.context.slot;
52
+ const programAccountSet = new Set();
53
+ for (const programAccount of rpcResponseAndContext.value) {
54
+ const key = programAccount.pubkey.toString();
55
+ // @ts-ignore
56
+ const buffer = buffer_1.Buffer.from(programAccount.account.data[0], programAccount.account.data[1]);
57
+ programAccountSet.add(key);
58
+ this.tryUpdateUserAccount(key, buffer, slot);
59
+ }
60
+ for (const key of this.usersAccounts.keys()) {
61
+ if (!programAccountSet.has(key)) {
62
+ this.usersAccounts.delete(key);
63
+ }
64
+ }
65
+ }
66
+ catch (e) {
67
+ console.error(e);
68
+ }
69
+ finally {
70
+ this.fetchPromiseResolver();
71
+ this.fetchPromise = undefined;
72
+ }
73
+ }
74
+ tryUpdateUserAccount(key, buffer, slot) {
75
+ const slotAndUserAccount = this.usersAccounts.get(key);
76
+ if (!slotAndUserAccount || slotAndUserAccount.slot < slot) {
77
+ const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', buffer);
78
+ if (userAccount.hasOpenOrder) {
79
+ this.usersAccounts.set(key, { slot, userAccount });
80
+ }
81
+ else {
82
+ this.usersAccounts.delete(key);
83
+ }
84
+ }
85
+ }
86
+ async getDLOB(slot) {
87
+ const dlob = new DLOB_1.DLOB();
88
+ for (const [key, { userAccount }] of this.usersAccounts.entries()) {
89
+ const userAccountPubkey = new web3_js_1.PublicKey(key);
90
+ for (const order of userAccount.orders) {
91
+ dlob.insertOrder(order, userAccountPubkey, slot);
92
+ }
93
+ }
94
+ return dlob;
95
+ }
96
+ async unsubscribe() {
97
+ await this.subscription.unsubscribe();
98
+ }
99
+ }
100
+ exports.OrderSubscriber = OrderSubscriber;
@@ -0,0 +1,13 @@
1
+ /// <reference types="node" />
2
+ import { OrderSubscriber } from './OrderSubscriber';
3
+ export declare class PollingSubscription {
4
+ private orderSubscriber;
5
+ private frequency;
6
+ intervalId?: NodeJS.Timer;
7
+ constructor({ orderSubscriber, frequency, }: {
8
+ orderSubscriber: OrderSubscriber;
9
+ frequency: number;
10
+ });
11
+ subscribe(): Promise<void>;
12
+ unsubscribe(): Promise<void>;
13
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PollingSubscription = void 0;
4
+ class PollingSubscription {
5
+ constructor({ orderSubscriber, frequency, }) {
6
+ this.orderSubscriber = orderSubscriber;
7
+ this.frequency = frequency;
8
+ }
9
+ async subscribe() {
10
+ if (this.intervalId) {
11
+ return;
12
+ }
13
+ this.intervalId = setInterval(this.orderSubscriber.fetch.bind(this.orderSubscriber), this.frequency);
14
+ await this.orderSubscriber.fetch();
15
+ }
16
+ async unsubscribe() {
17
+ if (this.intervalId) {
18
+ clearInterval(this.intervalId);
19
+ this.intervalId = undefined;
20
+ }
21
+ }
22
+ }
23
+ exports.PollingSubscription = PollingSubscription;