@drift-labs/sdk 2.145.0 → 2.146.0-alpha.13

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 (99) hide show
  1. package/.env +4 -0
  2. package/VERSION +1 -1
  3. package/lib/browser/accounts/grpcMultiUserAccountSubscriber.js +8 -1
  4. package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.d.ts +99 -7
  5. package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.js +435 -144
  6. package/lib/browser/adminClient.d.ts +5 -1
  7. package/lib/browser/adminClient.js +57 -23
  8. package/lib/browser/constants/numericConstants.d.ts +2 -0
  9. package/lib/browser/constants/numericConstants.js +5 -1
  10. package/lib/browser/constants/perpMarkets.js +0 -2
  11. package/lib/browser/decode/user.js +4 -0
  12. package/lib/browser/driftClient.d.ts +25 -10
  13. package/lib/browser/driftClient.js +238 -41
  14. package/lib/browser/driftClientConfig.d.ts +7 -2
  15. package/lib/browser/idl/drift.json +245 -22
  16. package/lib/browser/index.d.ts +4 -0
  17. package/lib/browser/index.js +9 -1
  18. package/lib/browser/marginCalculation.d.ts +86 -0
  19. package/lib/browser/marginCalculation.js +209 -0
  20. package/lib/browser/math/margin.d.ts +1 -1
  21. package/lib/browser/math/margin.js +8 -1
  22. package/lib/browser/math/position.d.ts +1 -0
  23. package/lib/browser/math/position.js +10 -2
  24. package/lib/browser/math/spotPosition.d.ts +1 -1
  25. package/lib/browser/math/spotPosition.js +3 -2
  26. package/lib/browser/math/superStake.d.ts +3 -2
  27. package/lib/browser/types.d.ts +13 -0
  28. package/lib/browser/types.js +12 -1
  29. package/lib/browser/user.d.ts +59 -11
  30. package/lib/browser/user.js +348 -43
  31. package/lib/node/accounts/grpcMultiUserAccountSubscriber.d.ts.map +1 -1
  32. package/lib/node/accounts/grpcMultiUserAccountSubscriber.js +8 -1
  33. package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts +99 -7
  34. package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts.map +1 -1
  35. package/lib/node/accounts/webSocketProgramAccountSubscriberV2.js +435 -144
  36. package/lib/node/adminClient.d.ts +5 -1
  37. package/lib/node/adminClient.d.ts.map +1 -1
  38. package/lib/node/adminClient.js +57 -23
  39. package/lib/node/constants/numericConstants.d.ts +2 -0
  40. package/lib/node/constants/numericConstants.d.ts.map +1 -1
  41. package/lib/node/constants/numericConstants.js +5 -1
  42. package/lib/node/constants/perpMarkets.d.ts.map +1 -1
  43. package/lib/node/constants/perpMarkets.js +0 -2
  44. package/lib/node/decode/user.d.ts.map +1 -1
  45. package/lib/node/decode/user.js +4 -0
  46. package/lib/node/driftClient.d.ts +25 -10
  47. package/lib/node/driftClient.d.ts.map +1 -1
  48. package/lib/node/driftClient.js +238 -41
  49. package/lib/node/driftClientConfig.d.ts +7 -2
  50. package/lib/node/driftClientConfig.d.ts.map +1 -1
  51. package/lib/node/idl/drift.json +245 -22
  52. package/lib/node/index.d.ts +4 -0
  53. package/lib/node/index.d.ts.map +1 -1
  54. package/lib/node/index.js +9 -1
  55. package/lib/node/marginCalculation.d.ts +87 -0
  56. package/lib/node/marginCalculation.d.ts.map +1 -0
  57. package/lib/node/marginCalculation.js +209 -0
  58. package/lib/node/math/margin.d.ts +1 -1
  59. package/lib/node/math/margin.d.ts.map +1 -1
  60. package/lib/node/math/margin.js +8 -1
  61. package/lib/node/math/position.d.ts +1 -0
  62. package/lib/node/math/position.d.ts.map +1 -1
  63. package/lib/node/math/position.js +10 -2
  64. package/lib/node/math/spotPosition.d.ts +1 -1
  65. package/lib/node/math/spotPosition.d.ts.map +1 -1
  66. package/lib/node/math/spotPosition.js +3 -2
  67. package/lib/node/math/superStake.d.ts +3 -2
  68. package/lib/node/math/superStake.d.ts.map +1 -1
  69. package/lib/node/types.d.ts +13 -0
  70. package/lib/node/types.d.ts.map +1 -1
  71. package/lib/node/types.js +12 -1
  72. package/lib/node/user.d.ts +59 -11
  73. package/lib/node/user.d.ts.map +1 -1
  74. package/lib/node/user.js +348 -43
  75. package/package.json +1 -1
  76. package/scripts/deposit-isolated-positions.ts +110 -0
  77. package/scripts/single-grpc-client-test.ts +71 -21
  78. package/scripts/withdraw-isolated-positions.ts +174 -0
  79. package/src/accounts/grpcMultiUserAccountSubscriber.ts +8 -1
  80. package/src/accounts/webSocketProgramAccountSubscriberV2.ts +566 -167
  81. package/src/adminClient.ts +74 -25
  82. package/src/constants/numericConstants.ts +5 -0
  83. package/src/constants/perpMarkets.ts +0 -3
  84. package/src/decode/user.ts +7 -1
  85. package/src/driftClient.ts +465 -52
  86. package/src/driftClientConfig.ts +15 -8
  87. package/src/idl/drift.json +246 -23
  88. package/src/index.ts +4 -0
  89. package/src/margin/README.md +143 -0
  90. package/src/marginCalculation.ts +306 -0
  91. package/src/math/margin.ts +13 -1
  92. package/src/math/position.ts +12 -2
  93. package/src/math/spotPosition.ts +6 -2
  94. package/src/types.ts +16 -0
  95. package/src/user.ts +623 -81
  96. package/tests/amm/test.ts +1 -1
  97. package/tests/dlob/helpers.ts +6 -3
  98. package/tests/user/getMarginCalculation.ts +405 -0
  99. package/tests/user/test.ts +0 -7
package/.env ADDED
@@ -0,0 +1,4 @@
1
+ # GRPC_ENDPOINT=https://drift-drift-951a.mainnet.rpcpool.com
2
+ # TOKEN=f1ead98714b94a67f82203cce918
3
+ GRPC_ENDPOINT=https://laserstream-mainnet-ams.helius-rpc.com
4
+ TOKEN=ff40c844-e15b-49d0-9d62-8534705aa48b
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.145.0-beta.3
1
+ 2.146.0-alpha.13
@@ -76,7 +76,10 @@ class grpcMultiUserAccountSubscriber {
76
76
  this.listeners.set(key, new Set());
77
77
  this.keyToPk.set(key, userAccountPublicKey);
78
78
  this.pendingAddKeys.add(key);
79
- this.scheduleFlush();
79
+ if (this.isMultiSubscribed) {
80
+ // only schedule flush if already subscribed to the multi-subscriber
81
+ this.scheduleFlush();
82
+ }
80
83
  }
81
84
  };
82
85
  const perUser = {
@@ -110,6 +113,10 @@ class grpcMultiUserAccountSubscriber {
110
113
  this.updateData(account, 0);
111
114
  },
112
115
  updateData(userAccount, slot) {
116
+ const existingData = parent.userData.get(key);
117
+ if (existingData && existingData.slot > slot) {
118
+ return;
119
+ }
113
120
  parent.userData.set(key, { data: userAccount, slot });
114
121
  perUserEmitter.emit('userAccountUpdate', userAccount);
115
122
  perUserEmitter.emit('update');
@@ -3,17 +3,75 @@
3
3
  import { BufferAndSlot, ProgramAccountSubscriber, ResubOpts } from './types';
4
4
  import { Program } from '@coral-xyz/anchor';
5
5
  import { Commitment, Context, MemcmpFilter, PublicKey } from '@solana/web3.js';
6
- import { AccountInfoBase, AccountInfoWithBase58EncodedData, AccountInfoWithBase64EncodedData } from 'gill';
7
- export declare class WebSocketProgramAccountSubscriberV2<T> implements ProgramAccountSubscriber<T> {
6
+ import { AccountInfoBase, AccountInfoWithBase58EncodedData, AccountInfoWithBase64EncodedData, Address } from 'gill';
7
+ /**
8
+ * WebSocketProgramAccountsSubscriberV2
9
+ *
10
+ * High-level overview
11
+ * - WebSocket-first subscriber for Solana program accounts that also layers in
12
+ * targeted polling to detect missed updates reliably.
13
+ * - Emits decoded account updates via the provided `onChange` callback.
14
+ * - Designed to focus extra work on the specific accounts the consumer cares
15
+ * about ("monitored accounts") while keeping baseline WS behavior for the
16
+ * full program subscription.
17
+ *
18
+ * Why polling if this is a WebSocket subscriber?
19
+ * - WS infra can stall, drop, or reorder notifications under network stress or
20
+ * provider hiccups. When that happens, critical account changes can be missed.
21
+ * - To mitigate this, the class accepts a set of accounts (provided via constructor) to monitor
22
+ * and uses light polling to verify whether a WS change was missed.
23
+ * - If polling detects a newer slot with different data than the last seen
24
+ * buffer, a centralized resubscription is triggered to restore a clean stream.
25
+ *
26
+ * Initial fetch (on subscribe)
27
+ * - On `subscribe()`, we first perform a single batched fetch of all monitored
28
+ * accounts ("initial monitor fetch").
29
+ * - Purpose: seed the internal `bufferAndSlotMap` and emit the latest state so
30
+ * consumers have up-to-date data immediately, even before WS events arrive.
31
+ * - This step does not decide resubscription; it only establishes ground truth.
32
+ *
33
+ * Continuous polling (only for monitored accounts)
34
+ * - After seeding, each monitored account is put into a monitoring cycle:
35
+ * 1) If no WS notification for an account is observed for `pollingIntervalMs`,
36
+ * we enqueue it for a batched fetch (buffered for a short window).
37
+ * 2) Once an account enters the "currently polling" set, a shared batch poll
38
+ * runs every `pollingIntervalMs` across all such accounts.
39
+ * 3) If WS notifications resume for an account, that account is removed from
40
+ * the polling set and returns to passive monitoring.
41
+ * - Polling compares the newly fetched buffer with the last stored buffer at a
42
+ * later slot. A difference indicates a missed update; we schedule a single
43
+ * resubscription (coalesced across accounts) to re-sync.
44
+ *
45
+ * Accounts the consumer cares about
46
+ * - Provide accounts up-front via the constructor `accountsToMonitor`, or add
47
+ * them dynamically with `addAccountToMonitor()` and remove with
48
+ * `removeAccountFromMonitor()`.
49
+ * - Only these accounts incur additional polling safeguards; other accounts are
50
+ * still processed from the WS stream normally.
51
+ *
52
+ * Resubscription strategy
53
+ * - Missed updates from any monitored account are coalesced and trigger a single
54
+ * resubscription after a short delay. This avoids rapid churn.
55
+ * - If `resubOpts.resubTimeoutMs` is set, an inactivity timer also performs a
56
+ * batch check of monitored accounts. If a missed update is found, the same
57
+ * centralized resubscription flow is used.
58
+ *
59
+ * Tuning knobs
60
+ * - `setPollingInterval(ms)`: adjust how often monitoring/polling runs
61
+ * (default 30s). Shorter = faster detection, higher RPC load.
62
+ * - Debounced immediate poll (~100ms): batches accounts added to polling right after inactivity.
63
+ * - Batch size for `getMultipleAccounts` is limited to 100, requests are chunked
64
+ * and processed concurrently.
65
+ */
66
+ export declare class WebSocketProgramAccountsSubscriberV2<T> implements ProgramAccountSubscriber<T> {
8
67
  subscriptionName: string;
9
68
  accountDiscriminator: string;
10
- bufferAndSlot?: BufferAndSlot;
11
69
  bufferAndSlotMap: Map<string, BufferAndSlot>;
12
70
  program: Program;
13
71
  decodeBuffer: (accountName: string, ix: Buffer) => T;
14
72
  onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void;
15
73
  listenerId?: number;
16
- resubOpts?: ResubOpts;
74
+ resubOpts: ResubOpts;
17
75
  isUnsubscribing: boolean;
18
76
  timeoutId?: ReturnType<typeof setTimeout>;
19
77
  options: {
@@ -30,24 +88,58 @@ export declare class WebSocketProgramAccountSubscriberV2<T> implements ProgramAc
30
88
  private lastWsNotificationTime;
31
89
  private accountsCurrentlyPolling;
32
90
  private batchPollingTimeout?;
91
+ private debouncedImmediatePollTimeout?;
92
+ private debouncedImmediatePollMs;
93
+ private missedChangeDetected;
94
+ private resubscriptionTimeout?;
95
+ private accountsWithMissedUpdates;
33
96
  constructor(subscriptionName: string, accountDiscriminator: string, program: Program, decodeBufferFn: (accountName: string, ix: Buffer) => T, options?: {
34
97
  filters: MemcmpFilter[];
35
98
  commitment?: Commitment;
36
99
  }, resubOpts?: ResubOpts, accountsToMonitor?: PublicKey[]);
100
+ private handleNotificationLoop;
37
101
  subscribe(onChange: (accountId: PublicKey, data: T, context: Context, buffer: Buffer) => void): Promise<void>;
38
102
  protected setTimeout(): void;
39
103
  handleRpcResponse(context: {
40
104
  slot: bigint;
41
- }, accountInfo?: AccountInfoBase & (AccountInfoWithBase58EncodedData | AccountInfoWithBase64EncodedData)): void;
105
+ }, accountId: Address, accountInfo?: AccountInfoBase & (AccountInfoWithBase58EncodedData | AccountInfoWithBase64EncodedData)['data']): void;
42
106
  private startMonitoringForAccounts;
43
107
  private startMonitoringForAccount;
44
- private startPollingForAccount;
108
+ private scheduleDebouncedImmediatePoll;
45
109
  private startBatchPolling;
46
110
  private pollAllAccounts;
47
- private pollAccount;
111
+ /**
112
+ * Fetches and populates all monitored accounts data without checking for missed changes
113
+ * This is used during initial subscription to populate data
114
+ */
115
+ private fetchAndPopulateAllMonitoredAccounts;
116
+ /**
117
+ * Fetches all monitored accounts and checks for missed changes
118
+ * Returns true if a missed change was detected and resubscription is needed
119
+ */
120
+ private fetchAllMonitoredAccounts;
121
+ private fetchAccountsBatch;
48
122
  private clearPollingTimeouts;
123
+ /**
124
+ * Centralized resubscription handler that only resubscribes once after checking all accounts
125
+ */
126
+ private handleResubscription;
127
+ /**
128
+ * Signal that a missed change was detected and schedule resubscription
129
+ */
130
+ private signalMissedChange;
49
131
  unsubscribe(onResub?: boolean): Promise<void>;
132
+ /**
133
+ * Add an account to the monitored set.
134
+ * - Monitored accounts are subject to initial fetch and periodic batch polls
135
+ * if WS notifications are not observed within `pollingIntervalMs`.
136
+ */
50
137
  addAccountToMonitor(accountId: PublicKey): void;
51
138
  removeAccountFromMonitor(accountId: PublicKey): void;
139
+ /**
140
+ * Set the monitoring/polling interval for monitored accounts.
141
+ * Shorter intervals detect missed updates sooner but increase RPC load.
142
+ */
52
143
  setPollingInterval(intervalMs: number): void;
144
+ private updateBufferAndHandleChange;
53
145
  }