@velocity-exchange/sdk 0.4.0 → 0.6.0

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 (323) hide show
  1. package/README.md +3 -3
  2. package/lib/browser/adminClient.d.ts +35 -0
  3. package/lib/browser/adminClient.js +65 -0
  4. package/lib/browser/config.js +6 -7
  5. package/lib/browser/constants/numericConstants.d.ts +1 -1
  6. package/lib/browser/constants/numericConstants.js +1 -1
  7. package/lib/browser/decode/user.js +5 -1
  8. package/lib/browser/idl/velocity.d.ts +146 -3
  9. package/lib/browser/idl/velocity.json +147 -4
  10. package/lib/browser/orderSubscriber/OrderSubscriber.js +3 -0
  11. package/lib/browser/pyth/pythLazerSubscriber.js +37 -27
  12. package/lib/browser/types.d.ts +4 -0
  13. package/lib/browser/user.d.ts +15 -0
  14. package/lib/browser/user.js +37 -1
  15. package/lib/browser/velocityClient.d.ts +46 -10
  16. package/lib/browser/velocityClient.js +107 -35
  17. package/lib/node/adminClient.d.ts +35 -0
  18. package/lib/node/adminClient.d.ts.map +1 -1
  19. package/lib/node/adminClient.js +65 -0
  20. package/lib/node/config.d.ts.map +1 -1
  21. package/lib/node/config.js +6 -7
  22. package/lib/node/constants/numericConstants.d.ts +1 -1
  23. package/lib/node/constants/numericConstants.d.ts.map +1 -1
  24. package/lib/node/constants/numericConstants.js +1 -1
  25. package/lib/node/decode/user.d.ts.map +1 -1
  26. package/lib/node/decode/user.js +5 -1
  27. package/lib/node/idl/velocity.d.ts +146 -3
  28. package/lib/node/idl/velocity.d.ts.map +1 -1
  29. package/lib/node/idl/velocity.json +147 -4
  30. package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -1
  31. package/lib/node/orderSubscriber/OrderSubscriber.js +3 -0
  32. package/lib/node/pyth/pythLazerSubscriber.d.ts.map +1 -1
  33. package/lib/node/pyth/pythLazerSubscriber.js +37 -27
  34. package/lib/node/types.d.ts +4 -0
  35. package/lib/node/types.d.ts.map +1 -1
  36. package/lib/node/user.d.ts +15 -0
  37. package/lib/node/user.d.ts.map +1 -1
  38. package/lib/node/user.js +37 -1
  39. package/lib/node/velocityClient.d.ts +46 -10
  40. package/lib/node/velocityClient.d.ts.map +1 -1
  41. package/lib/node/velocityClient.js +107 -35
  42. package/package.json +7 -3
  43. package/.prettierignore +0 -1
  44. package/CHANGELOG.md +0 -132
  45. package/build-browser.js +0 -58
  46. package/bunfig.toml +0 -3
  47. package/esbuild-shims.js +0 -12
  48. package/scripts/deposit-isolated-positions.ts +0 -110
  49. package/scripts/find-flagged-users.ts +0 -213
  50. package/scripts/grpc-client-test-comparison.ts +0 -372
  51. package/scripts/grpc-multiuser-client-test-comparison.ts +0 -158
  52. package/scripts/postbuild.js +0 -95
  53. package/scripts/single-grpc-client-test.ts +0 -284
  54. package/scripts/withdraw-isolated-positions.ts +0 -174
  55. package/src/accounts/README_WebSocketAccountSubscriberV2.md +0 -95
  56. package/src/accounts/README_WebSocketProgramAccountSubscriberV2.md +0 -135
  57. package/src/accounts/basicUserAccountSubscriber.ts +0 -79
  58. package/src/accounts/basicUserStatsAccountSubscriber.ts +0 -87
  59. package/src/accounts/bulkAccountLoader.ts +0 -358
  60. package/src/accounts/bulkUserStatsSubscription.ts +0 -40
  61. package/src/accounts/bulkUserSubscription.ts +0 -39
  62. package/src/accounts/customizedCadenceBulkAccountLoader.ts +0 -250
  63. package/src/accounts/fetch.ts +0 -200
  64. package/src/accounts/grpcAccountSubscriber.ts +0 -225
  65. package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +0 -73
  66. package/src/accounts/grpcMultiAccountSubscriber.ts +0 -566
  67. package/src/accounts/grpcMultiUserAccountSubscriber.ts +0 -328
  68. package/src/accounts/grpcProgramAccountSubscriber.ts +0 -264
  69. package/src/accounts/grpcUserAccountSubscriber.ts +0 -63
  70. package/src/accounts/grpcUserStatsAccountSubscriber.ts +0 -65
  71. package/src/accounts/grpcVelocityClientAccountSubscriber.ts +0 -257
  72. package/src/accounts/grpcVelocityClientAccountSubscriberV2.ts +0 -941
  73. package/src/accounts/laserProgramAccountSubscriber.ts +0 -266
  74. package/src/accounts/oneShotUserAccountSubscriber.ts +0 -88
  75. package/src/accounts/oneShotUserStatsAccountSubscriber.ts +0 -94
  76. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -223
  77. package/src/accounts/pollingOracleAccountSubscriber.ts +0 -151
  78. package/src/accounts/pollingTokenAccountSubscriber.ts +0 -147
  79. package/src/accounts/pollingUserAccountSubscriber.ts +0 -198
  80. package/src/accounts/pollingUserStatsAccountSubscriber.ts +0 -180
  81. package/src/accounts/pollingVelocityClientAccountSubscriber.ts +0 -774
  82. package/src/accounts/testBulkAccountLoader.ts +0 -59
  83. package/src/accounts/types.ts +0 -428
  84. package/src/accounts/utils.ts +0 -90
  85. package/src/accounts/webSocketAccountSubscriber.ts +0 -304
  86. package/src/accounts/webSocketAccountSubscriberV2.ts +0 -536
  87. package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +0 -171
  88. package/src/accounts/webSocketProgramAccountSubscriber.ts +0 -244
  89. package/src/accounts/webSocketProgramAccountSubscriberV2.ts +0 -1048
  90. package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +0 -1042
  91. package/src/accounts/webSocketUserAccountSubscriber.ts +0 -139
  92. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +0 -131
  93. package/src/accounts/webSocketVelocityClientAccountSubscriber.ts +0 -865
  94. package/src/accounts/webSocketVelocityClientAccountSubscriberV2.ts +0 -897
  95. package/src/accounts/websocketProgramUserAccountSubscriber.ts +0 -127
  96. package/src/addresses/marketAddresses.ts +0 -28
  97. package/src/addresses/pda.ts +0 -620
  98. package/src/adminClient.ts +0 -8136
  99. package/src/assert/assert.ts +0 -5
  100. package/src/auctionSubscriber/auctionSubscriber.ts +0 -86
  101. package/src/auctionSubscriber/auctionSubscriberGrpc.ts +0 -99
  102. package/src/auctionSubscriber/index.ts +0 -9
  103. package/src/auctionSubscriber/types.ts +0 -30
  104. package/src/bankrun/bankrunConnection.ts +0 -630
  105. package/src/blockhashSubscriber/BlockhashSubscriber.ts +0 -160
  106. package/src/blockhashSubscriber/index.ts +0 -6
  107. package/src/blockhashSubscriber/types.ts +0 -13
  108. package/src/clock/clockSubscriber.ts +0 -146
  109. package/src/config.ts +0 -312
  110. package/src/constants/index.ts +0 -9
  111. package/src/constants/numericConstants.ts +0 -194
  112. package/src/constants/perpMarkets.ts +0 -127
  113. package/src/constants/spotMarkets.ts +0 -104
  114. package/src/constants/txConstants.ts +0 -2
  115. package/src/constituentMap/constituentMap.ts +0 -305
  116. package/src/constituentMap/pollingConstituentAccountSubscriber.ts +0 -99
  117. package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +0 -121
  118. package/src/core/VelocityCore.ts +0 -606
  119. package/src/core/index.ts +0 -12
  120. package/src/core/instructions/deposit.ts +0 -64
  121. package/src/core/instructions/fill.ts +0 -51
  122. package/src/core/instructions/funding.ts +0 -33
  123. package/src/core/instructions/liquidation.ts +0 -55
  124. package/src/core/instructions/orders.ts +0 -84
  125. package/src/core/instructions/perpOrders.ts +0 -312
  126. package/src/core/instructions/settlement.ts +0 -40
  127. package/src/core/instructions/trigger.ts +0 -41
  128. package/src/core/instructions/withdraw.ts +0 -65
  129. package/src/core/remainingAccounts.ts +0 -320
  130. package/src/core/signedMsg.ts +0 -109
  131. package/src/decode/customCoder.ts +0 -148
  132. package/src/decode/user.ts +0 -401
  133. package/src/dlob/DLOB.ts +0 -2793
  134. package/src/dlob/DLOBNode.ts +0 -305
  135. package/src/dlob/DLOBSubscriber.ts +0 -269
  136. package/src/dlob/NodeList.ts +0 -244
  137. package/src/dlob/orderBookLevels.ts +0 -695
  138. package/src/dlob/types.ts +0 -37
  139. package/src/events/eventList.ts +0 -114
  140. package/src/events/eventSubscriber.ts +0 -521
  141. package/src/events/eventsServerLogProvider.ts +0 -189
  142. package/src/events/fetchLogs.ts +0 -219
  143. package/src/events/parse.ts +0 -271
  144. package/src/events/pollingLogProvider.ts +0 -113
  145. package/src/events/sort.ts +0 -51
  146. package/src/events/txEventCache.ts +0 -92
  147. package/src/events/types.ts +0 -337
  148. package/src/events/webSocketLogProvider.ts +0 -152
  149. package/src/factory/bigNum.ts +0 -709
  150. package/src/factory/oracleClient.ts +0 -73
  151. package/src/idl/pyth.json +0 -142
  152. package/src/idl/pyth.ts +0 -97
  153. package/src/idl/pyth_solana_receiver.json +0 -628
  154. package/src/idl/token_faucet.json +0 -229
  155. package/src/idl/token_faucet.ts +0 -197
  156. package/src/idl/velocity.json +0 -23974
  157. package/src/idl/velocity.ts +0 -23980
  158. package/src/index.ts +0 -150
  159. package/src/indicative-quotes/indicativeQuotesSender.ts +0 -233
  160. package/src/isomorphic/README.md +0 -19
  161. package/src/isomorphic/anchor.browser.ts +0 -44
  162. package/src/isomorphic/anchor.node.ts +0 -1
  163. package/src/isomorphic/anchor.ts +0 -1
  164. package/src/isomorphic/anchor29.browser.ts +0 -24
  165. package/src/isomorphic/anchor29.node.ts +0 -1
  166. package/src/isomorphic/anchor29.ts +0 -1
  167. package/src/isomorphic/grpc.browser.ts +0 -4
  168. package/src/isomorphic/grpc.node.ts +0 -130
  169. package/src/isomorphic/grpc.ts +0 -1
  170. package/src/jupiter/jupiterClient.ts +0 -502
  171. package/src/keypair.ts +0 -32
  172. package/src/margin/README.md +0 -138
  173. package/src/marginCalculation.ts +0 -407
  174. package/src/marinade/idl/idl.json +0 -1962
  175. package/src/marinade/index.ts +0 -73
  176. package/src/marinade/types.ts +0 -3925
  177. package/src/math/amm.ts +0 -1758
  178. package/src/math/auction.ts +0 -480
  179. package/src/math/bankruptcy.ts +0 -138
  180. package/src/math/builder.ts +0 -130
  181. package/src/math/conversion.ts +0 -45
  182. package/src/math/exchangeStatus.ts +0 -261
  183. package/src/math/funding.ts +0 -498
  184. package/src/math/insurance.ts +0 -171
  185. package/src/math/liquidation.ts +0 -433
  186. package/src/math/margin.ts +0 -327
  187. package/src/math/market.ts +0 -487
  188. package/src/math/oracles.ts +0 -477
  189. package/src/math/orders.ts +0 -500
  190. package/src/math/position.ts +0 -381
  191. package/src/math/repeg.ts +0 -223
  192. package/src/math/spotBalance.ts +0 -996
  193. package/src/math/spotMarket.ts +0 -115
  194. package/src/math/spotPosition.ts +0 -263
  195. package/src/math/state.ts +0 -71
  196. package/src/math/superStake.ts +0 -602
  197. package/src/math/tiers.ts +0 -73
  198. package/src/math/trade.ts +0 -879
  199. package/src/math/utils.ts +0 -183
  200. package/src/memcmp.ts +0 -279
  201. package/src/oracles/oracleClientCache.ts +0 -41
  202. package/src/oracles/oracleId.ts +0 -99
  203. package/src/oracles/prelaunchOracleClient.ts +0 -63
  204. package/src/oracles/pythClient.ts +0 -125
  205. package/src/oracles/pythLazerClient.ts +0 -141
  206. package/src/oracles/quoteAssetOracleClient.ts +0 -43
  207. package/src/oracles/strictOraclePrice.ts +0 -40
  208. package/src/oracles/types.ts +0 -82
  209. package/src/oracles/utils.ts +0 -45
  210. package/src/orderParams.ts +0 -117
  211. package/src/orderSubscriber/OrderSubscriber.ts +0 -378
  212. package/src/orderSubscriber/PollingSubscription.ts +0 -50
  213. package/src/orderSubscriber/WebsocketSubscription.ts +0 -137
  214. package/src/orderSubscriber/grpcSubscription.ts +0 -155
  215. package/src/orderSubscriber/index.ts +0 -7
  216. package/src/orderSubscriber/types.ts +0 -64
  217. package/src/priorityFee/averageOverSlotsStrategy.ts +0 -17
  218. package/src/priorityFee/averageStrategy.ts +0 -13
  219. package/src/priorityFee/ewmaStrategy.ts +0 -51
  220. package/src/priorityFee/heliusPriorityFeeMethod.ts +0 -68
  221. package/src/priorityFee/index.ts +0 -16
  222. package/src/priorityFee/maxOverSlotsStrategy.ts +0 -18
  223. package/src/priorityFee/maxStrategy.ts +0 -8
  224. package/src/priorityFee/priorityFeeSubscriber.ts +0 -328
  225. package/src/priorityFee/priorityFeeSubscriberMap.ts +0 -134
  226. package/src/priorityFee/solanaPriorityFeeMethod.ts +0 -46
  227. package/src/priorityFee/types.ts +0 -82
  228. package/src/priorityFee/velocityPriorityFeeMethod.ts +0 -53
  229. package/src/pyth/constants.ts +0 -9
  230. package/src/pyth/index.ts +0 -15
  231. package/src/pyth/pythLazerSubscriber.ts +0 -365
  232. package/src/pyth/types.ts +0 -4451
  233. package/src/pyth/utils.ts +0 -13
  234. package/src/slot/SlotSubscriber.ts +0 -126
  235. package/src/slot/SlothashSubscriber.ts +0 -163
  236. package/src/swap/UnifiedSwapClient.ts +0 -315
  237. package/src/swift/grpcSignedMsgUserAccountSubscriber.ts +0 -81
  238. package/src/swift/index.ts +0 -10
  239. package/src/swift/signedMsgUserAccountSubscriber.ts +0 -251
  240. package/src/swift/swiftOrderSubscriber.ts +0 -351
  241. package/src/testClient.ts +0 -42
  242. package/src/titan/titanClient.ts +0 -438
  243. package/src/token/index.ts +0 -13
  244. package/src/tokenFaucet.ts +0 -296
  245. package/src/tx/baseTxSender.ts +0 -651
  246. package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +0 -31
  247. package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +0 -105
  248. package/src/tx/blockhashFetcher/types.ts +0 -9
  249. package/src/tx/fastSingleTxSender.ts +0 -200
  250. package/src/tx/forwardOnlyTxSender.ts +0 -193
  251. package/src/tx/priorityFeeCalculator.ts +0 -117
  252. package/src/tx/reportTransactionError.ts +0 -176
  253. package/src/tx/retryTxSender.ts +0 -177
  254. package/src/tx/txHandler.ts +0 -1009
  255. package/src/tx/txParamProcessor.ts +0 -225
  256. package/src/tx/types.ts +0 -117
  257. package/src/tx/utils.ts +0 -133
  258. package/src/tx/whileValidTxSender.ts +0 -377
  259. package/src/types.ts +0 -2575
  260. package/src/user.ts +0 -5316
  261. package/src/userConfig.ts +0 -38
  262. package/src/userMap/PollingSubscription.ts +0 -61
  263. package/src/userMap/WebsocketSubscription.ts +0 -93
  264. package/src/userMap/grpcSubscription.ts +0 -93
  265. package/src/userMap/referrerMap.ts +0 -360
  266. package/src/userMap/revenueShareEscrowMap.ts +0 -342
  267. package/src/userMap/userMap.ts +0 -784
  268. package/src/userMap/userMapConfig.ts +0 -82
  269. package/src/userMap/userStatsMap.ts +0 -393
  270. package/src/userName.ts +0 -37
  271. package/src/userStats.ts +0 -159
  272. package/src/userStatsConfig.ts +0 -35
  273. package/src/util/TransactionConfirmationManager.ts +0 -333
  274. package/src/util/chainClock.ts +0 -65
  275. package/src/util/computeUnits.ts +0 -101
  276. package/src/util/digest.ts +0 -33
  277. package/src/util/ed25519Utils.ts +0 -95
  278. package/src/util/promiseTimeout.ts +0 -23
  279. package/src/velocityClient.ts +0 -14802
  280. package/src/velocityClientConfig.ts +0 -119
  281. package/src/wallet.ts +0 -91
  282. package/tests/VelocityCore/builder_escrow.test.ts +0 -121
  283. package/tests/VelocityCore/decode.test.ts +0 -16
  284. package/tests/VelocityCore/fill_trigger.test.ts +0 -73
  285. package/tests/VelocityCore/instructions.test.ts +0 -46
  286. package/tests/VelocityCore/pdas.test.ts +0 -30
  287. package/tests/VelocityCore/perp_orders.test.ts +0 -205
  288. package/tests/VelocityCore/remainingAccounts.test.ts +0 -72
  289. package/tests/VelocityCore/settlement_liquidation.test.ts +0 -69
  290. package/tests/accounts/customizedCadenceBulkAccountLoader.test.ts +0 -211
  291. package/tests/amm/test.ts +0 -2402
  292. package/tests/auctions/test.ts +0 -81
  293. package/tests/bn/test.ts +0 -355
  294. package/tests/builder/builderFee.test.ts +0 -42
  295. package/tests/ci/verifyConstants.ts +0 -393
  296. package/tests/decode/test.ts +0 -262
  297. package/tests/decode/userAccountBufferStrings.ts +0 -102
  298. package/tests/dlob/helpers.ts +0 -748
  299. package/tests/dlob/test.ts +0 -6969
  300. package/tests/dlob/tickSizeStandardization.ts +0 -545
  301. package/tests/events/parseLogsForCuUsage.ts +0 -139
  302. package/tests/exchangeStatus/test.ts +0 -45
  303. package/tests/insurance/test.ts +0 -40
  304. package/tests/liquidation/test.ts +0 -125
  305. package/tests/oracles/mmOracleGate.test.ts +0 -379
  306. package/tests/oracles/pythPegSnap.test.ts +0 -76
  307. package/tests/sdkParity/enumParity.test.ts +0 -84
  308. package/tests/sdkParity/marginCategoryFill.test.ts +0 -143
  309. package/tests/sdkParity/memcmpOffsets.test.ts +0 -139
  310. package/tests/spot/test.ts +0 -281
  311. package/tests/tx/TransactionConfirmationManager.test.ts +0 -312
  312. package/tests/tx/cachedBlockhashFetcher.test.ts +0 -96
  313. package/tests/tx/priorityFeeCalculator.ts +0 -77
  314. package/tests/tx/priorityFeeStrategy.ts +0 -95
  315. package/tests/user/bankruptcy.ts +0 -165
  316. package/tests/user/feeAndWithdrawLimits.ts +0 -284
  317. package/tests/user/getMarginCalculation.ts +0 -586
  318. package/tests/user/helpers.ts +0 -184
  319. package/tests/user/liquidations.ts +0 -129
  320. package/tests/user/marginCalculations.test.ts +0 -321
  321. package/tests/user/test.ts +0 -833
  322. package/tsconfig.browser.json +0 -18
  323. package/tsconfig.json +0 -36
@@ -1,358 +0,0 @@
1
- import { Commitment, PublicKey } from '@solana/web3.js';
2
- import { v4 as uuidv4 } from 'uuid';
3
- import { BufferAndSlot } from './types';
4
- import { promiseTimeout } from '../util/promiseTimeout';
5
- import { Connection } from '../bankrun/bankrunConnection';
6
- import { GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE } from '../constants/numericConstants';
7
-
8
- /** An account registered with a `BulkAccountLoader`, along with every callback subscribed to its updates (keyed by callback id). */
9
- export type AccountToLoad = {
10
- publicKey: PublicKey;
11
- callbacks: Map<string, (buffer: Buffer, slot: number) => void>;
12
- };
13
-
14
- const oneMinute = 60 * 1000;
15
-
16
- /**
17
- * Batches many accounts behind a single periodic `getMultipleAccounts` RPC poll instead of one
18
- * WebSocket subscription per account. Multiple independent callbacks (e.g. from different
19
- * `PollingUserAccountSubscriber`/`PollingVelocityClientAccountSubscriber` instances) can register
20
- * against the same `publicKey`; polling starts automatically on the first `addAccount` and stops
21
- * when the last callback for the last account is removed. A buffer is only re-delivered to
22
- * callbacks when its slot is not older than the last-seen slot for that account and its bytes
23
- * actually changed, so a callback never observes a stale or duplicate update. `load()` calls are
24
- * coalesced: concurrent callers share one in-flight RPC batch rather than issuing redundant
25
- * requests.
26
- */
27
- export class BulkAccountLoader {
28
- connection: Connection;
29
- commitment: Commitment;
30
- pollingFrequency: number;
31
- accountsToLoad = new Map<string, AccountToLoad>();
32
- bufferAndSlotMap = new Map<string, BufferAndSlot>();
33
- errorCallbacks = new Map<string, (e: Error) => void>();
34
- intervalId?: ReturnType<typeof setTimeout>;
35
- // to handle clients spamming load
36
- loadPromise?: Promise<void>;
37
- private loadPromiseResolver: () => void = () => {};
38
- lastTimeLoadingPromiseCleared = Date.now();
39
- mostRecentSlot = 0;
40
-
41
- /**
42
- * @param connection Connection (or bankrun-compatible shim) used for the batched `getMultipleAccounts` polls.
43
- * @param commitment Commitment level applied to every poll.
44
- * @param pollingFrequency Poll interval in ms; `0` disables automatic polling (`startPolling` becomes a no-op), useful when the loader is driven manually via `load()`.
45
- */
46
- public constructor(
47
- connection: Connection,
48
- commitment: Commitment,
49
- pollingFrequency: number
50
- ) {
51
- this.connection = connection;
52
- this.commitment = commitment;
53
- this.pollingFrequency = pollingFrequency;
54
- }
55
-
56
- /**
57
- * Registers a callback to be invoked whenever `publicKey`'s account data changes on a poll.
58
- * Multiple callbacks may be registered for the same account. Starts polling automatically if
59
- * this is the loader's first account. Awaits any in-flight `load()` before returning so a
60
- * caller can immediately follow with its own `load()` without racing the poll interval.
61
- * @param publicKey Account to track.
62
- * @param callback Invoked with the raw account buffer and the slot it was fetched at whenever the buffer changes at a non-decreasing slot.
63
- * @returns A callback id to pass to `removeAccount` later.
64
- */
65
- public async addAccount(
66
- publicKey: PublicKey,
67
- callback: (buffer: Buffer, slot: number) => void
68
- ): Promise<string> {
69
- if (!publicKey) {
70
- console.trace(`Caught adding blank publickey to bulkAccountLoader`);
71
- }
72
-
73
- const existingSize = this.accountsToLoad.size;
74
-
75
- const callbackId = uuidv4();
76
- const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
77
- if (existingAccountToLoad) {
78
- existingAccountToLoad.callbacks.set(callbackId, callback);
79
- } else {
80
- const callbacks = new Map<
81
- string,
82
- (buffer: Buffer, slot: number) => void
83
- >();
84
- callbacks.set(callbackId, callback);
85
- const newAccountToLoad = {
86
- publicKey,
87
- callbacks,
88
- };
89
- this.accountsToLoad.set(publicKey.toString(), newAccountToLoad);
90
- }
91
-
92
- if (existingSize === 0) {
93
- this.startPolling();
94
- }
95
-
96
- // resolve the current loadPromise in case client wants to call load
97
- await this.loadPromise;
98
-
99
- return callbackId;
100
- }
101
-
102
- /**
103
- * Unregisters a callback previously returned by `addAccount`. Once an account has no
104
- * remaining callbacks, its cached buffer/slot is dropped and it stops being polled; if no
105
- * accounts remain at all, polling stops entirely. A no-op if `callbackId` is undefined.
106
- * @param publicKey Account the callback was registered against.
107
- * @param callbackId Id returned by `addAccount`.
108
- */
109
- public removeAccount(
110
- publicKey: PublicKey,
111
- callbackId: string | undefined
112
- ): void {
113
- if (callbackId === undefined) {
114
- return;
115
- }
116
- const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
117
- if (existingAccountToLoad) {
118
- existingAccountToLoad.callbacks.delete(callbackId);
119
- if (existingAccountToLoad.callbacks.size === 0) {
120
- this.bufferAndSlotMap.delete(publicKey.toString());
121
- this.accountsToLoad.delete(existingAccountToLoad.publicKey.toString());
122
- }
123
- }
124
-
125
- if (this.accountsToLoad.size === 0) {
126
- this.stopPolling();
127
- }
128
- }
129
-
130
- /**
131
- * Registers a callback invoked whenever a `load()` batch throws (e.g. RPC failure or timeout).
132
- * The loader continues polling afterward; errors do not stop the interval.
133
- * @returns A callback id to pass to `removeErrorCallbacks` later.
134
- */
135
- public addErrorCallbacks(callback: (error: Error) => void): string {
136
- const callbackId = uuidv4();
137
- this.errorCallbacks.set(callbackId, callback);
138
- return callbackId;
139
- }
140
-
141
- /** Unregisters an error callback previously returned by `addErrorCallbacks`. A no-op if `callbackId` is undefined. */
142
- public removeErrorCallbacks(callbackId: string | undefined): void {
143
- if (callbackId === undefined) {
144
- return;
145
- }
146
- this.errorCallbacks.delete(callbackId);
147
- }
148
-
149
- chunks<T>(array: readonly T[], size: number): T[][] {
150
- return new Array(Math.ceil(array.length / size))
151
- .fill(null)
152
- .map((_, index) => index * size)
153
- .map((begin) => array.slice(begin, begin + size));
154
- }
155
-
156
- /**
157
- * Fetches every registered account in one or more chunked, concurrent `getMultipleAccounts`
158
- * batches (via `loadChunk`) and dispatches changed accounts to their callbacks. Concurrent
159
- * calls while a load is already in flight share that same in-flight promise rather than
160
- * issuing a duplicate RPC batch, unless the previous load has been running for over a minute
161
- * (treated as stuck and restarted). On failure, invokes every registered error callback
162
- * instead of throwing.
163
- */
164
- public async load(): Promise<void> {
165
- if (this.loadPromise) {
166
- const now = Date.now();
167
- if (now - this.lastTimeLoadingPromiseCleared > oneMinute) {
168
- this.loadPromise = undefined;
169
- } else {
170
- return this.loadPromise;
171
- }
172
- }
173
-
174
- this.loadPromise = new Promise((resolver) => {
175
- this.loadPromiseResolver = resolver;
176
- });
177
- this.lastTimeLoadingPromiseCleared = Date.now();
178
-
179
- try {
180
- const chunks = this.chunks(
181
- this.chunks(
182
- Array.from(this.accountsToLoad.values()),
183
- GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE
184
- ),
185
- 10
186
- );
187
-
188
- await Promise.all(
189
- chunks.map((chunk) => {
190
- return this.loadChunk(chunk);
191
- })
192
- );
193
- } catch (e) {
194
- console.error(`Error in bulkAccountLoader.load()`);
195
- console.error(e);
196
- const error = e instanceof Error ? e : new Error(String(e));
197
- for (const [_, callback] of this.errorCallbacks) {
198
- callback(error);
199
- }
200
- } finally {
201
- this.loadPromiseResolver();
202
- this.loadPromise = undefined;
203
- }
204
- }
205
-
206
- async loadChunk(accountsToLoadChunks: AccountToLoad[][]): Promise<void> {
207
- if (accountsToLoadChunks.length === 0) {
208
- return;
209
- }
210
-
211
- const requests = new Array<{ methodName: string; args: any }>();
212
- for (const accountsToLoadChunk of accountsToLoadChunks) {
213
- const args = [
214
- accountsToLoadChunk
215
- .filter((accountToLoad) => accountToLoad.callbacks.size > 0)
216
- .map((accountToLoad) => {
217
- return accountToLoad.publicKey.toBase58();
218
- }),
219
- { commitment: this.commitment },
220
- ];
221
-
222
- requests.push({
223
- methodName: 'getMultipleAccounts',
224
- args,
225
- });
226
- }
227
-
228
- const rpcResponses: any | null = await promiseTimeout(
229
- // @ts-ignore
230
- this.connection._rpcBatchRequest(requests),
231
- 10 * 1000 // 30 second timeout
232
- );
233
-
234
- if (rpcResponses === null) {
235
- this.log('request to rpc timed out');
236
- return;
237
- }
238
-
239
- rpcResponses.forEach((rpcResponse: any, i: number) => {
240
- if (!rpcResponse.result) {
241
- console.error('rpc response missing result:');
242
- console.log(JSON.stringify(rpcResponse));
243
- return;
244
- }
245
- const newSlot = rpcResponse.result.context.slot;
246
-
247
- if (newSlot > this.mostRecentSlot) {
248
- this.mostRecentSlot = newSlot;
249
- }
250
-
251
- const accountsToLoad = accountsToLoadChunks[i];
252
- accountsToLoad.forEach((accountToLoad, j) => {
253
- if (accountToLoad.callbacks.size === 0) {
254
- return;
255
- }
256
-
257
- const key = accountToLoad.publicKey.toBase58();
258
- const oldRPCResponse = this.bufferAndSlotMap.get(key);
259
-
260
- if (oldRPCResponse && newSlot < oldRPCResponse.slot) {
261
- return;
262
- }
263
-
264
- let newBuffer: Buffer | undefined = undefined;
265
- if (rpcResponse.result.value[j]) {
266
- const raw: string = rpcResponse.result.value[j].data[0];
267
- const dataType = rpcResponse.result.value[j].data[1];
268
- newBuffer = Buffer.from(raw, dataType);
269
- }
270
-
271
- if (!oldRPCResponse) {
272
- this.bufferAndSlotMap.set(key, {
273
- slot: newSlot,
274
- buffer: newBuffer,
275
- });
276
- this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
277
- return;
278
- }
279
-
280
- const oldBuffer = oldRPCResponse.buffer;
281
- if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
282
- this.bufferAndSlotMap.set(key, {
283
- slot: newSlot,
284
- buffer: newBuffer,
285
- });
286
- this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
287
- }
288
- });
289
- });
290
- }
291
-
292
- handleAccountCallbacks(
293
- accountToLoad: AccountToLoad,
294
- buffer: Buffer | undefined,
295
- slot: number
296
- ): void {
297
- if (buffer === undefined) {
298
- return;
299
- }
300
- for (const [_, callback] of accountToLoad.callbacks) {
301
- try {
302
- callback(buffer, slot);
303
- } catch (e) {
304
- console.log('Bulk account load: error in account callback');
305
- console.log('accounto to load', accountToLoad.publicKey.toString());
306
- console.log('buffer', buffer.toString('base64'));
307
- for (const callback of accountToLoad.callbacks.values()) {
308
- console.log('account to load cb', callback);
309
- }
310
- throw e;
311
- }
312
- }
313
- }
314
-
315
- /** Returns the last-fetched raw buffer/slot for `publicKey`, or undefined if it has never been loaded. */
316
- public getBufferAndSlot(publicKey: PublicKey): BufferAndSlot | undefined {
317
- return this.bufferAndSlotMap.get(publicKey.toString());
318
- }
319
-
320
- /** Returns the highest slot number observed across any account fetched by this loader so far. */
321
- public getSlot(): number {
322
- return this.mostRecentSlot;
323
- }
324
-
325
- /** Starts the polling interval if not already running and `pollingFrequency !== 0`. Called automatically by `addAccount`. */
326
- public startPolling(): void {
327
- if (this.intervalId) {
328
- return;
329
- }
330
-
331
- if (this.pollingFrequency !== 0)
332
- this.intervalId = setInterval(
333
- this.load.bind(this),
334
- this.pollingFrequency
335
- );
336
- }
337
-
338
- /** Stops the polling interval, if running. Called automatically by `removeAccount` once no accounts remain. */
339
- public stopPolling(): void {
340
- if (this.intervalId) {
341
- clearInterval(this.intervalId);
342
- this.intervalId = undefined;
343
- }
344
- }
345
-
346
- public log(msg: string): void {
347
- console.log(msg);
348
- }
349
-
350
- /** Restarts polling at a new interval (ms), preserving all registered accounts and callbacks. */
351
- public updatePollingFrequency(pollingFrequency: number): void {
352
- this.stopPolling();
353
- this.pollingFrequency = pollingFrequency;
354
- if (this.accountsToLoad.size > 0) {
355
- this.startPolling();
356
- }
357
- }
358
- }
@@ -1,40 +0,0 @@
1
- import { UserStats } from '../userStats';
2
- import { BulkAccountLoader } from './bulkAccountLoader';
3
- import { PollingUserStatsAccountSubscriber } from './pollingUserStatsAccountSubscriber';
4
-
5
- /**
6
- * Subscribes many `UserStats`s that share a single `BulkAccountLoader` in one batched round trip,
7
- * instead of each `UserStats.subscribe()` triggering its own `addAccount`/`load()`. Registers
8
- * every account's `PollingUserStatsAccountSubscriber` with the loader first, issues one `load()`
9
- * to seed all of them from a single batched `getMultipleAccounts` call, and only then calls
10
- * `userStat.subscribe()` (which becomes a fast no-op fetch since data is already cached). If
11
- * `userStats` is empty, still calls `accountLoader.load()` so any other accounts already
12
- * registered on the loader get polled.
13
- * @param userStats `UserStats` instances to subscribe; each must already be constructed with a `PollingUserStatsAccountSubscriber`.
14
- * @param accountLoader Shared `BulkAccountLoader` batching the underlying RPC polls.
15
- */
16
- export async function bulkPollingUserStatsSubscribe(
17
- userStats: UserStats[],
18
- accountLoader: BulkAccountLoader
19
- ): Promise<void> {
20
- if (userStats.length === 0) {
21
- await accountLoader.load();
22
- return;
23
- }
24
-
25
- await Promise.all(
26
- userStats.map((userStat) => {
27
- return (
28
- userStat.accountSubscriber as PollingUserStatsAccountSubscriber
29
- ).addToAccountLoader();
30
- })
31
- );
32
-
33
- await accountLoader.load();
34
-
35
- await Promise.all(
36
- userStats.map(async (userStat) => {
37
- return userStat.subscribe();
38
- })
39
- );
40
- }
@@ -1,39 +0,0 @@
1
- import { User } from '../user';
2
- import { BulkAccountLoader } from './bulkAccountLoader';
3
- import { PollingUserAccountSubscriber } from './pollingUserAccountSubscriber';
4
-
5
- /**
6
- * Subscribes many `User`s that share a single `BulkAccountLoader` in one batched round trip,
7
- * instead of each `User.subscribe()` triggering its own `addAccount`/`load()`. Registers every
8
- * user's `PollingUserAccountSubscriber` with the loader first, issues one `load()` to seed all of
9
- * them from a single batched `getMultipleAccounts` call, and only then calls `user.subscribe()`
10
- * (which becomes a fast no-op fetch since data is already cached). If `users` is empty, still
11
- * calls `accountLoader.load()` so any other accounts already registered on the loader get polled.
12
- * @param users Users to subscribe; each must already be constructed with a `PollingUserAccountSubscriber`.
13
- * @param accountLoader Shared `BulkAccountLoader` batching the underlying RPC polls.
14
- */
15
- export async function bulkPollingUserSubscribe(
16
- users: User[],
17
- accountLoader: BulkAccountLoader
18
- ): Promise<void> {
19
- if (users.length === 0) {
20
- await accountLoader.load();
21
- return;
22
- }
23
-
24
- await Promise.all(
25
- users.map((user) => {
26
- return (
27
- user.accountSubscriber as PollingUserAccountSubscriber
28
- ).addToAccountLoader();
29
- })
30
- );
31
-
32
- await accountLoader.load();
33
-
34
- await Promise.all(
35
- users.map(async (user) => {
36
- return user.subscribe();
37
- })
38
- );
39
- }
@@ -1,250 +0,0 @@
1
- import { GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE } from '../constants/numericConstants';
2
- import { BulkAccountLoader } from './bulkAccountLoader';
3
- import { Commitment, Connection, PublicKey } from '@solana/web3.js';
4
- import { v4 as uuidv4 } from 'uuid';
5
-
6
- /**
7
- * `BulkAccountLoader` variant where each account can be polled at its own cadence instead of a
8
- * single shared `pollingFrequency`. Overrides the base class's single `setInterval` with a
9
- * per-account `accountFrequencies` map: `handleAccountLoading()` only includes an account in a
10
- * given tick if `Date.now() - lastPollingTime >= frequency` for that account, then delegates to
11
- * the inherited chunked `loadChunk` for the actual `getMultipleAccounts` batch. The interval
12
- * itself always runs at the fastest frequency across all registered accounts (see `startPolling`),
13
- * so slower accounts simply get skipped on ticks that fire before they're due.
14
- */
15
- export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
16
- private customIntervalId: NodeJS.Timeout | null;
17
- private currentPollingFrequency: number | null;
18
- private accountFrequencies: Map<string, number>;
19
- private lastPollingTimes: Map<string, number>;
20
- private defaultPollingFrequency: number;
21
-
22
- /**
23
- * @param connection Connection used for the batched `getMultipleAccounts` polls.
24
- * @param commitment Commitment level applied to every poll.
25
- * @param defaultPollingFrequency Polling cadence in ms (see base `BulkAccountLoader`) used for any account added without an explicit `customPollingFrequency`, and as the floor when computing the shared interval in `startPolling`.
26
- */
27
- constructor(
28
- connection: Connection,
29
- commitment: Commitment,
30
- defaultPollingFrequency: number
31
- ) {
32
- super(connection, commitment, defaultPollingFrequency);
33
- this.customIntervalId = null;
34
- this.currentPollingFrequency = null;
35
- this.accountFrequencies = new Map();
36
- this.lastPollingTimes = new Map();
37
- this.defaultPollingFrequency = defaultPollingFrequency;
38
- }
39
-
40
- private getAccountsToLoad(): Array<{
41
- publicKey: PublicKey;
42
- callbacks: Map<string, (buffer: Buffer, slot: number) => void>;
43
- }> {
44
- const currentTime = Date.now();
45
- const accountsToLoad: Array<{
46
- publicKey: PublicKey;
47
- callbacks: Map<string, (buffer: Buffer, slot: number) => void>;
48
- }> = [];
49
-
50
- for (const [key, frequency] of this.accountFrequencies.entries()) {
51
- const lastPollTime = this.lastPollingTimes.get(key) || 0;
52
- if (currentTime - lastPollTime >= frequency) {
53
- const account = this.accountsToLoad.get(key);
54
- if (account) {
55
- accountsToLoad.push(account);
56
- this.lastPollingTimes.set(key, currentTime);
57
- }
58
- }
59
- }
60
-
61
- return accountsToLoad;
62
- }
63
-
64
- /** Immediately runs one due-account loading pass, bypassing the interval timer. Unlike the base class's `load()`, this does not force-load every registered account — only those currently due per their own cadence. */
65
- public async load(): Promise<void> {
66
- return this.handleAccountLoading();
67
- }
68
-
69
- private async handleAccountLoading(): Promise<void> {
70
- const accounts = this.getAccountsToLoad();
71
-
72
- if (accounts.length > 0) {
73
- const chunks = this.chunks(
74
- this.chunks(accounts, GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE),
75
- 10
76
- );
77
-
78
- await Promise.all(
79
- chunks.map((chunk) => {
80
- return this.loadChunk(chunk);
81
- })
82
- );
83
- }
84
- }
85
-
86
- /**
87
- * Updates the polling frequency for an account. This affects all callbacks attached to this account.
88
- *
89
- * @param publicKey The public key of the account to set the custom polling frequency for
90
- * @param newFrequency The new polling frequency in ms
91
- */
92
- public setCustomPollingFrequency(
93
- publicKey: PublicKey,
94
- newFrequency: number
95
- ): void {
96
- const key = publicKey.toBase58();
97
- this.accountFrequencies.set(key, newFrequency);
98
- this.lastPollingTimes.set(key, 0); // Reset last polling time to ensure immediate load
99
- this.restartPollingIfNeeded(newFrequency);
100
- }
101
-
102
- private restartPollingIfNeeded(newFrequency: number): void {
103
- if (
104
- (this.currentPollingFrequency &&
105
- newFrequency < this.currentPollingFrequency) ||
106
- !this.customIntervalId
107
- ) {
108
- this.stopPolling();
109
- this.startPolling();
110
- }
111
- }
112
-
113
- /**
114
- * Adds an account to be monitored by the bulk account loader
115
- * @param publicKey The public key of the account to monitor
116
- * @param callback Function to be called when account data is received
117
- * @param customPollingFrequency Optional custom polling frequency in ms for this specific account.
118
- * If not provided, will use the default polling frequency
119
- * @returns A unique callback ID that can be used to remove this specific callback later
120
- *
121
- * The method will:
122
- * 1. Create a new callback mapping for the account if it doesn't exist already
123
- * 2. Set up polling frequency tracking for the account if it doesn't exist already. If previous polling frequency is faster than the new one,
124
- * we will use the previous frequency.
125
- * 3. Reset last polling time to 0 to ensure data fetch is triggered on the next poll. Note that this does not mean the account will be fetched immediately.
126
- * 4. Automatically restart polling if this account needs a faster frequency than existing accounts
127
- */
128
- public async addAccount(
129
- publicKey: PublicKey,
130
- callback: (buffer: Buffer, slot: number) => void,
131
- customPollingFrequency?: number
132
- ): Promise<string> {
133
- const callbackId = uuidv4();
134
- const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
135
-
136
- if (existingAccountToLoad) {
137
- existingAccountToLoad.callbacks.set(callbackId, callback);
138
- } else {
139
- const callbacks = new Map<
140
- string,
141
- (buffer: Buffer, slot: number) => void
142
- >();
143
- callbacks.set(callbackId, callback);
144
- const newAccountToLoad = {
145
- publicKey,
146
- callbacks,
147
- };
148
- this.accountsToLoad.set(publicKey.toString(), newAccountToLoad);
149
- }
150
-
151
- const key = publicKey.toBase58();
152
- const previousFrequency =
153
- this.accountFrequencies.get(key) || this.defaultPollingFrequency;
154
- const updatedFrequency =
155
- customPollingFrequency && customPollingFrequency < previousFrequency
156
- ? customPollingFrequency
157
- : previousFrequency;
158
-
159
- this.accountFrequencies.set(key, updatedFrequency);
160
- this.lastPollingTimes.set(key, 0); // Reset last polling time to ensure immediate load
161
-
162
- this.restartPollingIfNeeded(updatedFrequency);
163
-
164
- return callbackId;
165
- }
166
-
167
- /**
168
- * Unregisters a callback previously returned by `addAccount`. Once an account has no
169
- * remaining callbacks, its cached buffer/slot and cadence bookkeeping (`accountFrequencies`,
170
- * `lastPollingTimes`) are dropped; if no accounts remain at all, polling stops entirely,
171
- * otherwise polling is restarted in case the removed account held the fastest cadence.
172
- * @param publicKey Account the callback was registered against.
173
- * @param callbackId Id returned by `addAccount`.
174
- */
175
- public removeAccount(publicKey: PublicKey, callbackId: string): void {
176
- const existingAccountToLoad = this.accountsToLoad.get(publicKey.toString());
177
-
178
- if (existingAccountToLoad) {
179
- existingAccountToLoad.callbacks.delete(callbackId);
180
-
181
- if (existingAccountToLoad.callbacks.size === 0) {
182
- this.bufferAndSlotMap.delete(publicKey.toString());
183
- this.accountsToLoad.delete(existingAccountToLoad.publicKey.toString());
184
- const key = publicKey.toBase58();
185
- this.accountFrequencies.delete(key);
186
- this.lastPollingTimes.delete(key);
187
- }
188
- }
189
-
190
- if (this.accountsToLoad.size === 0) {
191
- this.stopPolling();
192
- } else {
193
- // Restart polling in case we removed the account with the smallest frequency
194
- this.restartPollingIfNeeded(this.defaultPollingFrequency);
195
- }
196
- }
197
-
198
- /** Returns the polling cadence in ms currently set for `publicKey` (custom or default), or `null` if the account isn't registered. */
199
- public getAccountCadence(publicKey: PublicKey): number | null {
200
- const key = publicKey.toBase58();
201
- return this.accountFrequencies.get(key) || null;
202
- }
203
-
204
- /**
205
- * Starts the shared interval timer, ticking at the fastest cadence among all registered
206
- * accounts (or `defaultPollingFrequency` if none are registered). Each tick runs
207
- * `handleAccountLoading()`, which loads only the accounts due at that moment. A no-op if
208
- * already running; call `stopPolling()` first to pick up a new minimum frequency.
209
- */
210
- public startPolling(): void {
211
- if (this.customIntervalId) {
212
- return;
213
- }
214
-
215
- const minFrequency = Math.min(
216
- ...Array.from(this.accountFrequencies.values()),
217
- this.defaultPollingFrequency
218
- );
219
-
220
- this.currentPollingFrequency = minFrequency;
221
-
222
- this.customIntervalId = setInterval(() => {
223
- this.handleAccountLoading().catch((error) => {
224
- console.error('Error in account loading:', error);
225
- });
226
- }, minFrequency);
227
- }
228
-
229
- /** Stops the shared interval timer (and the base class's, via `super.stopPolling()`) and clears `lastPollingTimes` so every account is treated as due again once polling restarts. */
230
- public stopPolling(): void {
231
- super.stopPolling();
232
-
233
- if (this.customIntervalId) {
234
- clearInterval(this.customIntervalId);
235
- this.customIntervalId = null;
236
- this.currentPollingFrequency = null;
237
- }
238
- this.lastPollingTimes.clear();
239
- }
240
-
241
- /**
242
- * Clears all per-account cadence bookkeeping. Because `getAccountsToLoad()` only considers
243
- * accounts with an entry in `accountFrequencies`, this stops polling for every registered
244
- * account until a cadence is re-established via `setCustomPollingFrequency` or `addAccount`.
245
- * Registered accounts/callbacks themselves are untouched.
246
- */
247
- public clearAccountFrequencies(): void {
248
- this.accountFrequencies.clear();
249
- }
250
- }