@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
@@ -0,0 +1,12 @@
1
+ import { OrderSubscriber } from './OrderSubscriber';
2
+ export declare class WebsocketSubscription {
3
+ private orderSubscriber;
4
+ private skipInitialLoad;
5
+ private websocketId;
6
+ constructor({ orderSubscriber, skipInitialLoad, }: {
7
+ orderSubscriber: OrderSubscriber;
8
+ skipInitialLoad?: boolean;
9
+ });
10
+ subscribe(): Promise<void>;
11
+ unsubscribe(): Promise<void>;
12
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebsocketSubscription = void 0;
4
+ const memcmp_1 = require("../memcmp");
5
+ class WebsocketSubscription {
6
+ constructor({ orderSubscriber, skipInitialLoad = false, }) {
7
+ this.orderSubscriber = orderSubscriber;
8
+ this.skipInitialLoad = skipInitialLoad;
9
+ }
10
+ async subscribe() {
11
+ if (this.websocketId) {
12
+ return;
13
+ }
14
+ this.websocketId =
15
+ this.orderSubscriber.driftClient.connection.onProgramAccountChange(this.orderSubscriber.driftClient.program.programId, (keyAccountInfo, context) => {
16
+ const userKey = keyAccountInfo.accountId.toBase58();
17
+ this.orderSubscriber.tryUpdateUserAccount(userKey, keyAccountInfo.accountInfo.data, context.slot);
18
+ }, this.orderSubscriber.driftClient.opts.commitment, [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getNonIdleUserFilter)()]);
19
+ if (!this.skipInitialLoad) {
20
+ await this.orderSubscriber.fetch();
21
+ }
22
+ }
23
+ async unsubscribe() {
24
+ if (this.websocketId) {
25
+ await this.orderSubscriber.driftClient.connection.removeProgramAccountChangeListener(this.websocketId);
26
+ this.websocketId = undefined;
27
+ }
28
+ }
29
+ }
30
+ exports.WebsocketSubscription = WebsocketSubscription;
@@ -0,0 +1,2 @@
1
+ export * from './OrderSubscriber';
2
+ export * from './types';
@@ -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("./OrderSubscriber"), exports);
18
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,11 @@
1
+ import { DriftClient } from '../driftClient';
2
+ export type OrderSubscriberConfig = {
3
+ driftClient: DriftClient;
4
+ subscriptionConfig: {
5
+ type: 'polling';
6
+ frequency: number;
7
+ } | {
8
+ type: 'websocket';
9
+ skipInitialLoad?: boolean;
10
+ };
11
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -55,12 +55,15 @@ class RetryTxSender {
55
55
  return tx;
56
56
  }
57
57
  async sendVersionedTransaction(tx, additionalSigners, opts) {
58
+ additionalSigners === null || additionalSigners === void 0 ? void 0 : additionalSigners.filter((s) => s !== undefined).forEach((kp) => {
59
+ tx.sign([kp]);
60
+ });
58
61
  // @ts-ignore
59
- tx.sign((additionalSigners !== null && additionalSigners !== void 0 ? additionalSigners : []).concat(this.provider.wallet.payer));
62
+ const signedTx = await this.provider.wallet.signTransaction(tx);
60
63
  if (opts === undefined) {
61
64
  opts = this.provider.opts;
62
65
  }
63
- return this.sendRawTransaction(tx.serialize(), opts);
66
+ return this.sendRawTransaction(signedTx.serialize(), opts);
64
67
  }
65
68
  async sendRawTransaction(rawTransaction, opts) {
66
69
  const startTime = this.getTimestamp();
package/lib/types.d.ts CHANGED
@@ -222,7 +222,7 @@ export declare class OrderActionExplanation {
222
222
  orderFilledWithAmmJitLpSplit: {};
223
223
  };
224
224
  static readonly ORDER_FILLED_WITH_LP_JIT: {
225
- orderFilledWithAmmJitLpSplit: {};
225
+ orderFilledWithLpJit: {};
226
226
  };
227
227
  static readonly ORDER_FILLED_WITH_MATCH: {
228
228
  orderFilledWithMatch: {};
@@ -877,6 +877,10 @@ export type UserAccount = {
877
877
  lastActiveSlot: BN;
878
878
  isMarginTradingEnabled: boolean;
879
879
  idle: boolean;
880
+ openOrders: number;
881
+ hasOpenOrder: boolean;
882
+ openAuctions: number;
883
+ hasOpenAuction: boolean;
880
884
  };
881
885
  export type SpotPosition = {
882
886
  marketIndex: number;
package/lib/types.js CHANGED
@@ -138,7 +138,7 @@ OrderActionExplanation.ORDER_FILLED_WITH_AMM_JIT_LP_SPLIT = {
138
138
  orderFilledWithAmmJitLpSplit: {},
139
139
  };
140
140
  OrderActionExplanation.ORDER_FILLED_WITH_LP_JIT = {
141
- orderFilledWithAmmJitLpSplit: {},
141
+ orderFilledWithLpJit: {},
142
142
  };
143
143
  OrderActionExplanation.ORDER_FILLED_WITH_MATCH = {
144
144
  orderFilledWithMatch: {},
@@ -1,13 +1,10 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.UserMap = void 0;
7
4
  const __1 = require("..");
8
5
  const web3_js_1 = require("@solana/web3.js");
9
6
  const buffer_1 = require("buffer");
10
- const bs58_1 = __importDefault(require("bs58"));
7
+ const memcmp_1 = require("../memcmp");
11
8
  class UserMap {
12
9
  /**
13
10
  *
@@ -143,27 +140,15 @@ class UserMap {
143
140
  return this.userMap.size;
144
141
  }
145
142
  async sync() {
146
- let filters = undefined;
143
+ const filters = [(0, memcmp_1.getUserFilter)()];
147
144
  if (!this.includeIdle) {
148
- filters = [
149
- {
150
- memcmp: {
151
- offset: 4350,
152
- bytes: bs58_1.default.encode(Uint8Array.from([0])),
153
- },
154
- },
155
- ];
145
+ filters.push((0, memcmp_1.getNonIdleUserFilter)());
156
146
  }
157
147
  const rpcRequestArgs = [
158
148
  this.driftClient.program.programId.toBase58(),
159
149
  {
160
150
  commitment: this.driftClient.connection.commitment,
161
- filters: [
162
- {
163
- memcmp: this.driftClient.program.coder.accounts.memcmp('User'),
164
- },
165
- ...(Array.isArray(filters) ? filters : []),
166
- ],
151
+ filters,
167
152
  encoding: 'base64',
168
153
  withContext: true,
169
154
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.31.0-beta.1",
3
+ "version": "2.31.0-beta.4",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -174,6 +174,11 @@ export class BulkAccountLoader {
174
174
 
175
175
  for (const i in rpcResponses) {
176
176
  const rpcResponse = rpcResponses[i];
177
+ if (!rpcResponse.result) {
178
+ console.error('rpc response missing result:');
179
+ console.log(JSON.stringify(rpcResponse));
180
+ continue;
181
+ }
177
182
  const newSlot = rpcResponse.result.context.slot;
178
183
 
179
184
  if (newSlot > this.mostRecentSlot) {
@@ -0,0 +1,50 @@
1
+ import { AuctionSubscriberConfig, AuctionSubscriberEvents } from './types';
2
+ import { DriftClient } from '../driftClient';
3
+ import { getUserFilter, getUserWithAuctionFilter } from '../memcmp';
4
+ import StrictEventEmitter from 'strict-event-emitter-types';
5
+ import { EventEmitter } from 'events';
6
+ import { UserAccount } from '../types';
7
+ import { ConfirmOptions } from '@solana/web3.js';
8
+
9
+ export class AuctionSubscriber {
10
+ private driftClient: DriftClient;
11
+ private opts: ConfirmOptions;
12
+
13
+ eventEmitter: StrictEventEmitter<EventEmitter, AuctionSubscriberEvents>;
14
+
15
+ private websocketId: number;
16
+
17
+ constructor({ driftClient, opts }: AuctionSubscriberConfig) {
18
+ this.driftClient = driftClient;
19
+ this.opts = opts || this.driftClient.opts;
20
+ }
21
+
22
+ public async subscribe() {
23
+ this.websocketId = this.driftClient.connection.onProgramAccountChange(
24
+ this.driftClient.program.programId,
25
+ (keyAccountInfo, context) => {
26
+ const userAccount =
27
+ this.driftClient.program.account.user.coder.accounts.decode(
28
+ 'User',
29
+ keyAccountInfo.accountInfo.data
30
+ ) as UserAccount;
31
+ this.eventEmitter.emit(
32
+ 'onAccountUpdate',
33
+ userAccount,
34
+ keyAccountInfo.accountId,
35
+ context.slot
36
+ );
37
+ },
38
+ this.driftClient.opts.commitment,
39
+ [getUserFilter(), getUserWithAuctionFilter()]
40
+ );
41
+ }
42
+
43
+ public async unsubscribe() {
44
+ if (this.websocketId) {
45
+ await this.driftClient.connection.removeProgramAccountChangeListener(
46
+ this.websocketId
47
+ );
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,2 @@
1
+ export * from './types';
2
+ export * from './auctionSubscriber';
@@ -0,0 +1,16 @@
1
+ import { DriftClient } from '../driftClient';
2
+ import { UserAccount } from '../types';
3
+ import { ConfirmOptions, PublicKey } from '@solana/web3.js';
4
+
5
+ export type AuctionSubscriberConfig = {
6
+ driftClient: DriftClient;
7
+ opts?: ConfirmOptions;
8
+ };
9
+
10
+ export interface AuctionSubscriberEvents {
11
+ onAccountUpdate: (
12
+ account: UserAccount,
13
+ pubkey: PublicKey,
14
+ slot: number
15
+ ) => void;
16
+ }
@@ -114,6 +114,7 @@ import { calculateMarketMaxAvailableInsurance } from './math/market';
114
114
  import { fetchUserStatsAccount } from './accounts/fetch';
115
115
  import { castNumberToSpotPrecision } from './math/spotMarket';
116
116
  import { JupiterClient, Route, SwapMode } from './jupiter/jupiterClient';
117
+ import { getNonIdleUserFilter } from './memcmp';
117
118
 
118
119
  type RemainingAccountParams = {
119
120
  userAccounts: UserAccount[];
@@ -897,14 +898,7 @@ export class DriftClient {
897
898
  ): Promise<ProgramAccount<UserAccount>[]> {
898
899
  let filters = undefined;
899
900
  if (!includeIdle) {
900
- filters = [
901
- {
902
- memcmp: {
903
- offset: 4350,
904
- bytes: bs58.encode(Uint8Array.from([0])),
905
- },
906
- },
907
- ];
901
+ filters = [getNonIdleUserFilter()];
908
902
  }
909
903
  return (await this.program.account.user.all(
910
904
  filters
@@ -3395,12 +3389,12 @@ export class DriftClient {
3395
3389
  endSwapIx,
3396
3390
  ];
3397
3391
 
3398
- const tx = await this.buildTransaction(
3392
+ const tx = (await this.buildTransaction(
3399
3393
  instructions,
3400
3394
  txParams,
3401
3395
  0,
3402
3396
  lookupTables
3403
- );
3397
+ )) as VersionedTransaction;
3404
3398
 
3405
3399
  const { txSig, slot } = await this.sendTransaction(tx);
3406
3400
  this.spotMarketLastSlotCache.set(outMarketIndex, slot);
@@ -3625,6 +3619,43 @@ export class DriftClient {
3625
3619
  });
3626
3620
  }
3627
3621
 
3622
+ public async updateUserOpenOrdersCount(
3623
+ userAccountPublicKey: PublicKey,
3624
+ user: UserAccount,
3625
+ txParams?: TxParams
3626
+ ): Promise<TransactionSignature> {
3627
+ const { txSig } = await this.sendTransaction(
3628
+ await this.buildTransaction(
3629
+ await this.getUpdateUserOpenOrdersCountIx(userAccountPublicKey, user),
3630
+ txParams
3631
+ ),
3632
+ [],
3633
+ this.opts
3634
+ );
3635
+ return txSig;
3636
+ }
3637
+
3638
+ public async getUpdateUserOpenOrdersCountIx(
3639
+ userAccountPublicKey: PublicKey,
3640
+ userAccount: UserAccount
3641
+ ): Promise<TransactionInstruction> {
3642
+ const fillerPublicKey = await this.getUserAccountPublicKey();
3643
+
3644
+ const remainingAccounts = this.getRemainingAccounts({
3645
+ userAccounts: [userAccount],
3646
+ });
3647
+
3648
+ return await this.program.instruction.updateUserOpenOrdersCount({
3649
+ accounts: {
3650
+ state: await this.getStatePublicKey(),
3651
+ filler: fillerPublicKey,
3652
+ user: userAccountPublicKey,
3653
+ authority: this.wallet.publicKey,
3654
+ },
3655
+ remainingAccounts,
3656
+ });
3657
+ }
3658
+
3628
3659
  public async placeAndTakePerpOrder(
3629
3660
  orderParams: OptionalOrderParams,
3630
3661
  makerInfo?: MakerInfo | MakerInfo[],
@@ -1,4 +1,4 @@
1
- import { Connection, TransactionSignature } from '@solana/web3.js';
1
+ import { Connection, PublicKey, TransactionSignature } from '@solana/web3.js';
2
2
  import { Program } from '@coral-xyz/anchor';
3
3
  import {
4
4
  DefaultEventSubscriptionOptions,
@@ -19,6 +19,7 @@ import StrictEventEmitter from 'strict-event-emitter-types';
19
19
  import { getSortFn } from './sort';
20
20
 
21
21
  export class EventSubscriber {
22
+ private address: PublicKey;
22
23
  private eventListMap: Map<EventType, EventList<EventType>>;
23
24
  private txEventCache: TxEventCache;
24
25
  private awaitTxPromises = new Map<string, Promise<void>>();
@@ -35,6 +36,7 @@ export class EventSubscriber {
35
36
  private options: EventSubscriptionOptions = DefaultEventSubscriptionOptions
36
37
  ) {
37
38
  this.options = Object.assign({}, DefaultEventSubscriptionOptions, options);
39
+ this.address = this.options.address ?? program.programId;
38
40
  this.txEventCache = new TxEventCache(this.options.maxTx);
39
41
  this.eventListMap = new Map<EventType, EventList<EventType>>();
40
42
  for (const eventType of this.options.eventTypes) {
@@ -52,13 +54,13 @@ export class EventSubscriber {
52
54
  if (this.options.logProviderConfig.type === 'websocket') {
53
55
  this.logProvider = new WebSocketLogProvider(
54
56
  this.connection,
55
- this.program.programId,
57
+ this.address,
56
58
  this.options.commitment
57
59
  );
58
60
  } else {
59
61
  this.logProvider = new PollingLogProvider(
60
62
  this.connection,
61
- this.program.programId,
63
+ this.address,
62
64
  options.commitment,
63
65
  this.options.logProviderConfig.frequency
64
66
  );
@@ -134,7 +136,7 @@ export class EventSubscriber {
134
136
  while (txFetched < this.options.maxTx) {
135
137
  const response = await fetchLogs(
136
138
  this.connection,
137
- this.program.programId,
139
+ this.address,
138
140
  this.options.commitment === 'finalized' ? 'finalized' : 'confirmed',
139
141
  beforeTx,
140
142
  untilTx
@@ -31,14 +31,14 @@ function mapTransactionResponseToLog(
31
31
 
32
32
  export async function fetchLogs(
33
33
  connection: Connection,
34
- programId: PublicKey,
34
+ address: PublicKey,
35
35
  finality: Finality,
36
36
  beforeTx?: TransactionSignature,
37
37
  untilTx?: TransactionSignature,
38
38
  limit?: number
39
39
  ): Promise<FetchLogsResponse> {
40
40
  const signatures = await connection.getSignaturesForAddress(
41
- programId,
41
+ address,
42
42
  {
43
43
  before: beforeTx,
44
44
  until: untilTx,
@@ -17,7 +17,7 @@ export class PollingLogProvider implements LogProvider {
17
17
 
18
18
  public constructor(
19
19
  private connection: Connection,
20
- private programId: PublicKey,
20
+ private address: PublicKey,
21
21
  commitment: Commitment,
22
22
  private frequency = 15 * 1000
23
23
  ) {
@@ -41,7 +41,7 @@ export class PollingLogProvider implements LogProvider {
41
41
  try {
42
42
  const response = await fetchLogs(
43
43
  this.connection,
44
- this.programId,
44
+ this.address,
45
45
  this.finality,
46
46
  undefined,
47
47
  this.mostRecentSeenTx,
@@ -1,4 +1,4 @@
1
- import { Commitment, TransactionSignature } from '@solana/web3.js';
1
+ import { Commitment, PublicKey, TransactionSignature } from '@solana/web3.js';
2
2
  import {
3
3
  DepositRecord,
4
4
  FundingPaymentRecord,
@@ -17,6 +17,7 @@ import {
17
17
  } from '../index';
18
18
 
19
19
  export type EventSubscriptionOptions = {
20
+ address?: PublicKey;
20
21
  eventTypes?: EventType[];
21
22
  maxEventsPerType?: number;
22
23
  orderBy?: EventSubscriptionOrderBy;
@@ -5,7 +5,7 @@ export class WebSocketLogProvider implements LogProvider {
5
5
  private subscriptionId: number;
6
6
  public constructor(
7
7
  private connection: Connection,
8
- private programId: PublicKey,
8
+ private address: PublicKey,
9
9
  private commitment: Commitment
10
10
  ) {}
11
11
 
@@ -15,7 +15,7 @@ export class WebSocketLogProvider implements LogProvider {
15
15
  }
16
16
 
17
17
  this.subscriptionId = this.connection.onLogs(
18
- this.programId,
18
+ this.address,
19
19
  (logs, ctx) => {
20
20
  callback(logs.signature, ctx.slot, logs.logs, undefined);
21
21
  },
@@ -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/src/index.ts CHANGED
@@ -76,5 +76,6 @@ export * from './dlob/orderBookLevels';
76
76
  export * from './userMap/userMap';
77
77
  export * from './userMap/userStatsMap';
78
78
  export * from './math/bankruptcy';
79
+ export * from './orderSubscriber';
79
80
 
80
81
  export { BN, PublicKey, pyth };
@@ -282,9 +282,7 @@ export function calculateInterestRate(bank: SpotMarketAccount): BN {
282
282
  } else {
283
283
  const borrowRateSlope = new BN(bank.optimalBorrowRate)
284
284
  .mul(SPOT_MARKET_UTILIZATION_PRECISION)
285
- .div(
286
- SPOT_MARKET_UTILIZATION_PRECISION.sub(new BN(bank.optimalUtilization))
287
- );
285
+ .div(new BN(bank.optimalUtilization));
288
286
 
289
287
  interestRate = utilization
290
288
  .mul(borrowRateSlope)
package/src/memcmp.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { MemcmpFilter } from '@solana/web3.js';
2
+ import bs58 from 'bs58';
3
+ import { BorshAccountsCoder } from '@coral-xyz/anchor';
4
+
5
+ export function getUserFilter(): MemcmpFilter {
6
+ return {
7
+ memcmp: {
8
+ offset: 0,
9
+ bytes: bs58.encode(BorshAccountsCoder.accountDiscriminator('User')),
10
+ },
11
+ };
12
+ }
13
+
14
+ export function getNonIdleUserFilter(): MemcmpFilter {
15
+ return {
16
+ memcmp: {
17
+ offset: 4350,
18
+ bytes: bs58.encode(Uint8Array.from([0])),
19
+ },
20
+ };
21
+ }
22
+
23
+ export function getUserWithOrderFilter(): MemcmpFilter {
24
+ return {
25
+ memcmp: {
26
+ offset: 4352,
27
+ bytes: bs58.encode(Uint8Array.from([1])),
28
+ },
29
+ };
30
+ }
31
+
32
+ export function getUserWithAuctionFilter(): MemcmpFilter {
33
+ return {
34
+ memcmp: {
35
+ offset: 4354,
36
+ bytes: bs58.encode(Uint8Array.from([1])),
37
+ },
38
+ };
39
+ }