@velocity-exchange/sdk 0.4.0 → 0.6.1

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 (325) hide show
  1. package/README.md +3 -3
  2. package/lib/browser/adminClient.d.ts +52 -0
  3. package/lib/browser/adminClient.js +97 -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 +191 -15
  9. package/lib/browser/idl/velocity.json +192 -16
  10. package/lib/browser/orderSubscriber/OrderSubscriber.d.ts +1 -0
  11. package/lib/browser/orderSubscriber/OrderSubscriber.js +10 -4
  12. package/lib/browser/pyth/pythLazerSubscriber.js +37 -27
  13. package/lib/browser/types.d.ts +6 -0
  14. package/lib/browser/user.d.ts +20 -3
  15. package/lib/browser/user.js +52 -4
  16. package/lib/browser/velocityClient.d.ts +46 -10
  17. package/lib/browser/velocityClient.js +107 -35
  18. package/lib/node/adminClient.d.ts +52 -0
  19. package/lib/node/adminClient.d.ts.map +1 -1
  20. package/lib/node/adminClient.js +97 -0
  21. package/lib/node/config.d.ts.map +1 -1
  22. package/lib/node/config.js +6 -7
  23. package/lib/node/constants/numericConstants.d.ts +1 -1
  24. package/lib/node/constants/numericConstants.d.ts.map +1 -1
  25. package/lib/node/constants/numericConstants.js +1 -1
  26. package/lib/node/decode/user.d.ts.map +1 -1
  27. package/lib/node/decode/user.js +5 -1
  28. package/lib/node/idl/velocity.d.ts +191 -15
  29. package/lib/node/idl/velocity.d.ts.map +1 -1
  30. package/lib/node/idl/velocity.json +192 -16
  31. package/lib/node/orderSubscriber/OrderSubscriber.d.ts +1 -0
  32. package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -1
  33. package/lib/node/orderSubscriber/OrderSubscriber.js +10 -4
  34. package/lib/node/pyth/pythLazerSubscriber.d.ts.map +1 -1
  35. package/lib/node/pyth/pythLazerSubscriber.js +37 -27
  36. package/lib/node/types.d.ts +6 -0
  37. package/lib/node/types.d.ts.map +1 -1
  38. package/lib/node/user.d.ts +20 -3
  39. package/lib/node/user.d.ts.map +1 -1
  40. package/lib/node/user.js +52 -4
  41. package/lib/node/velocityClient.d.ts +46 -10
  42. package/lib/node/velocityClient.d.ts.map +1 -1
  43. package/lib/node/velocityClient.js +107 -35
  44. package/package.json +7 -3
  45. package/.prettierignore +0 -1
  46. package/CHANGELOG.md +0 -132
  47. package/build-browser.js +0 -58
  48. package/bunfig.toml +0 -3
  49. package/esbuild-shims.js +0 -12
  50. package/scripts/deposit-isolated-positions.ts +0 -110
  51. package/scripts/find-flagged-users.ts +0 -213
  52. package/scripts/grpc-client-test-comparison.ts +0 -372
  53. package/scripts/grpc-multiuser-client-test-comparison.ts +0 -158
  54. package/scripts/postbuild.js +0 -95
  55. package/scripts/single-grpc-client-test.ts +0 -284
  56. package/scripts/withdraw-isolated-positions.ts +0 -174
  57. package/src/accounts/README_WebSocketAccountSubscriberV2.md +0 -95
  58. package/src/accounts/README_WebSocketProgramAccountSubscriberV2.md +0 -135
  59. package/src/accounts/basicUserAccountSubscriber.ts +0 -79
  60. package/src/accounts/basicUserStatsAccountSubscriber.ts +0 -87
  61. package/src/accounts/bulkAccountLoader.ts +0 -358
  62. package/src/accounts/bulkUserStatsSubscription.ts +0 -40
  63. package/src/accounts/bulkUserSubscription.ts +0 -39
  64. package/src/accounts/customizedCadenceBulkAccountLoader.ts +0 -250
  65. package/src/accounts/fetch.ts +0 -200
  66. package/src/accounts/grpcAccountSubscriber.ts +0 -225
  67. package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +0 -73
  68. package/src/accounts/grpcMultiAccountSubscriber.ts +0 -566
  69. package/src/accounts/grpcMultiUserAccountSubscriber.ts +0 -328
  70. package/src/accounts/grpcProgramAccountSubscriber.ts +0 -264
  71. package/src/accounts/grpcUserAccountSubscriber.ts +0 -63
  72. package/src/accounts/grpcUserStatsAccountSubscriber.ts +0 -65
  73. package/src/accounts/grpcVelocityClientAccountSubscriber.ts +0 -257
  74. package/src/accounts/grpcVelocityClientAccountSubscriberV2.ts +0 -941
  75. package/src/accounts/laserProgramAccountSubscriber.ts +0 -266
  76. package/src/accounts/oneShotUserAccountSubscriber.ts +0 -88
  77. package/src/accounts/oneShotUserStatsAccountSubscriber.ts +0 -94
  78. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -223
  79. package/src/accounts/pollingOracleAccountSubscriber.ts +0 -151
  80. package/src/accounts/pollingTokenAccountSubscriber.ts +0 -147
  81. package/src/accounts/pollingUserAccountSubscriber.ts +0 -198
  82. package/src/accounts/pollingUserStatsAccountSubscriber.ts +0 -180
  83. package/src/accounts/pollingVelocityClientAccountSubscriber.ts +0 -774
  84. package/src/accounts/testBulkAccountLoader.ts +0 -59
  85. package/src/accounts/types.ts +0 -428
  86. package/src/accounts/utils.ts +0 -90
  87. package/src/accounts/webSocketAccountSubscriber.ts +0 -304
  88. package/src/accounts/webSocketAccountSubscriberV2.ts +0 -536
  89. package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +0 -171
  90. package/src/accounts/webSocketProgramAccountSubscriber.ts +0 -244
  91. package/src/accounts/webSocketProgramAccountSubscriberV2.ts +0 -1048
  92. package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +0 -1042
  93. package/src/accounts/webSocketUserAccountSubscriber.ts +0 -139
  94. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +0 -131
  95. package/src/accounts/webSocketVelocityClientAccountSubscriber.ts +0 -865
  96. package/src/accounts/webSocketVelocityClientAccountSubscriberV2.ts +0 -897
  97. package/src/accounts/websocketProgramUserAccountSubscriber.ts +0 -127
  98. package/src/addresses/marketAddresses.ts +0 -28
  99. package/src/addresses/pda.ts +0 -620
  100. package/src/adminClient.ts +0 -8136
  101. package/src/assert/assert.ts +0 -5
  102. package/src/auctionSubscriber/auctionSubscriber.ts +0 -86
  103. package/src/auctionSubscriber/auctionSubscriberGrpc.ts +0 -99
  104. package/src/auctionSubscriber/index.ts +0 -9
  105. package/src/auctionSubscriber/types.ts +0 -30
  106. package/src/bankrun/bankrunConnection.ts +0 -630
  107. package/src/blockhashSubscriber/BlockhashSubscriber.ts +0 -160
  108. package/src/blockhashSubscriber/index.ts +0 -6
  109. package/src/blockhashSubscriber/types.ts +0 -13
  110. package/src/clock/clockSubscriber.ts +0 -146
  111. package/src/config.ts +0 -312
  112. package/src/constants/index.ts +0 -9
  113. package/src/constants/numericConstants.ts +0 -194
  114. package/src/constants/perpMarkets.ts +0 -127
  115. package/src/constants/spotMarkets.ts +0 -104
  116. package/src/constants/txConstants.ts +0 -2
  117. package/src/constituentMap/constituentMap.ts +0 -305
  118. package/src/constituentMap/pollingConstituentAccountSubscriber.ts +0 -99
  119. package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +0 -121
  120. package/src/core/VelocityCore.ts +0 -606
  121. package/src/core/index.ts +0 -12
  122. package/src/core/instructions/deposit.ts +0 -64
  123. package/src/core/instructions/fill.ts +0 -51
  124. package/src/core/instructions/funding.ts +0 -33
  125. package/src/core/instructions/liquidation.ts +0 -55
  126. package/src/core/instructions/orders.ts +0 -84
  127. package/src/core/instructions/perpOrders.ts +0 -312
  128. package/src/core/instructions/settlement.ts +0 -40
  129. package/src/core/instructions/trigger.ts +0 -41
  130. package/src/core/instructions/withdraw.ts +0 -65
  131. package/src/core/remainingAccounts.ts +0 -320
  132. package/src/core/signedMsg.ts +0 -109
  133. package/src/decode/customCoder.ts +0 -148
  134. package/src/decode/user.ts +0 -401
  135. package/src/dlob/DLOB.ts +0 -2793
  136. package/src/dlob/DLOBNode.ts +0 -305
  137. package/src/dlob/DLOBSubscriber.ts +0 -269
  138. package/src/dlob/NodeList.ts +0 -244
  139. package/src/dlob/orderBookLevels.ts +0 -695
  140. package/src/dlob/types.ts +0 -37
  141. package/src/events/eventList.ts +0 -114
  142. package/src/events/eventSubscriber.ts +0 -521
  143. package/src/events/eventsServerLogProvider.ts +0 -189
  144. package/src/events/fetchLogs.ts +0 -219
  145. package/src/events/parse.ts +0 -271
  146. package/src/events/pollingLogProvider.ts +0 -113
  147. package/src/events/sort.ts +0 -51
  148. package/src/events/txEventCache.ts +0 -92
  149. package/src/events/types.ts +0 -337
  150. package/src/events/webSocketLogProvider.ts +0 -152
  151. package/src/factory/bigNum.ts +0 -709
  152. package/src/factory/oracleClient.ts +0 -73
  153. package/src/idl/pyth.json +0 -142
  154. package/src/idl/pyth.ts +0 -97
  155. package/src/idl/pyth_solana_receiver.json +0 -628
  156. package/src/idl/token_faucet.json +0 -229
  157. package/src/idl/token_faucet.ts +0 -197
  158. package/src/idl/velocity.json +0 -23974
  159. package/src/idl/velocity.ts +0 -23980
  160. package/src/index.ts +0 -150
  161. package/src/indicative-quotes/indicativeQuotesSender.ts +0 -233
  162. package/src/isomorphic/README.md +0 -19
  163. package/src/isomorphic/anchor.browser.ts +0 -44
  164. package/src/isomorphic/anchor.node.ts +0 -1
  165. package/src/isomorphic/anchor.ts +0 -1
  166. package/src/isomorphic/anchor29.browser.ts +0 -24
  167. package/src/isomorphic/anchor29.node.ts +0 -1
  168. package/src/isomorphic/anchor29.ts +0 -1
  169. package/src/isomorphic/grpc.browser.ts +0 -4
  170. package/src/isomorphic/grpc.node.ts +0 -130
  171. package/src/isomorphic/grpc.ts +0 -1
  172. package/src/jupiter/jupiterClient.ts +0 -502
  173. package/src/keypair.ts +0 -32
  174. package/src/margin/README.md +0 -138
  175. package/src/marginCalculation.ts +0 -407
  176. package/src/marinade/idl/idl.json +0 -1962
  177. package/src/marinade/index.ts +0 -73
  178. package/src/marinade/types.ts +0 -3925
  179. package/src/math/amm.ts +0 -1758
  180. package/src/math/auction.ts +0 -480
  181. package/src/math/bankruptcy.ts +0 -138
  182. package/src/math/builder.ts +0 -130
  183. package/src/math/conversion.ts +0 -45
  184. package/src/math/exchangeStatus.ts +0 -261
  185. package/src/math/funding.ts +0 -498
  186. package/src/math/insurance.ts +0 -171
  187. package/src/math/liquidation.ts +0 -433
  188. package/src/math/margin.ts +0 -327
  189. package/src/math/market.ts +0 -487
  190. package/src/math/oracles.ts +0 -477
  191. package/src/math/orders.ts +0 -500
  192. package/src/math/position.ts +0 -381
  193. package/src/math/repeg.ts +0 -223
  194. package/src/math/spotBalance.ts +0 -996
  195. package/src/math/spotMarket.ts +0 -115
  196. package/src/math/spotPosition.ts +0 -263
  197. package/src/math/state.ts +0 -71
  198. package/src/math/superStake.ts +0 -602
  199. package/src/math/tiers.ts +0 -73
  200. package/src/math/trade.ts +0 -879
  201. package/src/math/utils.ts +0 -183
  202. package/src/memcmp.ts +0 -279
  203. package/src/oracles/oracleClientCache.ts +0 -41
  204. package/src/oracles/oracleId.ts +0 -99
  205. package/src/oracles/prelaunchOracleClient.ts +0 -63
  206. package/src/oracles/pythClient.ts +0 -125
  207. package/src/oracles/pythLazerClient.ts +0 -141
  208. package/src/oracles/quoteAssetOracleClient.ts +0 -43
  209. package/src/oracles/strictOraclePrice.ts +0 -40
  210. package/src/oracles/types.ts +0 -82
  211. package/src/oracles/utils.ts +0 -45
  212. package/src/orderParams.ts +0 -117
  213. package/src/orderSubscriber/OrderSubscriber.ts +0 -378
  214. package/src/orderSubscriber/PollingSubscription.ts +0 -50
  215. package/src/orderSubscriber/WebsocketSubscription.ts +0 -137
  216. package/src/orderSubscriber/grpcSubscription.ts +0 -155
  217. package/src/orderSubscriber/index.ts +0 -7
  218. package/src/orderSubscriber/types.ts +0 -64
  219. package/src/priorityFee/averageOverSlotsStrategy.ts +0 -17
  220. package/src/priorityFee/averageStrategy.ts +0 -13
  221. package/src/priorityFee/ewmaStrategy.ts +0 -51
  222. package/src/priorityFee/heliusPriorityFeeMethod.ts +0 -68
  223. package/src/priorityFee/index.ts +0 -16
  224. package/src/priorityFee/maxOverSlotsStrategy.ts +0 -18
  225. package/src/priorityFee/maxStrategy.ts +0 -8
  226. package/src/priorityFee/priorityFeeSubscriber.ts +0 -328
  227. package/src/priorityFee/priorityFeeSubscriberMap.ts +0 -134
  228. package/src/priorityFee/solanaPriorityFeeMethod.ts +0 -46
  229. package/src/priorityFee/types.ts +0 -82
  230. package/src/priorityFee/velocityPriorityFeeMethod.ts +0 -53
  231. package/src/pyth/constants.ts +0 -9
  232. package/src/pyth/index.ts +0 -15
  233. package/src/pyth/pythLazerSubscriber.ts +0 -365
  234. package/src/pyth/types.ts +0 -4451
  235. package/src/pyth/utils.ts +0 -13
  236. package/src/slot/SlotSubscriber.ts +0 -126
  237. package/src/slot/SlothashSubscriber.ts +0 -163
  238. package/src/swap/UnifiedSwapClient.ts +0 -315
  239. package/src/swift/grpcSignedMsgUserAccountSubscriber.ts +0 -81
  240. package/src/swift/index.ts +0 -10
  241. package/src/swift/signedMsgUserAccountSubscriber.ts +0 -251
  242. package/src/swift/swiftOrderSubscriber.ts +0 -351
  243. package/src/testClient.ts +0 -42
  244. package/src/titan/titanClient.ts +0 -438
  245. package/src/token/index.ts +0 -13
  246. package/src/tokenFaucet.ts +0 -296
  247. package/src/tx/baseTxSender.ts +0 -651
  248. package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +0 -31
  249. package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +0 -105
  250. package/src/tx/blockhashFetcher/types.ts +0 -9
  251. package/src/tx/fastSingleTxSender.ts +0 -200
  252. package/src/tx/forwardOnlyTxSender.ts +0 -193
  253. package/src/tx/priorityFeeCalculator.ts +0 -117
  254. package/src/tx/reportTransactionError.ts +0 -176
  255. package/src/tx/retryTxSender.ts +0 -177
  256. package/src/tx/txHandler.ts +0 -1009
  257. package/src/tx/txParamProcessor.ts +0 -225
  258. package/src/tx/types.ts +0 -117
  259. package/src/tx/utils.ts +0 -133
  260. package/src/tx/whileValidTxSender.ts +0 -377
  261. package/src/types.ts +0 -2575
  262. package/src/user.ts +0 -5316
  263. package/src/userConfig.ts +0 -38
  264. package/src/userMap/PollingSubscription.ts +0 -61
  265. package/src/userMap/WebsocketSubscription.ts +0 -93
  266. package/src/userMap/grpcSubscription.ts +0 -93
  267. package/src/userMap/referrerMap.ts +0 -360
  268. package/src/userMap/revenueShareEscrowMap.ts +0 -342
  269. package/src/userMap/userMap.ts +0 -784
  270. package/src/userMap/userMapConfig.ts +0 -82
  271. package/src/userMap/userStatsMap.ts +0 -393
  272. package/src/userName.ts +0 -37
  273. package/src/userStats.ts +0 -159
  274. package/src/userStatsConfig.ts +0 -35
  275. package/src/util/TransactionConfirmationManager.ts +0 -333
  276. package/src/util/chainClock.ts +0 -65
  277. package/src/util/computeUnits.ts +0 -101
  278. package/src/util/digest.ts +0 -33
  279. package/src/util/ed25519Utils.ts +0 -95
  280. package/src/util/promiseTimeout.ts +0 -23
  281. package/src/velocityClient.ts +0 -14802
  282. package/src/velocityClientConfig.ts +0 -119
  283. package/src/wallet.ts +0 -91
  284. package/tests/VelocityCore/builder_escrow.test.ts +0 -121
  285. package/tests/VelocityCore/decode.test.ts +0 -16
  286. package/tests/VelocityCore/fill_trigger.test.ts +0 -73
  287. package/tests/VelocityCore/instructions.test.ts +0 -46
  288. package/tests/VelocityCore/pdas.test.ts +0 -30
  289. package/tests/VelocityCore/perp_orders.test.ts +0 -205
  290. package/tests/VelocityCore/remainingAccounts.test.ts +0 -72
  291. package/tests/VelocityCore/settlement_liquidation.test.ts +0 -69
  292. package/tests/accounts/customizedCadenceBulkAccountLoader.test.ts +0 -211
  293. package/tests/amm/test.ts +0 -2402
  294. package/tests/auctions/test.ts +0 -81
  295. package/tests/bn/test.ts +0 -355
  296. package/tests/builder/builderFee.test.ts +0 -42
  297. package/tests/ci/verifyConstants.ts +0 -393
  298. package/tests/decode/test.ts +0 -262
  299. package/tests/decode/userAccountBufferStrings.ts +0 -102
  300. package/tests/dlob/helpers.ts +0 -748
  301. package/tests/dlob/test.ts +0 -6969
  302. package/tests/dlob/tickSizeStandardization.ts +0 -545
  303. package/tests/events/parseLogsForCuUsage.ts +0 -139
  304. package/tests/exchangeStatus/test.ts +0 -45
  305. package/tests/insurance/test.ts +0 -40
  306. package/tests/liquidation/test.ts +0 -125
  307. package/tests/oracles/mmOracleGate.test.ts +0 -379
  308. package/tests/oracles/pythPegSnap.test.ts +0 -76
  309. package/tests/sdkParity/enumParity.test.ts +0 -84
  310. package/tests/sdkParity/marginCategoryFill.test.ts +0 -143
  311. package/tests/sdkParity/memcmpOffsets.test.ts +0 -139
  312. package/tests/spot/test.ts +0 -281
  313. package/tests/tx/TransactionConfirmationManager.test.ts +0 -312
  314. package/tests/tx/cachedBlockhashFetcher.test.ts +0 -96
  315. package/tests/tx/priorityFeeCalculator.ts +0 -77
  316. package/tests/tx/priorityFeeStrategy.ts +0 -95
  317. package/tests/user/bankruptcy.ts +0 -165
  318. package/tests/user/feeAndWithdrawLimits.ts +0 -284
  319. package/tests/user/getMarginCalculation.ts +0 -586
  320. package/tests/user/helpers.ts +0 -184
  321. package/tests/user/liquidations.ts +0 -129
  322. package/tests/user/marginCalculations.test.ts +0 -321
  323. package/tests/user/test.ts +0 -833
  324. package/tsconfig.browser.json +0 -18
  325. package/tsconfig.json +0 -36
@@ -1,865 +0,0 @@
1
- import {
2
- AccountSubscriber,
3
- DataAndSlot,
4
- DelistedMarketSetting,
5
- VelocityClientAccountEvents,
6
- VelocityClientAccountSubscriber,
7
- NotSubscribedError,
8
- ResubOpts,
9
- } from './types';
10
- import { PerpMarketAccount, SpotMarketAccount, StateAccount } from '../types';
11
- import StrictEventEmitter from 'strict-event-emitter-types';
12
- import { EventEmitter } from 'events';
13
- import {
14
- getVelocityStateAccountPublicKey,
15
- getPerpMarketPublicKey,
16
- getPerpMarketPublicKeySync,
17
- getSpotMarketPublicKey,
18
- getSpotMarketPublicKeySync,
19
- } from '../addresses/pda';
20
- import { WebSocketAccountSubscriber } from './webSocketAccountSubscriber';
21
- import { AccountInfo, Commitment, PublicKey } from '@solana/web3.js';
22
- import { OracleInfo, OraclePriceData } from '../oracles/types';
23
- import { OracleClientCache } from '../oracles/oracleClientCache';
24
- import * as Buffer from 'buffer';
25
- import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
26
- import { findAllMarketAndOracles, VelocityProgram } from '../config';
27
- import { findDelistedPerpMarketsAndOracles } from './utils';
28
- import { getOracleId } from '../oracles/oracleId';
29
- import { OracleSource } from '../types';
30
- import { WebSocketAccountSubscriberV2 } from './webSocketAccountSubscriberV2';
31
-
32
- const ORACLE_DEFAULT_ID = getOracleId(
33
- PublicKey.default,
34
- OracleSource.QUOTE_ASSET
35
- );
36
-
37
- async function ensureAccountFetched<T>(
38
- subscriber: AccountSubscriber<T>,
39
- maxAttempts = 5,
40
- delayMs = 200
41
- ): Promise<void> {
42
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
43
- if (subscriber.dataAndSlot?.data !== undefined) {
44
- return;
45
- }
46
- try {
47
- await subscriber.fetch();
48
- } catch {
49
- // retry below
50
- }
51
- if (subscriber.dataAndSlot?.data !== undefined) {
52
- return;
53
- }
54
- await new Promise((resolve) => setTimeout(resolve, delayMs));
55
- }
56
- }
57
-
58
- /**
59
- * Default `VelocityClientAccountSubscriber` implementation: creates one `WebSocketAccountSubscriber`
60
- * per tracked `State`/`PerpMarket`/`SpotMarket`/oracle account, giving the lowest update latency
61
- * at the cost of one WebSocket subscription per account. Before subscribing each per-account
62
- * subscriber, `setInitialData()` batch-fetches all of them via `getMultipleAccountsInfo` so the
63
- * per-account `WebSocketAccountSubscriber.subscribe()` calls can seed from that data instead of
64
- * each issuing its own `getAccountInfo` round trip. `customPerpMarketAccountSubscriber`/
65
- * `customOracleAccountSubscriber` let a caller substitute `WebSocketAccountSubscriberV2` (or any
66
- * other `AccountSubscriber` implementation) for those two account types specifically.
67
- */
68
- export class WebSocketVelocityClientAccountSubscriber
69
- implements VelocityClientAccountSubscriber
70
- {
71
- isSubscribed: boolean;
72
- program: VelocityProgram;
73
- commitment?: Commitment;
74
- perpMarketIndexes: number[];
75
- spotMarketIndexes: number[];
76
- oracleInfos: OracleInfo[];
77
- oracleClientCache = new OracleClientCache();
78
-
79
- resubOpts?: ResubOpts;
80
- shouldFindAllMarketsAndOracles: boolean;
81
-
82
- eventEmitter: StrictEventEmitter<EventEmitter, VelocityClientAccountEvents>;
83
- stateAccountSubscriber?: AccountSubscriber<StateAccount>;
84
- perpMarketAccountSubscribers = new Map<
85
- number,
86
- AccountSubscriber<PerpMarketAccount>
87
- >();
88
- perpOracleMap = new Map<number, PublicKey>();
89
- perpOracleStringMap = new Map<number, string>();
90
- spotMarketAccountSubscribers = new Map<
91
- number,
92
- AccountSubscriber<SpotMarketAccount>
93
- >();
94
- spotOracleMap = new Map<number, PublicKey>();
95
- spotOracleStringMap = new Map<number, string>();
96
- oracleSubscribers = new Map<string, AccountSubscriber<OraclePriceData>>();
97
- delistedMarketSetting: DelistedMarketSetting;
98
-
99
- initialPerpMarketAccountData?: Map<number, PerpMarketAccount>;
100
- initialSpotMarketAccountData?: Map<number, SpotMarketAccount>;
101
- initialOraclePriceData?: Map<string, OraclePriceData>;
102
- customPerpMarketAccountSubscriber?: new (
103
- accountName: string,
104
- program: VelocityProgram,
105
- accountPublicKey: PublicKey,
106
- decodeBuffer?: (buffer: Buffer) => any,
107
- resubOpts?: ResubOpts,
108
- commitment?: Commitment
109
- ) => AccountSubscriber<any>;
110
- customOracleAccountSubscriber?: new (
111
- accountName: string,
112
- program: VelocityProgram,
113
- accountPublicKey: PublicKey,
114
- decodeBuffer?: (buffer: Buffer) => any,
115
- resubOpts?: ResubOpts,
116
- commitment?: Commitment
117
- ) => AccountSubscriber<any>;
118
-
119
- protected isSubscribing = false;
120
- protected subscriptionPromiseResolver: (val: boolean) => void = () => {};
121
- protected subscriptionPromise: Promise<boolean> = Promise.resolve(false);
122
-
123
- /**
124
- * @param program Anchor program used to derive PDAs, decode accounts, and resolve oracle clients.
125
- * @param perpMarketIndexes Perp market indexes to track, if `shouldFindAllMarketsAndOracles` is false.
126
- * @param spotMarketIndexes Spot market indexes to track, if `shouldFindAllMarketsAndOracles` is false.
127
- * @param oracleInfos Oracles to track up front, if `shouldFindAllMarketsAndOracles` is false.
128
- * @param shouldFindAllMarketsAndOracles If true, `subscribe()` first discovers every market/oracle from on-chain state, ignoring the index/info args above.
129
- * @param delistedMarketSetting Behavior applied to delisted perp markets/oracles after subscribing; see `DelistedMarketSetting`.
130
- * @param resubOpts Resubscription watchdog options passed to every per-account `WebSocketAccountSubscriber`.
131
- * @param commitment Commitment for every per-account subscription; defaults to the provider's configured commitment.
132
- * @param customPerpMarketAccountSubscriber Optional alternate `AccountSubscriber` constructor (e.g. `WebSocketAccountSubscriberV2`) used for perp market accounts instead of the default `WebSocketAccountSubscriber`.
133
- * @param customOracleAccountSubscriber Optional alternate `AccountSubscriber` constructor used for oracle accounts instead of the default `WebSocketAccountSubscriber`.
134
- */
135
- public constructor(
136
- program: VelocityProgram,
137
- perpMarketIndexes: number[],
138
- spotMarketIndexes: number[],
139
- oracleInfos: OracleInfo[],
140
- shouldFindAllMarketsAndOracles: boolean,
141
- delistedMarketSetting: DelistedMarketSetting,
142
- resubOpts?: ResubOpts,
143
- commitment?: Commitment,
144
- customPerpMarketAccountSubscriber?: new (
145
- accountName: string,
146
- program: VelocityProgram,
147
- accountPublicKey: PublicKey,
148
- decodeBuffer?: (buffer: Buffer) => any,
149
- resubOpts?: ResubOpts,
150
- commitment?: Commitment
151
- ) => WebSocketAccountSubscriberV2<any> | WebSocketAccountSubscriber<any>,
152
- customOracleAccountSubscriber?: new (
153
- accountName: string,
154
- program: VelocityProgram,
155
- accountPublicKey: PublicKey,
156
- decodeBuffer?: (buffer: Buffer) => any,
157
- resubOpts?: ResubOpts,
158
- commitment?: Commitment
159
- ) => WebSocketAccountSubscriberV2<any> | WebSocketAccountSubscriber<any>
160
- ) {
161
- this.isSubscribed = false;
162
- this.program = program;
163
- this.eventEmitter = new EventEmitter();
164
- this.perpMarketIndexes = perpMarketIndexes;
165
- this.spotMarketIndexes = spotMarketIndexes;
166
- this.oracleInfos = oracleInfos;
167
- this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
168
- this.delistedMarketSetting = delistedMarketSetting;
169
- this.resubOpts = resubOpts;
170
- this.commitment = commitment;
171
- this.customPerpMarketAccountSubscriber = customPerpMarketAccountSubscriber;
172
- this.customOracleAccountSubscriber = customOracleAccountSubscriber;
173
- }
174
-
175
- /**
176
- * Subscribes the `State` account, batch-seeds all market/oracle accounts via `setInitialData()`,
177
- * then subscribes every per-account `WebSocketAccountSubscriber` (or the custom subscriber
178
- * class, if configured) for perp markets, spot markets, and oracles. Applies
179
- * `delistedMarketSetting` afterward. Idempotent: a no-op if already subscribed, and concurrent
180
- * calls while a subscribe is in flight share the same result via `subscriptionPromise` rather
181
- * than issuing duplicate subscriptions. Always resolves `true` (no retry/failure path — a
182
- * per-account fetch failure surfaces via `ensureAccountFetched`'s retries, not by aborting
183
- * subscribe).
184
- */
185
- public async subscribe(): Promise<boolean> {
186
- if (this.isSubscribed) {
187
- return true;
188
- }
189
-
190
- if (this.isSubscribing) {
191
- return await this.subscriptionPromise;
192
- }
193
-
194
- this.isSubscribing = true;
195
-
196
- this.subscriptionPromise = new Promise((res) => {
197
- this.subscriptionPromiseResolver = res;
198
- });
199
-
200
- if (this.shouldFindAllMarketsAndOracles) {
201
- const {
202
- perpMarketIndexes,
203
- perpMarketAccounts,
204
- spotMarketIndexes,
205
- spotMarketAccounts,
206
- oracleInfos,
207
- } = await findAllMarketAndOracles(this.program);
208
- this.perpMarketIndexes = perpMarketIndexes;
209
- this.spotMarketIndexes = spotMarketIndexes;
210
- this.oracleInfos = oracleInfos;
211
- // front run and set the initial data here to save extra gma call in set initial data
212
- this.initialPerpMarketAccountData = new Map(
213
- perpMarketAccounts.map((market) => [market.marketIndex, market])
214
- );
215
- this.initialSpotMarketAccountData = new Map(
216
- spotMarketAccounts.map((market) => [market.marketIndex, market])
217
- );
218
- }
219
-
220
- const statePublicKey = await getVelocityStateAccountPublicKey(
221
- this.program.programId
222
- );
223
-
224
- // create and activate main state account subscription
225
- this.stateAccountSubscriber = new WebSocketAccountSubscriber(
226
- 'state',
227
- this.program,
228
- statePublicKey,
229
- undefined,
230
- undefined,
231
- this.commitment
232
- );
233
- await this.stateAccountSubscriber.subscribe((data: StateAccount) => {
234
- this.eventEmitter.emit('stateAccountUpdate', data);
235
- this.eventEmitter.emit('update');
236
- });
237
-
238
- // set initial data to avoid spamming getAccountInfo calls in webSocketAccountSubscriber
239
- await this.setInitialData();
240
-
241
- await Promise.all([
242
- // subscribe to market accounts
243
- this.subscribeToPerpMarketAccounts(),
244
- // subscribe to spot market accounts
245
- this.subscribeToSpotMarketAccounts(),
246
- // subscribe to oracles
247
- this.subscribeToOracles(),
248
- ]);
249
-
250
- this.eventEmitter.emit('update');
251
-
252
- await this.handleDelistedMarkets();
253
-
254
- await Promise.all([this.setPerpOracleMap(), this.setSpotOracleMap()]);
255
-
256
- this.isSubscribing = false;
257
- this.isSubscribed = true;
258
- this.subscriptionPromiseResolver(true);
259
-
260
- // delete initial data
261
- this.removeInitialData();
262
-
263
- return true;
264
- }
265
-
266
- chunks = <T>(array: readonly T[], size: number): T[][] => {
267
- return new Array(Math.ceil(array.length / size))
268
- .fill(null)
269
- .map((_, index) => index * size)
270
- .map((begin) => array.slice(begin, begin + size));
271
- };
272
-
273
- /**
274
- * Batch-fetches every tracked perp market, spot market, and oracle account via chunked
275
- * `getMultipleAccountsInfo` calls (75 pubkeys per chunk) and stashes the decoded results in
276
- * `initialPerpMarketAccountData`/`initialSpotMarketAccountData`/`initialOraclePriceData`.
277
- * Each per-account `WebSocketAccountSubscriber.subscribe()` call seeds from this data via
278
- * `setData` instead of issuing its own `getAccountInfo` round trip. Skips markets already
279
- * populated (e.g. by `findAllMarketAndOracles` when `shouldFindAllMarketsAndOracles` is set).
280
- */
281
- async setInitialData(): Promise<void> {
282
- const connection = this.program.provider.connection;
283
-
284
- if (!this.initialPerpMarketAccountData) {
285
- const perpMarketPublicKeys = this.perpMarketIndexes.map((marketIndex) =>
286
- getPerpMarketPublicKeySync(this.program.programId, marketIndex)
287
- );
288
- const perpMarketPublicKeysChunks = this.chunks(perpMarketPublicKeys, 75);
289
- const perpMarketAccountInfos = (
290
- await Promise.all(
291
- perpMarketPublicKeysChunks.map((perpMarketPublicKeysChunk) =>
292
- connection.getMultipleAccountsInfo(perpMarketPublicKeysChunk)
293
- )
294
- )
295
- ).flat();
296
- this.initialPerpMarketAccountData = new Map(
297
- perpMarketAccountInfos
298
- .filter(
299
- (accountInfo): accountInfo is AccountInfo<Buffer> => !!accountInfo
300
- )
301
- .map((accountInfo) => {
302
- const perpMarket = this.program.coder.accounts.decode(
303
- 'perpMarket',
304
- accountInfo.data
305
- );
306
- return [perpMarket.marketIndex, perpMarket];
307
- })
308
- );
309
- }
310
-
311
- if (!this.initialSpotMarketAccountData) {
312
- const spotMarketPublicKeys = this.spotMarketIndexes.map((marketIndex) =>
313
- getSpotMarketPublicKeySync(this.program.programId, marketIndex)
314
- );
315
- const spotMarketPublicKeysChunks = this.chunks(spotMarketPublicKeys, 75);
316
- const spotMarketAccountInfos = (
317
- await Promise.all(
318
- spotMarketPublicKeysChunks.map((spotMarketPublicKeysChunk) =>
319
- connection.getMultipleAccountsInfo(spotMarketPublicKeysChunk)
320
- )
321
- )
322
- ).flat();
323
- this.initialSpotMarketAccountData = new Map(
324
- spotMarketAccountInfos
325
- .filter(
326
- (accountInfo): accountInfo is AccountInfo<Buffer> => !!accountInfo
327
- )
328
- .map((accountInfo) => {
329
- const spotMarket = this.program.coder.accounts.decode(
330
- 'spotMarket',
331
- accountInfo.data
332
- );
333
- return [spotMarket.marketIndex, spotMarket];
334
- })
335
- );
336
- }
337
-
338
- const oracleAccountPubkeyChunks = this.chunks(
339
- this.oracleInfos.map((oracleInfo) => oracleInfo.publicKey),
340
- 75
341
- );
342
- const oracleAccountInfos = (
343
- await Promise.all(
344
- oracleAccountPubkeyChunks.map((oracleAccountPublicKeysChunk) =>
345
- connection.getMultipleAccountsInfo(oracleAccountPublicKeysChunk)
346
- )
347
- )
348
- ).flat();
349
- this.initialOraclePriceData = new Map(
350
- this.oracleInfos.reduce(
351
- (result, oracleInfo, i) => {
352
- const oracleAccountInfo = oracleAccountInfos[i];
353
- if (!oracleAccountInfo) {
354
- return result;
355
- }
356
-
357
- const oracleClient = this.oracleClientCache.get(
358
- oracleInfo.source,
359
- connection,
360
- this.program
361
- );
362
- if (!oracleClient) {
363
- return result;
364
- }
365
-
366
- const oraclePriceData = oracleClient.getOraclePriceDataFromBuffer(
367
- oracleAccountInfo.data
368
- );
369
-
370
- result.push([
371
- getOracleId(oracleInfo.publicKey, oracleInfo.source),
372
- oraclePriceData,
373
- ]);
374
- return result;
375
- },
376
- [] as [string, OraclePriceData][]
377
- )
378
- );
379
- }
380
-
381
- /** Clears the seed data stashed by `setInitialData()` once every per-account subscriber has consumed it, freeing the memory. */
382
- removeInitialData() {
383
- this.initialPerpMarketAccountData = new Map();
384
- this.initialSpotMarketAccountData = new Map();
385
- this.initialOraclePriceData = new Map();
386
- }
387
-
388
- /** Subscribes a `WebSocketAccountSubscriber` for every tracked perp market index, in parallel. */
389
- async subscribeToPerpMarketAccounts(): Promise<boolean> {
390
- await Promise.all(
391
- this.perpMarketIndexes.map((marketIndex) =>
392
- this.subscribeToPerpMarketAccount(marketIndex)
393
- )
394
- );
395
- return true;
396
- }
397
-
398
- /**
399
- * Creates and subscribes the per-account subscriber (custom class if `customPerpMarketAccountSubscriber`
400
- * is set, else `WebSocketAccountSubscriber`) for one perp market, seeding it from
401
- * `initialPerpMarketAccountData` if available, and waits (via `ensureAccountFetched`, up to 5
402
- * retries with a 200ms backoff) for data to actually land before returning.
403
- * @param marketIndex Perp market index to subscribe.
404
- */
405
- async subscribeToPerpMarketAccount(marketIndex: number): Promise<boolean> {
406
- const perpMarketPublicKey = await getPerpMarketPublicKey(
407
- this.program.programId,
408
- marketIndex
409
- );
410
- const AccountSubscriberClass =
411
- this.customPerpMarketAccountSubscriber || WebSocketAccountSubscriber;
412
- const accountSubscriber = new AccountSubscriberClass<PerpMarketAccount>(
413
- 'perpMarket',
414
- this.program,
415
- perpMarketPublicKey,
416
- undefined,
417
- this.resubOpts,
418
- this.commitment
419
- );
420
- const initialPerpMarketData =
421
- this.initialPerpMarketAccountData?.get(marketIndex);
422
- if (initialPerpMarketData) {
423
- accountSubscriber.setData(initialPerpMarketData);
424
- }
425
- await accountSubscriber.subscribe((data: PerpMarketAccount) => {
426
- this.eventEmitter.emit('perpMarketAccountUpdate', data);
427
- this.eventEmitter.emit('update');
428
- });
429
- await ensureAccountFetched(accountSubscriber);
430
- this.perpMarketAccountSubscribers.set(marketIndex, accountSubscriber);
431
- return true;
432
- }
433
-
434
- /** Subscribes a `WebSocketAccountSubscriber` for every tracked spot market index, in parallel. */
435
- async subscribeToSpotMarketAccounts(): Promise<boolean> {
436
- await Promise.all(
437
- this.spotMarketIndexes.map((marketIndex) =>
438
- this.subscribeToSpotMarketAccount(marketIndex)
439
- )
440
- );
441
- return true;
442
- }
443
-
444
- /**
445
- * Creates and subscribes a `WebSocketAccountSubscriber` for one spot market, seeding it from
446
- * `initialSpotMarketAccountData` if available, and waits (via `ensureAccountFetched`) for data
447
- * to land before returning.
448
- * @param marketIndex Spot market index to subscribe.
449
- */
450
- async subscribeToSpotMarketAccount(marketIndex: number): Promise<boolean> {
451
- const marketPublicKey = await getSpotMarketPublicKey(
452
- this.program.programId,
453
- marketIndex
454
- );
455
- const accountSubscriber = new WebSocketAccountSubscriber<SpotMarketAccount>(
456
- 'spotMarket',
457
- this.program,
458
- marketPublicKey,
459
- undefined,
460
- this.resubOpts,
461
- this.commitment
462
- );
463
- const initialSpotMarketData =
464
- this.initialSpotMarketAccountData?.get(marketIndex);
465
- if (initialSpotMarketData) {
466
- accountSubscriber.setData(initialSpotMarketData);
467
- }
468
- await accountSubscriber.subscribe((data: SpotMarketAccount) => {
469
- this.eventEmitter.emit('spotMarketAccountUpdate', data);
470
- this.eventEmitter.emit('update');
471
- });
472
- await ensureAccountFetched(accountSubscriber);
473
- this.spotMarketAccountSubscribers.set(marketIndex, accountSubscriber);
474
- return true;
475
- }
476
-
477
- /** Subscribes an account subscriber for every tracked oracle, in parallel, skipping the `PublicKey.default` (quote-asset "no oracle") sentinel. */
478
- async subscribeToOracles(): Promise<boolean> {
479
- await Promise.all(
480
- this.oracleInfos
481
- .filter((oracleInfo) => !oracleInfo.publicKey.equals(PublicKey.default))
482
- .map((oracleInfo) => this.subscribeToOracle(oracleInfo))
483
- );
484
-
485
- return true;
486
- }
487
-
488
- /**
489
- * Creates and subscribes the per-account subscriber (custom class if `customOracleAccountSubscriber`
490
- * is set, else `WebSocketAccountSubscriber`) for one oracle, decoding buffers with the
491
- * source-appropriate `OracleClient`. Seeds from `initialOraclePriceData` if available and
492
- * waits (via `ensureAccountFetched`) for data to land before returning.
493
- * @param oracleInfo Oracle pubkey and source to subscribe.
494
- * @returns `false` if no `OracleClient` is registered for `oracleInfo.source`; otherwise `true`.
495
- */
496
- async subscribeToOracle(oracleInfo: OracleInfo): Promise<boolean> {
497
- const oracleId = getOracleId(oracleInfo.publicKey, oracleInfo.source);
498
- const client = this.oracleClientCache.get(
499
- oracleInfo.source,
500
- this.program.provider.connection,
501
- this.program
502
- );
503
- if (!client) {
504
- return false;
505
- }
506
- const AccountSubscriberClass =
507
- this.customOracleAccountSubscriber || WebSocketAccountSubscriber;
508
- const accountSubscriber = new AccountSubscriberClass<OraclePriceData>(
509
- 'oracle',
510
- this.program,
511
- oracleInfo.publicKey,
512
- (buffer: Buffer) => {
513
- return client.getOraclePriceDataFromBuffer(buffer);
514
- },
515
- this.resubOpts,
516
- this.commitment
517
- );
518
- const initialOraclePriceData = this.initialOraclePriceData?.get(oracleId);
519
- if (initialOraclePriceData) {
520
- accountSubscriber.setData(initialOraclePriceData);
521
- }
522
- await accountSubscriber.subscribe((data: OraclePriceData) => {
523
- this.eventEmitter.emit(
524
- 'oraclePriceUpdate',
525
- oracleInfo.publicKey,
526
- oracleInfo.source,
527
- data
528
- );
529
- this.eventEmitter.emit('update');
530
- });
531
- await ensureAccountFetched(accountSubscriber);
532
-
533
- this.oracleSubscribers.set(oracleId, accountSubscriber);
534
- return true;
535
- }
536
-
537
- /** Unsubscribes every per-account subscriber tracking a perp market, in parallel. */
538
- async unsubscribeFromMarketAccounts(): Promise<void> {
539
- await Promise.all(
540
- Array.from(this.perpMarketAccountSubscribers.values()).map(
541
- (accountSubscriber) => accountSubscriber.unsubscribe()
542
- )
543
- );
544
- }
545
-
546
- /** Unsubscribes every per-account subscriber tracking a spot market, in parallel. */
547
- async unsubscribeFromSpotMarketAccounts(): Promise<void> {
548
- await Promise.all(
549
- Array.from(this.spotMarketAccountSubscribers.values()).map(
550
- (accountSubscriber) => accountSubscriber.unsubscribe()
551
- )
552
- );
553
- }
554
-
555
- /** Unsubscribes every per-account subscriber tracking an oracle, in parallel. */
556
- async unsubscribeFromOracles(): Promise<void> {
557
- await Promise.all(
558
- Array.from(this.oracleSubscribers.values()).map((accountSubscriber) =>
559
- accountSubscriber.unsubscribe()
560
- )
561
- );
562
- }
563
-
564
- /** Fetches the `State` account and every subscribed perp/spot market's `WebSocketAccountSubscriber` in parallel. A no-op if not subscribed. Oracle accounts are not re-fetched here (they update via their own WS notifications). */
565
- public async fetch(): Promise<void> {
566
- if (!this.isSubscribed) {
567
- return;
568
- }
569
-
570
- if (!this.stateAccountSubscriber) {
571
- return;
572
- }
573
-
574
- const promises = [this.stateAccountSubscriber.fetch()]
575
- .concat(
576
- Array.from(this.perpMarketAccountSubscribers.values()).map(
577
- (subscriber) => subscriber.fetch()
578
- )
579
- )
580
- .concat(
581
- Array.from(this.spotMarketAccountSubscribers.values()).map(
582
- (subscriber) => subscriber.fetch()
583
- )
584
- );
585
-
586
- await Promise.all(promises);
587
- }
588
-
589
- /** Tears down the `State` subscriber and every per-account market/oracle subscriber. A no-op if not subscribed. */
590
- public async unsubscribe(): Promise<void> {
591
- if (!this.isSubscribed) {
592
- return;
593
- }
594
-
595
- await this.stateAccountSubscriber?.unsubscribe();
596
-
597
- await this.unsubscribeFromMarketAccounts();
598
- await this.unsubscribeFromSpotMarketAccounts();
599
- await this.unsubscribeFromOracles();
600
-
601
- this.isSubscribed = false;
602
- }
603
-
604
- /**
605
- * Adds a spot market (and its oracle, via `setSpotOracleMap`) to be tracked, subscribing a new
606
- * `WebSocketAccountSubscriber` for it. Idempotent: returns `true` immediately if already tracked.
607
- * @param marketIndex Spot market index to start tracking.
608
- */
609
- async addSpotMarket(marketIndex: number): Promise<boolean> {
610
- if (this.spotMarketAccountSubscribers.has(marketIndex)) {
611
- return true;
612
- }
613
- const subscriptionSuccess = await this.subscribeToSpotMarketAccount(
614
- marketIndex
615
- );
616
- await this.setSpotOracleMap();
617
- return subscriptionSuccess;
618
- }
619
-
620
- /**
621
- * Adds a perp market (and its oracle, via `setPerpOracleMap`) to be tracked, subscribing a new
622
- * `WebSocketAccountSubscriber` for it. Idempotent: returns `true` immediately if already tracked.
623
- * @param marketIndex Perp market index to start tracking.
624
- */
625
- async addPerpMarket(marketIndex: number): Promise<boolean> {
626
- if (this.perpMarketAccountSubscribers.has(marketIndex)) {
627
- return true;
628
- }
629
- const subscriptionSuccess = await this.subscribeToPerpMarketAccount(
630
- marketIndex
631
- );
632
- await this.setPerpOracleMap();
633
- return subscriptionSuccess;
634
- }
635
-
636
- /**
637
- * Adds an oracle to be tracked, subscribing a new per-account subscriber for it. A no-op that
638
- * resolves `true` immediately for the `PublicKey.default` sentinel (quote-asset "no oracle")
639
- * or an oracle already tracked.
640
- * @param oracleInfo Oracle pubkey and source to start tracking.
641
- */
642
- async addOracle(oracleInfo: OracleInfo): Promise<boolean> {
643
- const oracleId = getOracleId(oracleInfo.publicKey, oracleInfo.source);
644
- if (this.oracleSubscribers.has(oracleId)) {
645
- return true;
646
- }
647
-
648
- if (oracleInfo.publicKey.equals(PublicKey.default)) {
649
- return true;
650
- }
651
-
652
- return this.subscribeToOracle(oracleInfo);
653
- }
654
-
655
- /** Rebuilds `perpOracleMap`/`perpOracleStringMap` from currently cached perp markets, calling `addOracle` for any oracle not yet tracked. */
656
- async setPerpOracleMap() {
657
- const perpMarkets = this.getMarketAccountsAndSlots();
658
- const addOraclePromises = [];
659
- for (const perpMarket of perpMarkets) {
660
- if (!perpMarket || !perpMarket.data) {
661
- continue;
662
- }
663
- const perpMarketAccount = perpMarket.data;
664
- const perpMarketIndex = perpMarketAccount.marketIndex;
665
- const oracle = perpMarketAccount.oracle;
666
- const oracleId = getOracleId(oracle, perpMarket.data.oracleSource);
667
- if (!this.oracleSubscribers.has(oracleId)) {
668
- addOraclePromises.push(
669
- this.addOracle({
670
- publicKey: oracle,
671
- source: perpMarket.data.oracleSource,
672
- })
673
- );
674
- }
675
- this.perpOracleMap.set(perpMarketIndex, oracle);
676
- this.perpOracleStringMap.set(perpMarketIndex, oracleId);
677
- }
678
- await Promise.all(addOraclePromises);
679
- }
680
-
681
- /** Rebuilds `spotOracleMap`/`spotOracleStringMap` from currently cached spot markets, calling `addOracle` for any oracle not yet tracked. */
682
- async setSpotOracleMap() {
683
- const spotMarkets = this.getSpotMarketAccountsAndSlots();
684
- const addOraclePromises = [];
685
- for (const spotMarket of spotMarkets) {
686
- if (!spotMarket || !spotMarket.data) {
687
- continue;
688
- }
689
- const spotMarketAccount = spotMarket.data;
690
- const spotMarketIndex = spotMarketAccount.marketIndex;
691
- const oracle = spotMarketAccount.oracle;
692
- const oracleId = getOracleId(oracle, spotMarketAccount.oracleSource);
693
- if (!this.oracleSubscribers.has(oracleId)) {
694
- addOraclePromises.push(
695
- this.addOracle({
696
- publicKey: oracle,
697
- source: spotMarketAccount.oracleSource,
698
- })
699
- );
700
- }
701
- this.spotOracleMap.set(spotMarketIndex, oracle);
702
- this.spotOracleStringMap.set(spotMarketIndex, oracleId);
703
- }
704
- await Promise.all(addOraclePromises);
705
- }
706
-
707
- /**
708
- * Applies `delistedMarketSetting` to any perp market currently `status: delisted` (and its
709
- * oracle, if not shared with a live spot market): unsubscribes the per-account subscriber, and
710
- * additionally drops it from `perpMarketAccountSubscribers`/`oracleSubscribers` if the setting
711
- * is `Discard`. A no-op if the setting is `Subscribe`.
712
- */
713
- async handleDelistedMarkets(): Promise<void> {
714
- if (this.delistedMarketSetting === DelistedMarketSetting.Subscribe) {
715
- return;
716
- }
717
-
718
- const { perpMarketIndexes, oracles } = findDelistedPerpMarketsAndOracles(
719
- this.getMarketAccountsAndSlots(),
720
- this.getSpotMarketAccountsAndSlots()
721
- );
722
-
723
- for (const perpMarketIndex of perpMarketIndexes) {
724
- await this.perpMarketAccountSubscribers
725
- .get(perpMarketIndex)
726
- ?.unsubscribe();
727
- if (this.delistedMarketSetting === DelistedMarketSetting.Discard) {
728
- this.perpMarketAccountSubscribers.delete(perpMarketIndex);
729
- }
730
- }
731
-
732
- for (const oracle of oracles) {
733
- const oracleId = getOracleId(oracle.publicKey, oracle.source);
734
- await this.oracleSubscribers.get(oracleId)?.unsubscribe();
735
- if (this.delistedMarketSetting === DelistedMarketSetting.Discard) {
736
- this.oracleSubscribers.delete(oracleId);
737
- }
738
- }
739
- }
740
-
741
- /** Throws `NotSubscribedError` if `subscribe()` has not been called. */
742
- assertIsSubscribed(): void {
743
- if (!this.isSubscribed) {
744
- throw new NotSubscribedError(
745
- 'You must call `subscribe` before using this function'
746
- );
747
- }
748
- }
749
-
750
- /** Throws `NotSubscribedError` if not subscribed, or a generic `Error` if subscribed but the `State` account hasn't loaded yet (should not normally happen after `subscribe()` resolves). */
751
- public getStateAccountAndSlot(): DataAndSlot<StateAccount> {
752
- this.assertIsSubscribed();
753
- const dataAndSlot = this.stateAccountSubscriber?.dataAndSlot;
754
- if (!dataAndSlot) {
755
- throw new Error('State account data not available');
756
- }
757
- return dataAndSlot;
758
- }
759
-
760
- /** Throws `NotSubscribedError` if not subscribed. Returns undefined if `marketIndex` isn't tracked (or hasn't loaded yet). */
761
- public getMarketAccountAndSlot(
762
- marketIndex: number
763
- ): DataAndSlot<PerpMarketAccount> | undefined {
764
- this.assertIsSubscribed();
765
- return this.perpMarketAccountSubscribers.get(marketIndex)?.dataAndSlot;
766
- }
767
-
768
- /** Returns every currently cached (loaded) perp market. Does not throw `NotSubscribedError`. */
769
- public getMarketAccountsAndSlots(): DataAndSlot<PerpMarketAccount>[] {
770
- return Array.from(this.perpMarketAccountSubscribers.values())
771
- .map((subscriber) => subscriber.dataAndSlot)
772
- .filter(
773
- (dataAndSlot): dataAndSlot is DataAndSlot<PerpMarketAccount> =>
774
- dataAndSlot !== undefined
775
- );
776
- }
777
-
778
- /** Throws `NotSubscribedError` if not subscribed. Returns undefined if `marketIndex` isn't tracked (or hasn't loaded yet). */
779
- public getSpotMarketAccountAndSlot(
780
- marketIndex: number
781
- ): DataAndSlot<SpotMarketAccount> | undefined {
782
- this.assertIsSubscribed();
783
- return this.spotMarketAccountSubscribers.get(marketIndex)?.dataAndSlot;
784
- }
785
-
786
- /** Returns every currently cached (loaded) spot market. Does not throw `NotSubscribedError`. */
787
- public getSpotMarketAccountsAndSlots(): DataAndSlot<SpotMarketAccount>[] {
788
- return Array.from(this.spotMarketAccountSubscribers.values())
789
- .map((subscriber) => subscriber.dataAndSlot)
790
- .filter(
791
- (dataAndSlot): dataAndSlot is DataAndSlot<SpotMarketAccount> =>
792
- dataAndSlot !== undefined
793
- );
794
- }
795
-
796
- /**
797
- * Looks up cached oracle price data by oracle id (see `getOracleId`). Special-cases the
798
- * quote-asset default oracle id, returning the constant `QUOTE_ORACLE_PRICE_DATA` at slot 0
799
- * rather than a subscriber lookup, since that oracle is never actually subscribed to.
800
- * @param oracleId Oracle id string from `getOracleId(publicKey, source)`.
801
- * @returns Cached price data/slot, or undefined if not tracked. Throws `NotSubscribedError` if not subscribed.
802
- */
803
- public getOraclePriceDataAndSlot(
804
- oracleId: string
805
- ): DataAndSlot<OraclePriceData> | undefined {
806
- this.assertIsSubscribed();
807
- if (oracleId === ORACLE_DEFAULT_ID) {
808
- return {
809
- data: QUOTE_ORACLE_PRICE_DATA,
810
- slot: 0,
811
- };
812
- }
813
- return this.oracleSubscribers.get(oracleId)?.dataAndSlot;
814
- }
815
-
816
- /**
817
- * Convenience lookup: resolves the oracle price data currently mapped to a perp market's
818
- * oracle. If the cached market's oracle pubkey has drifted from (or isn't yet in)
819
- * `perpOracleMap`, triggers a background `setPerpOracleMap()` refresh and still returns the
820
- * (possibly stale) mapping for this call.
821
- * @param marketIndex Perp market index whose oracle price to look up.
822
- */
823
- public getOraclePriceDataAndSlotForPerpMarket(
824
- marketIndex: number
825
- ): DataAndSlot<OraclePriceData> | undefined {
826
- const perpMarketAccount = this.getMarketAccountAndSlot(marketIndex);
827
- const oracle = this.perpOracleMap.get(marketIndex);
828
- const oracleId = this.perpOracleStringMap.get(marketIndex);
829
- if (!perpMarketAccount || !oracleId) {
830
- return undefined;
831
- }
832
-
833
- if (!oracle || !perpMarketAccount.data.oracle.equals(oracle)) {
834
- // If the oracle has changed (or not yet cached), update the oracle map in background
835
- this.setPerpOracleMap();
836
- }
837
-
838
- return this.getOraclePriceDataAndSlot(oracleId);
839
- }
840
-
841
- /**
842
- * Convenience lookup: resolves the oracle price data currently mapped to a spot market's
843
- * oracle. If the cached market's oracle pubkey has drifted from (or isn't yet in)
844
- * `spotOracleMap`, triggers a background `setSpotOracleMap()` refresh and still returns the
845
- * (possibly stale) mapping for this call.
846
- * @param marketIndex Spot market index whose oracle price to look up.
847
- */
848
- public getOraclePriceDataAndSlotForSpotMarket(
849
- marketIndex: number
850
- ): DataAndSlot<OraclePriceData> | undefined {
851
- const spotMarketAccount = this.getSpotMarketAccountAndSlot(marketIndex);
852
- const oracle = this.spotOracleMap.get(marketIndex);
853
- const oracleId = this.spotOracleStringMap.get(marketIndex);
854
- if (!spotMarketAccount || !oracleId) {
855
- return undefined;
856
- }
857
-
858
- if (!oracle || !spotMarketAccount.data.oracle.equals(oracle)) {
859
- // If the oracle has changed (or not yet cached), update the oracle map in background
860
- this.setSpotOracleMap();
861
- }
862
-
863
- return this.getOraclePriceDataAndSlot(oracleId);
864
- }
865
- }