@velocity-exchange/sdk 0.3.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 (1127) hide show
  1. package/README.md +3 -3
  2. package/lib/browser/accounts/basicUserAccountSubscriber.d.ts +18 -0
  3. package/lib/browser/accounts/basicUserAccountSubscriber.js +18 -0
  4. package/lib/browser/accounts/basicUserStatsAccountSubscriber.d.ts +18 -0
  5. package/lib/browser/accounts/basicUserStatsAccountSubscriber.js +18 -0
  6. package/lib/browser/accounts/bulkAccountLoader.d.ts +52 -0
  7. package/lib/browser/accounts/bulkAccountLoader.js +51 -0
  8. package/lib/browser/accounts/bulkUserStatsSubscription.d.ts +9 -2
  9. package/lib/browser/accounts/bulkUserStatsSubscription.js +9 -2
  10. package/lib/browser/accounts/bulkUserSubscription.d.ts +8 -2
  11. package/lib/browser/accounts/bulkUserSubscription.js +8 -2
  12. package/lib/browser/accounts/customizedCadenceBulkAccountLoader.d.ts +37 -0
  13. package/lib/browser/accounts/customizedCadenceBulkAccountLoader.js +37 -0
  14. package/lib/browser/accounts/fetch.d.ts +59 -2
  15. package/lib/browser/accounts/fetch.js +57 -2
  16. package/lib/browser/accounts/grpcAccountSubscriber.d.ts +30 -0
  17. package/lib/browser/accounts/grpcAccountSubscriber.js +30 -0
  18. package/lib/browser/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts +16 -0
  19. package/lib/browser/accounts/grpcInsuranceFundStakeAccountSubscriber.js +16 -0
  20. package/lib/browser/accounts/grpcMultiAccountSubscriber.d.ts +60 -1
  21. package/lib/browser/accounts/grpcMultiAccountSubscriber.js +118 -37
  22. package/lib/browser/accounts/grpcMultiUserAccountSubscriber.d.ts +32 -0
  23. package/lib/browser/accounts/grpcMultiUserAccountSubscriber.js +40 -12
  24. package/lib/browser/accounts/grpcProgramAccountSubscriber.d.ts +33 -0
  25. package/lib/browser/accounts/grpcProgramAccountSubscriber.js +33 -0
  26. package/lib/browser/accounts/grpcUserAccountSubscriber.d.ts +15 -0
  27. package/lib/browser/accounts/grpcUserAccountSubscriber.js +15 -0
  28. package/lib/browser/accounts/grpcUserStatsAccountSubscriber.d.ts +15 -0
  29. package/lib/browser/accounts/grpcUserStatsAccountSubscriber.js +15 -0
  30. package/lib/browser/accounts/grpcVelocityClientAccountSubscriber.d.ts +41 -0
  31. package/lib/browser/accounts/grpcVelocityClientAccountSubscriber.js +41 -0
  32. package/lib/browser/accounts/grpcVelocityClientAccountSubscriberV2.d.ts +116 -0
  33. package/lib/browser/accounts/grpcVelocityClientAccountSubscriberV2.js +152 -1
  34. package/lib/browser/accounts/laserProgramAccountSubscriber.d.ts +34 -0
  35. package/lib/browser/accounts/laserProgramAccountSubscriber.js +34 -0
  36. package/lib/browser/accounts/oneShotUserAccountSubscriber.d.ts +19 -0
  37. package/lib/browser/accounts/oneShotUserAccountSubscriber.js +19 -0
  38. package/lib/browser/accounts/oneShotUserStatsAccountSubscriber.d.ts +19 -0
  39. package/lib/browser/accounts/oneShotUserStatsAccountSubscriber.js +19 -0
  40. package/lib/browser/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts +31 -0
  41. package/lib/browser/accounts/pollingInsuranceFundStakeAccountSubscriber.js +31 -0
  42. package/lib/browser/accounts/pollingOracleAccountSubscriber.d.ts +19 -0
  43. package/lib/browser/accounts/pollingOracleAccountSubscriber.js +21 -2
  44. package/lib/browser/accounts/pollingTokenAccountSubscriber.d.ts +22 -0
  45. package/lib/browser/accounts/pollingTokenAccountSubscriber.js +22 -0
  46. package/lib/browser/accounts/pollingUserAccountSubscriber.d.ts +32 -0
  47. package/lib/browser/accounts/pollingUserAccountSubscriber.js +32 -0
  48. package/lib/browser/accounts/pollingUserStatsAccountSubscriber.d.ts +22 -0
  49. package/lib/browser/accounts/pollingUserStatsAccountSubscriber.js +22 -0
  50. package/lib/browser/accounts/pollingVelocityClientAccountSubscriber.d.ts +83 -0
  51. package/lib/browser/accounts/pollingVelocityClientAccountSubscriber.js +84 -1
  52. package/lib/browser/accounts/testBulkAccountLoader.d.ts +8 -0
  53. package/lib/browser/accounts/testBulkAccountLoader.js +8 -0
  54. package/lib/browser/accounts/types.d.ts +149 -0
  55. package/lib/browser/accounts/types.js +13 -0
  56. package/lib/browser/accounts/utils.d.ts +18 -0
  57. package/lib/browser/accounts/utils.js +32 -16
  58. package/lib/browser/accounts/webSocketAccountSubscriber.d.ts +41 -0
  59. package/lib/browser/accounts/webSocketAccountSubscriber.js +41 -0
  60. package/lib/browser/accounts/webSocketAccountSubscriberV2.d.ts +31 -0
  61. package/lib/browser/accounts/webSocketAccountSubscriberV2.js +31 -23
  62. package/lib/browser/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +27 -0
  63. package/lib/browser/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +27 -0
  64. package/lib/browser/accounts/webSocketProgramAccountSubscriber.d.ts +36 -0
  65. package/lib/browser/accounts/webSocketProgramAccountSubscriber.js +36 -0
  66. package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.d.ts +21 -0
  67. package/lib/browser/accounts/webSocketProgramAccountSubscriberV2.js +25 -0
  68. package/lib/browser/accounts/webSocketProgramAccountsSubscriberV2.d.ts +21 -0
  69. package/lib/browser/accounts/webSocketProgramAccountsSubscriberV2.js +21 -0
  70. package/lib/browser/accounts/webSocketUserAccountSubscriber.d.ts +26 -0
  71. package/lib/browser/accounts/webSocketUserAccountSubscriber.js +26 -0
  72. package/lib/browser/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  73. package/lib/browser/accounts/webSocketUserStatsAccountSubsriber.js +20 -0
  74. package/lib/browser/accounts/webSocketVelocityClientAccountSubscriber.d.ts +121 -0
  75. package/lib/browser/accounts/webSocketVelocityClientAccountSubscriber.js +123 -2
  76. package/lib/browser/accounts/webSocketVelocityClientAccountSubscriberV2.d.ts +96 -0
  77. package/lib/browser/accounts/webSocketVelocityClientAccountSubscriberV2.js +108 -0
  78. package/lib/browser/accounts/websocketProgramUserAccountSubscriber.d.ts +28 -0
  79. package/lib/browser/accounts/websocketProgramUserAccountSubscriber.js +33 -0
  80. package/lib/browser/addresses/marketAddresses.d.ts +10 -0
  81. package/lib/browser/addresses/marketAddresses.js +10 -0
  82. package/lib/browser/addresses/pda.d.ts +214 -2
  83. package/lib/browser/addresses/pda.js +217 -5
  84. package/lib/browser/adminClient.d.ts +2171 -4
  85. package/lib/browser/adminClient.js +2215 -4
  86. package/lib/browser/auctionSubscriber/auctionSubscriber.d.ts +15 -0
  87. package/lib/browser/auctionSubscriber/auctionSubscriber.js +15 -0
  88. package/lib/browser/auctionSubscriber/auctionSubscriberGrpc.d.ts +19 -0
  89. package/lib/browser/auctionSubscriber/auctionSubscriberGrpc.js +19 -0
  90. package/lib/browser/auctionSubscriber/index.d.ts +6 -0
  91. package/lib/browser/auctionSubscriber/index.js +6 -0
  92. package/lib/browser/auctionSubscriber/types.d.ts +7 -0
  93. package/lib/browser/blockhashSubscriber/BlockhashSubscriber.d.ts +33 -0
  94. package/lib/browser/blockhashSubscriber/BlockhashSubscriber.js +33 -0
  95. package/lib/browser/blockhashSubscriber/index.d.ts +5 -0
  96. package/lib/browser/blockhashSubscriber/index.js +5 -0
  97. package/lib/browser/blockhashSubscriber/types.d.ts +5 -0
  98. package/lib/browser/clock/clockSubscriber.d.ts +24 -0
  99. package/lib/browser/clock/clockSubscriber.js +22 -0
  100. package/lib/browser/config.d.ts +58 -4
  101. package/lib/browser/config.js +94 -28
  102. package/lib/browser/constants/numericConstants.d.ts +67 -0
  103. package/lib/browser/constants/numericConstants.js +68 -1
  104. package/lib/browser/constants/perpMarkets.d.ts +10 -0
  105. package/lib/browser/constants/perpMarkets.js +40 -908
  106. package/lib/browser/constants/spotMarkets.d.ts +13 -0
  107. package/lib/browser/constants/spotMarkets.js +16 -742
  108. package/lib/browser/constants/txConstants.d.ts +1 -0
  109. package/lib/browser/constants/txConstants.js +1 -0
  110. package/lib/browser/core/VelocityCore.d.ts +285 -8
  111. package/lib/browser/core/VelocityCore.js +281 -8
  112. package/lib/browser/core/instructions/deposit.d.ts +22 -0
  113. package/lib/browser/core/instructions/deposit.js +22 -0
  114. package/lib/browser/core/instructions/fill.d.ts +17 -0
  115. package/lib/browser/core/instructions/fill.js +17 -0
  116. package/lib/browser/core/instructions/funding.d.ts +12 -0
  117. package/lib/browser/core/instructions/funding.js +12 -0
  118. package/lib/browser/core/instructions/liquidation.d.ts +18 -0
  119. package/lib/browser/core/instructions/liquidation.js +18 -0
  120. package/lib/browser/core/instructions/orders.d.ts +28 -0
  121. package/lib/browser/core/instructions/orders.js +28 -0
  122. package/lib/browser/core/instructions/perpOrders.d.ts +106 -0
  123. package/lib/browser/core/instructions/perpOrders.js +106 -0
  124. package/lib/browser/core/instructions/settlement.d.ts +14 -0
  125. package/lib/browser/core/instructions/settlement.js +14 -0
  126. package/lib/browser/core/instructions/trigger.d.ts +15 -0
  127. package/lib/browser/core/instructions/trigger.js +15 -0
  128. package/lib/browser/core/instructions/withdraw.d.ts +21 -0
  129. package/lib/browser/core/instructions/withdraw.js +21 -0
  130. package/lib/browser/core/remainingAccounts.d.ts +47 -3
  131. package/lib/browser/core/remainingAccounts.js +20 -0
  132. package/lib/browser/core/signedMsg.d.ts +38 -0
  133. package/lib/browser/core/signedMsg.js +33 -0
  134. package/lib/browser/decode/customCoder.d.ts +39 -3
  135. package/lib/browser/decode/customCoder.js +45 -3
  136. package/lib/browser/decode/user.d.ts +22 -0
  137. package/lib/browser/decode/user.js +27 -1
  138. package/lib/browser/dlob/DLOB.d.ts +502 -53
  139. package/lib/browser/dlob/DLOB.js +540 -98
  140. package/lib/browser/dlob/DLOBNode.d.ts +86 -4
  141. package/lib/browser/dlob/DLOBNode.js +37 -4
  142. package/lib/browser/dlob/DLOBSubscriber.d.ts +39 -12
  143. package/lib/browser/dlob/DLOBSubscriber.js +42 -12
  144. package/lib/browser/dlob/NodeList.d.ts +69 -0
  145. package/lib/browser/dlob/NodeList.js +66 -0
  146. package/lib/browser/dlob/orderBookLevels.d.ts +106 -13
  147. package/lib/browser/dlob/orderBookLevels.js +84 -14
  148. package/lib/browser/dlob/types.d.ts +15 -0
  149. package/lib/browser/events/eventList.d.ts +14 -0
  150. package/lib/browser/events/eventList.js +14 -0
  151. package/lib/browser/events/eventSubscriber.d.ts +87 -10
  152. package/lib/browser/events/eventSubscriber.js +93 -8
  153. package/lib/browser/events/eventsServerLogProvider.d.ts +22 -0
  154. package/lib/browser/events/eventsServerLogProvider.js +27 -0
  155. package/lib/browser/events/fetchLogs.d.ts +31 -0
  156. package/lib/browser/events/fetchLogs.js +46 -1
  157. package/lib/browser/events/parse.d.ts +23 -0
  158. package/lib/browser/events/parse.js +23 -0
  159. package/lib/browser/events/pollingLogProvider.d.ts +24 -0
  160. package/lib/browser/events/pollingLogProvider.js +24 -0
  161. package/lib/browser/events/sort.d.ts +11 -0
  162. package/lib/browser/events/sort.js +12 -0
  163. package/lib/browser/events/txEventCache.d.ts +13 -3
  164. package/lib/browser/events/txEventCache.js +19 -7
  165. package/lib/browser/events/types.d.ts +118 -2
  166. package/lib/browser/events/types.js +11 -0
  167. package/lib/browser/events/webSocketLogProvider.d.ts +23 -0
  168. package/lib/browser/events/webSocketLogProvider.js +28 -0
  169. package/lib/browser/factory/oracleClient.js +2 -2
  170. package/lib/browser/idl/velocity.d.ts +150 -7
  171. package/lib/browser/idl/velocity.json +151 -8
  172. package/lib/browser/keypair.d.ts +8 -0
  173. package/lib/browser/keypair.js +8 -0
  174. package/lib/browser/marginCalculation.d.ts +134 -2
  175. package/lib/browser/marginCalculation.js +121 -0
  176. package/lib/browser/math/amm.d.ts +348 -29
  177. package/lib/browser/math/amm.js +310 -32
  178. package/lib/browser/math/auction.d.ts +95 -19
  179. package/lib/browser/math/auction.js +118 -28
  180. package/lib/browser/math/bankruptcy.d.ts +46 -0
  181. package/lib/browser/math/bankruptcy.js +89 -1
  182. package/lib/browser/math/builder.d.ts +64 -8
  183. package/lib/browser/math/builder.js +71 -9
  184. package/lib/browser/math/conversion.d.ts +21 -0
  185. package/lib/browser/math/conversion.js +21 -0
  186. package/lib/browser/math/exchangeStatus.d.ts +91 -0
  187. package/lib/browser/math/exchangeStatus.js +106 -3
  188. package/lib/browser/math/funding.d.ts +57 -20
  189. package/lib/browser/math/funding.js +63 -23
  190. package/lib/browser/math/insurance.d.ts +62 -0
  191. package/lib/browser/math/insurance.js +62 -0
  192. package/lib/browser/math/liquidation.d.ts +127 -11
  193. package/lib/browser/math/liquidation.js +182 -19
  194. package/lib/browser/math/margin.d.ts +79 -13
  195. package/lib/browser/math/margin.js +80 -14
  196. package/lib/browser/math/market.d.ts +135 -15
  197. package/lib/browser/math/market.js +145 -17
  198. package/lib/browser/math/oracles.d.ts +113 -0
  199. package/lib/browser/math/oracles.js +118 -1
  200. package/lib/browser/math/orders.d.ts +115 -10
  201. package/lib/browser/math/orders.js +130 -19
  202. package/lib/browser/math/position.d.ts +80 -33
  203. package/lib/browser/math/position.js +80 -33
  204. package/lib/browser/math/repeg.d.ts +48 -10
  205. package/lib/browser/math/repeg.js +48 -10
  206. package/lib/browser/math/spotBalance.d.ts +200 -5
  207. package/lib/browser/math/spotBalance.js +239 -10
  208. package/lib/browser/math/spotMarket.d.ts +36 -3
  209. package/lib/browser/math/spotMarket.js +36 -3
  210. package/lib/browser/math/spotPosition.d.ts +72 -0
  211. package/lib/browser/math/spotPosition.js +62 -0
  212. package/lib/browser/math/state.d.ts +31 -0
  213. package/lib/browser/math/state.js +31 -0
  214. package/lib/browser/math/superStake.d.ts +126 -2
  215. package/lib/browser/math/superStake.js +123 -3
  216. package/lib/browser/math/tiers.d.ts +29 -0
  217. package/lib/browser/math/tiers.js +29 -0
  218. package/lib/browser/math/trade.d.ts +102 -51
  219. package/lib/browser/math/trade.js +101 -55
  220. package/lib/browser/math/utils.d.ts +71 -9
  221. package/lib/browser/math/utils.js +71 -9
  222. package/lib/browser/memcmp.d.ts +94 -0
  223. package/lib/browser/memcmp.js +103 -2
  224. package/lib/browser/oracles/oracleClientCache.d.ts +16 -0
  225. package/lib/browser/oracles/oracleClientCache.js +16 -0
  226. package/lib/browser/oracles/oracleId.d.ts +31 -0
  227. package/lib/browser/oracles/oracleId.js +39 -8
  228. package/lib/browser/oracles/prelaunchOracleClient.d.ts +20 -0
  229. package/lib/browser/oracles/prelaunchOracleClient.js +20 -0
  230. package/lib/browser/oracles/pythClient.d.ts +31 -0
  231. package/lib/browser/oracles/pythClient.js +32 -1
  232. package/lib/browser/oracles/pythLazerClient.d.ts +34 -0
  233. package/lib/browser/oracles/pythLazerClient.js +35 -1
  234. package/lib/browser/oracles/quoteAssetOracleClient.d.ts +18 -0
  235. package/lib/browser/oracles/quoteAssetOracleClient.js +18 -0
  236. package/lib/browser/oracles/strictOraclePrice.d.ts +21 -0
  237. package/lib/browser/oracles/strictOraclePrice.js +21 -0
  238. package/lib/browser/oracles/types.d.ts +45 -0
  239. package/lib/browser/oracles/utils.d.ts +20 -0
  240. package/lib/browser/oracles/utils.js +20 -0
  241. package/lib/browser/orderParams.d.ts +42 -4
  242. package/lib/browser/orderParams.js +42 -4
  243. package/lib/browser/orderSubscriber/OrderSubscriber.d.ts +56 -0
  244. package/lib/browser/orderSubscriber/OrderSubscriber.js +59 -0
  245. package/lib/browser/orderSubscriber/PollingSubscription.d.ts +11 -0
  246. package/lib/browser/orderSubscriber/PollingSubscription.js +11 -0
  247. package/lib/browser/orderSubscriber/WebsocketSubscription.d.ts +18 -0
  248. package/lib/browser/orderSubscriber/WebsocketSubscription.js +18 -0
  249. package/lib/browser/orderSubscriber/grpcSubscription.d.ts +16 -0
  250. package/lib/browser/orderSubscriber/grpcSubscription.js +16 -0
  251. package/lib/browser/orderSubscriber/types.d.ts +9 -0
  252. package/lib/browser/priorityFee/averageOverSlotsStrategy.d.ts +1 -0
  253. package/lib/browser/priorityFee/averageOverSlotsStrategy.js +1 -0
  254. package/lib/browser/priorityFee/averageStrategy.d.ts +1 -0
  255. package/lib/browser/priorityFee/averageStrategy.js +1 -0
  256. package/lib/browser/priorityFee/ewmaStrategy.d.ts +10 -0
  257. package/lib/browser/priorityFee/ewmaStrategy.js +10 -0
  258. package/lib/browser/priorityFee/heliusPriorityFeeMethod.d.ts +13 -0
  259. package/lib/browser/priorityFee/heliusPriorityFeeMethod.js +9 -2
  260. package/lib/browser/priorityFee/maxOverSlotsStrategy.d.ts +1 -0
  261. package/lib/browser/priorityFee/maxOverSlotsStrategy.js +1 -0
  262. package/lib/browser/priorityFee/maxStrategy.d.ts +1 -0
  263. package/lib/browser/priorityFee/maxStrategy.js +1 -0
  264. package/lib/browser/priorityFee/priorityFeeSubscriber.d.ts +39 -0
  265. package/lib/browser/priorityFee/priorityFeeSubscriber.js +39 -0
  266. package/lib/browser/priorityFee/priorityFeeSubscriberMap.d.ts +20 -1
  267. package/lib/browser/priorityFee/priorityFeeSubscriberMap.js +21 -2
  268. package/lib/browser/priorityFee/solanaPriorityFeeMethod.d.ts +12 -0
  269. package/lib/browser/priorityFee/solanaPriorityFeeMethod.js +10 -0
  270. package/lib/browser/priorityFee/types.d.ts +32 -0
  271. package/lib/browser/priorityFee/types.js +5 -0
  272. package/lib/browser/priorityFee/velocityPriorityFeeMethod.d.ts +11 -0
  273. package/lib/browser/priorityFee/velocityPriorityFeeMethod.js +8 -0
  274. package/lib/browser/pyth/pythLazerSubscriber.js +37 -27
  275. package/lib/browser/slot/SlotSubscriber.d.ts +18 -0
  276. package/lib/browser/slot/SlotSubscriber.js +16 -0
  277. package/lib/browser/slot/SlothashSubscriber.d.ts +26 -0
  278. package/lib/browser/slot/SlothashSubscriber.js +25 -1
  279. package/lib/browser/tx/baseTxSender.d.ts +163 -0
  280. package/lib/browser/tx/baseTxSender.js +174 -6
  281. package/lib/browser/tx/blockhashFetcher/baseBlockhashFetcher.d.ts +12 -0
  282. package/lib/browser/tx/blockhashFetcher/baseBlockhashFetcher.js +12 -0
  283. package/lib/browser/tx/blockhashFetcher/cachedBlockhashFetcher.d.ts +15 -0
  284. package/lib/browser/tx/blockhashFetcher/cachedBlockhashFetcher.js +15 -0
  285. package/lib/browser/tx/blockhashFetcher/types.d.ts +4 -0
  286. package/lib/browser/tx/fastSingleTxSender.d.ts +47 -0
  287. package/lib/browser/tx/fastSingleTxSender.js +48 -1
  288. package/lib/browser/tx/forwardOnlyTxSender.d.ts +48 -0
  289. package/lib/browser/tx/forwardOnlyTxSender.js +48 -0
  290. package/lib/browser/tx/reportTransactionError.d.ts +18 -6
  291. package/lib/browser/tx/reportTransactionError.js +18 -6
  292. package/lib/browser/tx/retryTxSender.d.ts +40 -0
  293. package/lib/browser/tx/retryTxSender.js +39 -0
  294. package/lib/browser/tx/txHandler.d.ts +146 -35
  295. package/lib/browser/tx/txHandler.js +132 -32
  296. package/lib/browser/tx/txParamProcessor.d.ts +47 -0
  297. package/lib/browser/tx/txParamProcessor.js +47 -0
  298. package/lib/browser/tx/types.d.ts +46 -0
  299. package/lib/browser/tx/types.js +5 -0
  300. package/lib/browser/tx/utils.d.ts +26 -0
  301. package/lib/browser/tx/utils.js +26 -0
  302. package/lib/browser/tx/whileValidTxSender.d.ts +82 -0
  303. package/lib/browser/tx/whileValidTxSender.js +81 -0
  304. package/lib/browser/types.d.ts +785 -13
  305. package/lib/browser/types.js +126 -9
  306. package/lib/browser/user.d.ts +660 -84
  307. package/lib/browser/user.js +816 -97
  308. package/lib/browser/userMap/PollingSubscription.d.ts +10 -0
  309. package/lib/browser/userMap/PollingSubscription.js +14 -2
  310. package/lib/browser/userMap/WebsocketSubscription.d.ts +9 -0
  311. package/lib/browser/userMap/WebsocketSubscription.js +9 -0
  312. package/lib/browser/userMap/grpcSubscription.d.ts +8 -0
  313. package/lib/browser/userMap/grpcSubscription.js +8 -0
  314. package/lib/browser/userMap/referrerMap.d.ts +72 -2
  315. package/lib/browser/userMap/referrerMap.js +84 -2
  316. package/lib/browser/userMap/revenueShareEscrowMap.d.ts +37 -10
  317. package/lib/browser/userMap/revenueShareEscrowMap.js +38 -11
  318. package/lib/browser/userMap/userMap.d.ts +81 -3
  319. package/lib/browser/userMap/userMap.js +81 -4
  320. package/lib/browser/userMap/userMapConfig.d.ts +23 -0
  321. package/lib/browser/userMap/userStatsMap.d.ts +22 -0
  322. package/lib/browser/userMap/userStatsMap.js +22 -0
  323. package/lib/browser/userName.d.ts +16 -0
  324. package/lib/browser/userName.js +16 -0
  325. package/lib/browser/userStats.d.ts +28 -1
  326. package/lib/browser/userStats.js +28 -1
  327. package/lib/browser/util/TransactionConfirmationManager.d.ts +33 -0
  328. package/lib/browser/util/TransactionConfirmationManager.js +33 -0
  329. package/lib/browser/util/chainClock.d.ts +24 -0
  330. package/lib/browser/util/chainClock.js +20 -0
  331. package/lib/browser/util/computeUnits.d.ts +32 -0
  332. package/lib/browser/util/computeUnits.js +32 -0
  333. package/lib/browser/util/digest.d.ts +17 -0
  334. package/lib/browser/util/digest.js +17 -0
  335. package/lib/browser/util/ed25519Utils.d.ts +12 -2
  336. package/lib/browser/util/ed25519Utils.js +12 -2
  337. package/lib/browser/util/promiseTimeout.d.ts +9 -0
  338. package/lib/browser/util/promiseTimeout.js +9 -0
  339. package/lib/browser/velocityClient.d.ts +3363 -220
  340. package/lib/browser/velocityClient.js +3514 -275
  341. package/lib/browser/wallet.d.ts +37 -0
  342. package/lib/browser/wallet.js +37 -0
  343. package/lib/node/accounts/basicUserAccountSubscriber.d.ts +18 -0
  344. package/lib/node/accounts/basicUserAccountSubscriber.d.ts.map +1 -1
  345. package/lib/node/accounts/basicUserAccountSubscriber.js +18 -0
  346. package/lib/node/accounts/basicUserStatsAccountSubscriber.d.ts +18 -0
  347. package/lib/node/accounts/basicUserStatsAccountSubscriber.d.ts.map +1 -1
  348. package/lib/node/accounts/basicUserStatsAccountSubscriber.js +18 -0
  349. package/lib/node/accounts/bulkAccountLoader.d.ts +52 -0
  350. package/lib/node/accounts/bulkAccountLoader.d.ts.map +1 -1
  351. package/lib/node/accounts/bulkAccountLoader.js +51 -0
  352. package/lib/node/accounts/bulkUserStatsSubscription.d.ts +9 -2
  353. package/lib/node/accounts/bulkUserStatsSubscription.d.ts.map +1 -1
  354. package/lib/node/accounts/bulkUserStatsSubscription.js +9 -2
  355. package/lib/node/accounts/bulkUserSubscription.d.ts +8 -2
  356. package/lib/node/accounts/bulkUserSubscription.d.ts.map +1 -1
  357. package/lib/node/accounts/bulkUserSubscription.js +8 -2
  358. package/lib/node/accounts/customizedCadenceBulkAccountLoader.d.ts +37 -0
  359. package/lib/node/accounts/customizedCadenceBulkAccountLoader.d.ts.map +1 -1
  360. package/lib/node/accounts/customizedCadenceBulkAccountLoader.js +37 -0
  361. package/lib/node/accounts/fetch.d.ts +59 -2
  362. package/lib/node/accounts/fetch.d.ts.map +1 -1
  363. package/lib/node/accounts/fetch.js +57 -2
  364. package/lib/node/accounts/grpcAccountSubscriber.d.ts +30 -0
  365. package/lib/node/accounts/grpcAccountSubscriber.d.ts.map +1 -1
  366. package/lib/node/accounts/grpcAccountSubscriber.js +30 -0
  367. package/lib/node/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts +16 -0
  368. package/lib/node/accounts/grpcInsuranceFundStakeAccountSubscriber.d.ts.map +1 -1
  369. package/lib/node/accounts/grpcInsuranceFundStakeAccountSubscriber.js +16 -0
  370. package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts +60 -1
  371. package/lib/node/accounts/grpcMultiAccountSubscriber.d.ts.map +1 -1
  372. package/lib/node/accounts/grpcMultiAccountSubscriber.js +118 -37
  373. package/lib/node/accounts/grpcMultiUserAccountSubscriber.d.ts +32 -0
  374. package/lib/node/accounts/grpcMultiUserAccountSubscriber.d.ts.map +1 -1
  375. package/lib/node/accounts/grpcMultiUserAccountSubscriber.js +40 -12
  376. package/lib/node/accounts/grpcProgramAccountSubscriber.d.ts +33 -0
  377. package/lib/node/accounts/grpcProgramAccountSubscriber.d.ts.map +1 -1
  378. package/lib/node/accounts/grpcProgramAccountSubscriber.js +33 -0
  379. package/lib/node/accounts/grpcUserAccountSubscriber.d.ts +15 -0
  380. package/lib/node/accounts/grpcUserAccountSubscriber.d.ts.map +1 -1
  381. package/lib/node/accounts/grpcUserAccountSubscriber.js +15 -0
  382. package/lib/node/accounts/grpcUserStatsAccountSubscriber.d.ts +15 -0
  383. package/lib/node/accounts/grpcUserStatsAccountSubscriber.d.ts.map +1 -1
  384. package/lib/node/accounts/grpcUserStatsAccountSubscriber.js +15 -0
  385. package/lib/node/accounts/grpcVelocityClientAccountSubscriber.d.ts +41 -0
  386. package/lib/node/accounts/grpcVelocityClientAccountSubscriber.d.ts.map +1 -1
  387. package/lib/node/accounts/grpcVelocityClientAccountSubscriber.js +41 -0
  388. package/lib/node/accounts/grpcVelocityClientAccountSubscriberV2.d.ts +116 -0
  389. package/lib/node/accounts/grpcVelocityClientAccountSubscriberV2.d.ts.map +1 -1
  390. package/lib/node/accounts/grpcVelocityClientAccountSubscriberV2.js +152 -1
  391. package/lib/node/accounts/laserProgramAccountSubscriber.d.ts +34 -0
  392. package/lib/node/accounts/laserProgramAccountSubscriber.d.ts.map +1 -1
  393. package/lib/node/accounts/laserProgramAccountSubscriber.js +34 -0
  394. package/lib/node/accounts/oneShotUserAccountSubscriber.d.ts +19 -0
  395. package/lib/node/accounts/oneShotUserAccountSubscriber.d.ts.map +1 -1
  396. package/lib/node/accounts/oneShotUserAccountSubscriber.js +19 -0
  397. package/lib/node/accounts/oneShotUserStatsAccountSubscriber.d.ts +19 -0
  398. package/lib/node/accounts/oneShotUserStatsAccountSubscriber.d.ts.map +1 -1
  399. package/lib/node/accounts/oneShotUserStatsAccountSubscriber.js +19 -0
  400. package/lib/node/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts +31 -0
  401. package/lib/node/accounts/pollingInsuranceFundStakeAccountSubscriber.d.ts.map +1 -1
  402. package/lib/node/accounts/pollingInsuranceFundStakeAccountSubscriber.js +31 -0
  403. package/lib/node/accounts/pollingOracleAccountSubscriber.d.ts +19 -0
  404. package/lib/node/accounts/pollingOracleAccountSubscriber.d.ts.map +1 -1
  405. package/lib/node/accounts/pollingOracleAccountSubscriber.js +21 -2
  406. package/lib/node/accounts/pollingTokenAccountSubscriber.d.ts +22 -0
  407. package/lib/node/accounts/pollingTokenAccountSubscriber.d.ts.map +1 -1
  408. package/lib/node/accounts/pollingTokenAccountSubscriber.js +22 -0
  409. package/lib/node/accounts/pollingUserAccountSubscriber.d.ts +32 -0
  410. package/lib/node/accounts/pollingUserAccountSubscriber.d.ts.map +1 -1
  411. package/lib/node/accounts/pollingUserAccountSubscriber.js +32 -0
  412. package/lib/node/accounts/pollingUserStatsAccountSubscriber.d.ts +22 -0
  413. package/lib/node/accounts/pollingUserStatsAccountSubscriber.d.ts.map +1 -1
  414. package/lib/node/accounts/pollingUserStatsAccountSubscriber.js +22 -0
  415. package/lib/node/accounts/pollingVelocityClientAccountSubscriber.d.ts +83 -0
  416. package/lib/node/accounts/pollingVelocityClientAccountSubscriber.d.ts.map +1 -1
  417. package/lib/node/accounts/pollingVelocityClientAccountSubscriber.js +84 -1
  418. package/lib/node/accounts/testBulkAccountLoader.d.ts +8 -0
  419. package/lib/node/accounts/testBulkAccountLoader.d.ts.map +1 -1
  420. package/lib/node/accounts/testBulkAccountLoader.js +8 -0
  421. package/lib/node/accounts/types.d.ts +149 -0
  422. package/lib/node/accounts/types.d.ts.map +1 -1
  423. package/lib/node/accounts/types.js +13 -0
  424. package/lib/node/accounts/utils.d.ts +18 -0
  425. package/lib/node/accounts/utils.d.ts.map +1 -1
  426. package/lib/node/accounts/utils.js +32 -16
  427. package/lib/node/accounts/webSocketAccountSubscriber.d.ts +41 -0
  428. package/lib/node/accounts/webSocketAccountSubscriber.d.ts.map +1 -1
  429. package/lib/node/accounts/webSocketAccountSubscriber.js +41 -0
  430. package/lib/node/accounts/webSocketAccountSubscriberV2.d.ts +31 -0
  431. package/lib/node/accounts/webSocketAccountSubscriberV2.d.ts.map +1 -1
  432. package/lib/node/accounts/webSocketAccountSubscriberV2.js +31 -23
  433. package/lib/node/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +27 -0
  434. package/lib/node/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts.map +1 -1
  435. package/lib/node/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +27 -0
  436. package/lib/node/accounts/webSocketProgramAccountSubscriber.d.ts +36 -0
  437. package/lib/node/accounts/webSocketProgramAccountSubscriber.d.ts.map +1 -1
  438. package/lib/node/accounts/webSocketProgramAccountSubscriber.js +36 -0
  439. package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts +21 -0
  440. package/lib/node/accounts/webSocketProgramAccountSubscriberV2.d.ts.map +1 -1
  441. package/lib/node/accounts/webSocketProgramAccountSubscriberV2.js +25 -0
  442. package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.d.ts +21 -0
  443. package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.d.ts.map +1 -1
  444. package/lib/node/accounts/webSocketProgramAccountsSubscriberV2.js +21 -0
  445. package/lib/node/accounts/webSocketUserAccountSubscriber.d.ts +26 -0
  446. package/lib/node/accounts/webSocketUserAccountSubscriber.d.ts.map +1 -1
  447. package/lib/node/accounts/webSocketUserAccountSubscriber.js +26 -0
  448. package/lib/node/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
  449. package/lib/node/accounts/webSocketUserStatsAccountSubsriber.d.ts.map +1 -1
  450. package/lib/node/accounts/webSocketUserStatsAccountSubsriber.js +20 -0
  451. package/lib/node/accounts/webSocketVelocityClientAccountSubscriber.d.ts +121 -0
  452. package/lib/node/accounts/webSocketVelocityClientAccountSubscriber.d.ts.map +1 -1
  453. package/lib/node/accounts/webSocketVelocityClientAccountSubscriber.js +123 -2
  454. package/lib/node/accounts/webSocketVelocityClientAccountSubscriberV2.d.ts +96 -0
  455. package/lib/node/accounts/webSocketVelocityClientAccountSubscriberV2.d.ts.map +1 -1
  456. package/lib/node/accounts/webSocketVelocityClientAccountSubscriberV2.js +108 -0
  457. package/lib/node/accounts/websocketProgramUserAccountSubscriber.d.ts +28 -0
  458. package/lib/node/accounts/websocketProgramUserAccountSubscriber.d.ts.map +1 -1
  459. package/lib/node/accounts/websocketProgramUserAccountSubscriber.js +33 -0
  460. package/lib/node/addresses/marketAddresses.d.ts +10 -0
  461. package/lib/node/addresses/marketAddresses.d.ts.map +1 -1
  462. package/lib/node/addresses/marketAddresses.js +10 -0
  463. package/lib/node/addresses/pda.d.ts +214 -2
  464. package/lib/node/addresses/pda.d.ts.map +1 -1
  465. package/lib/node/addresses/pda.js +217 -5
  466. package/lib/node/adminClient.d.ts +2171 -4
  467. package/lib/node/adminClient.d.ts.map +1 -1
  468. package/lib/node/adminClient.js +2215 -4
  469. package/lib/node/auctionSubscriber/auctionSubscriber.d.ts +15 -0
  470. package/lib/node/auctionSubscriber/auctionSubscriber.d.ts.map +1 -1
  471. package/lib/node/auctionSubscriber/auctionSubscriber.js +15 -0
  472. package/lib/node/auctionSubscriber/auctionSubscriberGrpc.d.ts +19 -0
  473. package/lib/node/auctionSubscriber/auctionSubscriberGrpc.d.ts.map +1 -1
  474. package/lib/node/auctionSubscriber/auctionSubscriberGrpc.js +19 -0
  475. package/lib/node/auctionSubscriber/index.d.ts +6 -0
  476. package/lib/node/auctionSubscriber/index.d.ts.map +1 -1
  477. package/lib/node/auctionSubscriber/index.js +6 -0
  478. package/lib/node/auctionSubscriber/types.d.ts +7 -0
  479. package/lib/node/auctionSubscriber/types.d.ts.map +1 -1
  480. package/lib/node/blockhashSubscriber/BlockhashSubscriber.d.ts +33 -0
  481. package/lib/node/blockhashSubscriber/BlockhashSubscriber.d.ts.map +1 -1
  482. package/lib/node/blockhashSubscriber/BlockhashSubscriber.js +33 -0
  483. package/lib/node/blockhashSubscriber/index.d.ts +5 -0
  484. package/lib/node/blockhashSubscriber/index.d.ts.map +1 -1
  485. package/lib/node/blockhashSubscriber/index.js +5 -0
  486. package/lib/node/blockhashSubscriber/types.d.ts +5 -0
  487. package/lib/node/blockhashSubscriber/types.d.ts.map +1 -1
  488. package/lib/node/clock/clockSubscriber.d.ts +24 -0
  489. package/lib/node/clock/clockSubscriber.d.ts.map +1 -1
  490. package/lib/node/clock/clockSubscriber.js +22 -0
  491. package/lib/node/config.d.ts +58 -4
  492. package/lib/node/config.d.ts.map +1 -1
  493. package/lib/node/config.js +94 -28
  494. package/lib/node/constants/numericConstants.d.ts +67 -0
  495. package/lib/node/constants/numericConstants.d.ts.map +1 -1
  496. package/lib/node/constants/numericConstants.js +68 -1
  497. package/lib/node/constants/perpMarkets.d.ts +10 -0
  498. package/lib/node/constants/perpMarkets.d.ts.map +1 -1
  499. package/lib/node/constants/perpMarkets.js +40 -908
  500. package/lib/node/constants/spotMarkets.d.ts +13 -0
  501. package/lib/node/constants/spotMarkets.d.ts.map +1 -1
  502. package/lib/node/constants/spotMarkets.js +16 -742
  503. package/lib/node/constants/txConstants.d.ts +1 -0
  504. package/lib/node/constants/txConstants.d.ts.map +1 -1
  505. package/lib/node/constants/txConstants.js +1 -0
  506. package/lib/node/core/VelocityCore.d.ts +285 -8
  507. package/lib/node/core/VelocityCore.d.ts.map +1 -1
  508. package/lib/node/core/VelocityCore.js +281 -8
  509. package/lib/node/core/instructions/deposit.d.ts +22 -0
  510. package/lib/node/core/instructions/deposit.d.ts.map +1 -1
  511. package/lib/node/core/instructions/deposit.js +22 -0
  512. package/lib/node/core/instructions/fill.d.ts +17 -0
  513. package/lib/node/core/instructions/fill.d.ts.map +1 -1
  514. package/lib/node/core/instructions/fill.js +17 -0
  515. package/lib/node/core/instructions/funding.d.ts +12 -0
  516. package/lib/node/core/instructions/funding.d.ts.map +1 -1
  517. package/lib/node/core/instructions/funding.js +12 -0
  518. package/lib/node/core/instructions/liquidation.d.ts +18 -0
  519. package/lib/node/core/instructions/liquidation.d.ts.map +1 -1
  520. package/lib/node/core/instructions/liquidation.js +18 -0
  521. package/lib/node/core/instructions/orders.d.ts +28 -0
  522. package/lib/node/core/instructions/orders.d.ts.map +1 -1
  523. package/lib/node/core/instructions/orders.js +28 -0
  524. package/lib/node/core/instructions/perpOrders.d.ts +106 -0
  525. package/lib/node/core/instructions/perpOrders.d.ts.map +1 -1
  526. package/lib/node/core/instructions/perpOrders.js +106 -0
  527. package/lib/node/core/instructions/settlement.d.ts +14 -0
  528. package/lib/node/core/instructions/settlement.d.ts.map +1 -1
  529. package/lib/node/core/instructions/settlement.js +14 -0
  530. package/lib/node/core/instructions/trigger.d.ts +15 -0
  531. package/lib/node/core/instructions/trigger.d.ts.map +1 -1
  532. package/lib/node/core/instructions/trigger.js +15 -0
  533. package/lib/node/core/instructions/withdraw.d.ts +21 -0
  534. package/lib/node/core/instructions/withdraw.d.ts.map +1 -1
  535. package/lib/node/core/instructions/withdraw.js +21 -0
  536. package/lib/node/core/remainingAccounts.d.ts +47 -3
  537. package/lib/node/core/remainingAccounts.d.ts.map +1 -1
  538. package/lib/node/core/remainingAccounts.js +20 -0
  539. package/lib/node/core/signedMsg.d.ts +38 -0
  540. package/lib/node/core/signedMsg.d.ts.map +1 -1
  541. package/lib/node/core/signedMsg.js +33 -0
  542. package/lib/node/decode/customCoder.d.ts +39 -3
  543. package/lib/node/decode/customCoder.d.ts.map +1 -1
  544. package/lib/node/decode/customCoder.js +45 -3
  545. package/lib/node/decode/user.d.ts +22 -0
  546. package/lib/node/decode/user.d.ts.map +1 -1
  547. package/lib/node/decode/user.js +27 -1
  548. package/lib/node/dlob/DLOB.d.ts +502 -53
  549. package/lib/node/dlob/DLOB.d.ts.map +1 -1
  550. package/lib/node/dlob/DLOB.js +540 -98
  551. package/lib/node/dlob/DLOBNode.d.ts +86 -4
  552. package/lib/node/dlob/DLOBNode.d.ts.map +1 -1
  553. package/lib/node/dlob/DLOBNode.js +37 -4
  554. package/lib/node/dlob/DLOBSubscriber.d.ts +39 -12
  555. package/lib/node/dlob/DLOBSubscriber.d.ts.map +1 -1
  556. package/lib/node/dlob/DLOBSubscriber.js +42 -12
  557. package/lib/node/dlob/NodeList.d.ts +69 -0
  558. package/lib/node/dlob/NodeList.d.ts.map +1 -1
  559. package/lib/node/dlob/NodeList.js +66 -0
  560. package/lib/node/dlob/orderBookLevels.d.ts +106 -13
  561. package/lib/node/dlob/orderBookLevels.d.ts.map +1 -1
  562. package/lib/node/dlob/orderBookLevels.js +84 -14
  563. package/lib/node/dlob/types.d.ts +15 -0
  564. package/lib/node/dlob/types.d.ts.map +1 -1
  565. package/lib/node/events/eventList.d.ts +14 -0
  566. package/lib/node/events/eventList.d.ts.map +1 -1
  567. package/lib/node/events/eventList.js +14 -0
  568. package/lib/node/events/eventSubscriber.d.ts +87 -10
  569. package/lib/node/events/eventSubscriber.d.ts.map +1 -1
  570. package/lib/node/events/eventSubscriber.js +93 -8
  571. package/lib/node/events/eventsServerLogProvider.d.ts +22 -0
  572. package/lib/node/events/eventsServerLogProvider.d.ts.map +1 -1
  573. package/lib/node/events/eventsServerLogProvider.js +27 -0
  574. package/lib/node/events/fetchLogs.d.ts +31 -0
  575. package/lib/node/events/fetchLogs.d.ts.map +1 -1
  576. package/lib/node/events/fetchLogs.js +46 -1
  577. package/lib/node/events/parse.d.ts +23 -0
  578. package/lib/node/events/parse.d.ts.map +1 -1
  579. package/lib/node/events/parse.js +23 -0
  580. package/lib/node/events/pollingLogProvider.d.ts +24 -0
  581. package/lib/node/events/pollingLogProvider.d.ts.map +1 -1
  582. package/lib/node/events/pollingLogProvider.js +24 -0
  583. package/lib/node/events/sort.d.ts +11 -0
  584. package/lib/node/events/sort.d.ts.map +1 -1
  585. package/lib/node/events/sort.js +12 -0
  586. package/lib/node/events/txEventCache.d.ts +13 -3
  587. package/lib/node/events/txEventCache.d.ts.map +1 -1
  588. package/lib/node/events/txEventCache.js +19 -7
  589. package/lib/node/events/types.d.ts +118 -2
  590. package/lib/node/events/types.d.ts.map +1 -1
  591. package/lib/node/events/types.js +11 -0
  592. package/lib/node/events/webSocketLogProvider.d.ts +23 -0
  593. package/lib/node/events/webSocketLogProvider.d.ts.map +1 -1
  594. package/lib/node/events/webSocketLogProvider.js +28 -0
  595. package/lib/node/factory/oracleClient.js +2 -2
  596. package/lib/node/idl/velocity.d.ts +150 -7
  597. package/lib/node/idl/velocity.d.ts.map +1 -1
  598. package/lib/node/idl/velocity.json +151 -8
  599. package/lib/node/keypair.d.ts +8 -0
  600. package/lib/node/keypair.d.ts.map +1 -1
  601. package/lib/node/keypair.js +8 -0
  602. package/lib/node/marginCalculation.d.ts +134 -2
  603. package/lib/node/marginCalculation.d.ts.map +1 -1
  604. package/lib/node/marginCalculation.js +121 -0
  605. package/lib/node/math/amm.d.ts +348 -29
  606. package/lib/node/math/amm.d.ts.map +1 -1
  607. package/lib/node/math/amm.js +310 -32
  608. package/lib/node/math/auction.d.ts +95 -19
  609. package/lib/node/math/auction.d.ts.map +1 -1
  610. package/lib/node/math/auction.js +118 -28
  611. package/lib/node/math/bankruptcy.d.ts +46 -0
  612. package/lib/node/math/bankruptcy.d.ts.map +1 -1
  613. package/lib/node/math/bankruptcy.js +89 -1
  614. package/lib/node/math/builder.d.ts +64 -8
  615. package/lib/node/math/builder.d.ts.map +1 -1
  616. package/lib/node/math/builder.js +71 -9
  617. package/lib/node/math/conversion.d.ts +21 -0
  618. package/lib/node/math/conversion.d.ts.map +1 -1
  619. package/lib/node/math/conversion.js +21 -0
  620. package/lib/node/math/exchangeStatus.d.ts +91 -0
  621. package/lib/node/math/exchangeStatus.d.ts.map +1 -1
  622. package/lib/node/math/exchangeStatus.js +106 -3
  623. package/lib/node/math/funding.d.ts +57 -20
  624. package/lib/node/math/funding.d.ts.map +1 -1
  625. package/lib/node/math/funding.js +63 -23
  626. package/lib/node/math/insurance.d.ts +62 -0
  627. package/lib/node/math/insurance.d.ts.map +1 -1
  628. package/lib/node/math/insurance.js +62 -0
  629. package/lib/node/math/liquidation.d.ts +127 -11
  630. package/lib/node/math/liquidation.d.ts.map +1 -1
  631. package/lib/node/math/liquidation.js +182 -19
  632. package/lib/node/math/margin.d.ts +79 -13
  633. package/lib/node/math/margin.d.ts.map +1 -1
  634. package/lib/node/math/margin.js +80 -14
  635. package/lib/node/math/market.d.ts +135 -15
  636. package/lib/node/math/market.d.ts.map +1 -1
  637. package/lib/node/math/market.js +145 -17
  638. package/lib/node/math/oracles.d.ts +113 -0
  639. package/lib/node/math/oracles.d.ts.map +1 -1
  640. package/lib/node/math/oracles.js +118 -1
  641. package/lib/node/math/orders.d.ts +115 -10
  642. package/lib/node/math/orders.d.ts.map +1 -1
  643. package/lib/node/math/orders.js +130 -19
  644. package/lib/node/math/position.d.ts +80 -33
  645. package/lib/node/math/position.d.ts.map +1 -1
  646. package/lib/node/math/position.js +80 -33
  647. package/lib/node/math/repeg.d.ts +48 -10
  648. package/lib/node/math/repeg.d.ts.map +1 -1
  649. package/lib/node/math/repeg.js +48 -10
  650. package/lib/node/math/spotBalance.d.ts +200 -5
  651. package/lib/node/math/spotBalance.d.ts.map +1 -1
  652. package/lib/node/math/spotBalance.js +239 -10
  653. package/lib/node/math/spotMarket.d.ts +36 -3
  654. package/lib/node/math/spotMarket.d.ts.map +1 -1
  655. package/lib/node/math/spotMarket.js +36 -3
  656. package/lib/node/math/spotPosition.d.ts +72 -0
  657. package/lib/node/math/spotPosition.d.ts.map +1 -1
  658. package/lib/node/math/spotPosition.js +62 -0
  659. package/lib/node/math/state.d.ts +31 -0
  660. package/lib/node/math/state.d.ts.map +1 -1
  661. package/lib/node/math/state.js +31 -0
  662. package/lib/node/math/superStake.d.ts +126 -2
  663. package/lib/node/math/superStake.d.ts.map +1 -1
  664. package/lib/node/math/superStake.js +123 -3
  665. package/lib/node/math/tiers.d.ts +29 -0
  666. package/lib/node/math/tiers.d.ts.map +1 -1
  667. package/lib/node/math/tiers.js +29 -0
  668. package/lib/node/math/trade.d.ts +102 -51
  669. package/lib/node/math/trade.d.ts.map +1 -1
  670. package/lib/node/math/trade.js +101 -55
  671. package/lib/node/math/utils.d.ts +71 -9
  672. package/lib/node/math/utils.d.ts.map +1 -1
  673. package/lib/node/math/utils.js +71 -9
  674. package/lib/node/memcmp.d.ts +94 -0
  675. package/lib/node/memcmp.d.ts.map +1 -1
  676. package/lib/node/memcmp.js +103 -2
  677. package/lib/node/oracles/oracleClientCache.d.ts +16 -0
  678. package/lib/node/oracles/oracleClientCache.d.ts.map +1 -1
  679. package/lib/node/oracles/oracleClientCache.js +16 -0
  680. package/lib/node/oracles/oracleId.d.ts +31 -0
  681. package/lib/node/oracles/oracleId.d.ts.map +1 -1
  682. package/lib/node/oracles/oracleId.js +39 -8
  683. package/lib/node/oracles/prelaunchOracleClient.d.ts +20 -0
  684. package/lib/node/oracles/prelaunchOracleClient.d.ts.map +1 -1
  685. package/lib/node/oracles/prelaunchOracleClient.js +20 -0
  686. package/lib/node/oracles/pythClient.d.ts +31 -0
  687. package/lib/node/oracles/pythClient.d.ts.map +1 -1
  688. package/lib/node/oracles/pythClient.js +32 -1
  689. package/lib/node/oracles/pythLazerClient.d.ts +34 -0
  690. package/lib/node/oracles/pythLazerClient.d.ts.map +1 -1
  691. package/lib/node/oracles/pythLazerClient.js +35 -1
  692. package/lib/node/oracles/quoteAssetOracleClient.d.ts +18 -0
  693. package/lib/node/oracles/quoteAssetOracleClient.d.ts.map +1 -1
  694. package/lib/node/oracles/quoteAssetOracleClient.js +18 -0
  695. package/lib/node/oracles/strictOraclePrice.d.ts +21 -0
  696. package/lib/node/oracles/strictOraclePrice.d.ts.map +1 -1
  697. package/lib/node/oracles/strictOraclePrice.js +21 -0
  698. package/lib/node/oracles/types.d.ts +45 -0
  699. package/lib/node/oracles/types.d.ts.map +1 -1
  700. package/lib/node/oracles/utils.d.ts +20 -0
  701. package/lib/node/oracles/utils.d.ts.map +1 -1
  702. package/lib/node/oracles/utils.js +20 -0
  703. package/lib/node/orderParams.d.ts +42 -4
  704. package/lib/node/orderParams.d.ts.map +1 -1
  705. package/lib/node/orderParams.js +42 -4
  706. package/lib/node/orderSubscriber/OrderSubscriber.d.ts +56 -0
  707. package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -1
  708. package/lib/node/orderSubscriber/OrderSubscriber.js +59 -0
  709. package/lib/node/orderSubscriber/PollingSubscription.d.ts +11 -0
  710. package/lib/node/orderSubscriber/PollingSubscription.d.ts.map +1 -1
  711. package/lib/node/orderSubscriber/PollingSubscription.js +11 -0
  712. package/lib/node/orderSubscriber/WebsocketSubscription.d.ts +18 -0
  713. package/lib/node/orderSubscriber/WebsocketSubscription.d.ts.map +1 -1
  714. package/lib/node/orderSubscriber/WebsocketSubscription.js +18 -0
  715. package/lib/node/orderSubscriber/grpcSubscription.d.ts +16 -0
  716. package/lib/node/orderSubscriber/grpcSubscription.d.ts.map +1 -1
  717. package/lib/node/orderSubscriber/grpcSubscription.js +16 -0
  718. package/lib/node/orderSubscriber/types.d.ts +9 -0
  719. package/lib/node/orderSubscriber/types.d.ts.map +1 -1
  720. package/lib/node/priorityFee/averageOverSlotsStrategy.d.ts +1 -0
  721. package/lib/node/priorityFee/averageOverSlotsStrategy.d.ts.map +1 -1
  722. package/lib/node/priorityFee/averageOverSlotsStrategy.js +1 -0
  723. package/lib/node/priorityFee/averageStrategy.d.ts +1 -0
  724. package/lib/node/priorityFee/averageStrategy.d.ts.map +1 -1
  725. package/lib/node/priorityFee/averageStrategy.js +1 -0
  726. package/lib/node/priorityFee/ewmaStrategy.d.ts +10 -0
  727. package/lib/node/priorityFee/ewmaStrategy.d.ts.map +1 -1
  728. package/lib/node/priorityFee/ewmaStrategy.js +10 -0
  729. package/lib/node/priorityFee/heliusPriorityFeeMethod.d.ts +13 -0
  730. package/lib/node/priorityFee/heliusPriorityFeeMethod.d.ts.map +1 -1
  731. package/lib/node/priorityFee/heliusPriorityFeeMethod.js +9 -2
  732. package/lib/node/priorityFee/maxOverSlotsStrategy.d.ts +1 -0
  733. package/lib/node/priorityFee/maxOverSlotsStrategy.d.ts.map +1 -1
  734. package/lib/node/priorityFee/maxOverSlotsStrategy.js +1 -0
  735. package/lib/node/priorityFee/maxStrategy.d.ts +1 -0
  736. package/lib/node/priorityFee/maxStrategy.d.ts.map +1 -1
  737. package/lib/node/priorityFee/maxStrategy.js +1 -0
  738. package/lib/node/priorityFee/priorityFeeSubscriber.d.ts +39 -0
  739. package/lib/node/priorityFee/priorityFeeSubscriber.d.ts.map +1 -1
  740. package/lib/node/priorityFee/priorityFeeSubscriber.js +39 -0
  741. package/lib/node/priorityFee/priorityFeeSubscriberMap.d.ts +20 -1
  742. package/lib/node/priorityFee/priorityFeeSubscriberMap.d.ts.map +1 -1
  743. package/lib/node/priorityFee/priorityFeeSubscriberMap.js +21 -2
  744. package/lib/node/priorityFee/solanaPriorityFeeMethod.d.ts +12 -0
  745. package/lib/node/priorityFee/solanaPriorityFeeMethod.d.ts.map +1 -1
  746. package/lib/node/priorityFee/solanaPriorityFeeMethod.js +10 -0
  747. package/lib/node/priorityFee/types.d.ts +32 -0
  748. package/lib/node/priorityFee/types.d.ts.map +1 -1
  749. package/lib/node/priorityFee/types.js +5 -0
  750. package/lib/node/priorityFee/velocityPriorityFeeMethod.d.ts +11 -0
  751. package/lib/node/priorityFee/velocityPriorityFeeMethod.d.ts.map +1 -1
  752. package/lib/node/priorityFee/velocityPriorityFeeMethod.js +8 -0
  753. package/lib/node/pyth/pythLazerSubscriber.d.ts.map +1 -1
  754. package/lib/node/pyth/pythLazerSubscriber.js +37 -27
  755. package/lib/node/slot/SlotSubscriber.d.ts +18 -0
  756. package/lib/node/slot/SlotSubscriber.d.ts.map +1 -1
  757. package/lib/node/slot/SlotSubscriber.js +16 -0
  758. package/lib/node/slot/SlothashSubscriber.d.ts +26 -0
  759. package/lib/node/slot/SlothashSubscriber.d.ts.map +1 -1
  760. package/lib/node/slot/SlothashSubscriber.js +25 -1
  761. package/lib/node/tx/baseTxSender.d.ts +163 -0
  762. package/lib/node/tx/baseTxSender.d.ts.map +1 -1
  763. package/lib/node/tx/baseTxSender.js +174 -6
  764. package/lib/node/tx/blockhashFetcher/baseBlockhashFetcher.d.ts +12 -0
  765. package/lib/node/tx/blockhashFetcher/baseBlockhashFetcher.d.ts.map +1 -1
  766. package/lib/node/tx/blockhashFetcher/baseBlockhashFetcher.js +12 -0
  767. package/lib/node/tx/blockhashFetcher/cachedBlockhashFetcher.d.ts +15 -0
  768. package/lib/node/tx/blockhashFetcher/cachedBlockhashFetcher.d.ts.map +1 -1
  769. package/lib/node/tx/blockhashFetcher/cachedBlockhashFetcher.js +15 -0
  770. package/lib/node/tx/blockhashFetcher/types.d.ts +4 -0
  771. package/lib/node/tx/blockhashFetcher/types.d.ts.map +1 -1
  772. package/lib/node/tx/fastSingleTxSender.d.ts +47 -0
  773. package/lib/node/tx/fastSingleTxSender.d.ts.map +1 -1
  774. package/lib/node/tx/fastSingleTxSender.js +48 -1
  775. package/lib/node/tx/forwardOnlyTxSender.d.ts +48 -0
  776. package/lib/node/tx/forwardOnlyTxSender.d.ts.map +1 -1
  777. package/lib/node/tx/forwardOnlyTxSender.js +48 -0
  778. package/lib/node/tx/reportTransactionError.d.ts +18 -6
  779. package/lib/node/tx/reportTransactionError.d.ts.map +1 -1
  780. package/lib/node/tx/reportTransactionError.js +18 -6
  781. package/lib/node/tx/retryTxSender.d.ts +40 -0
  782. package/lib/node/tx/retryTxSender.d.ts.map +1 -1
  783. package/lib/node/tx/retryTxSender.js +39 -0
  784. package/lib/node/tx/txHandler.d.ts +146 -35
  785. package/lib/node/tx/txHandler.d.ts.map +1 -1
  786. package/lib/node/tx/txHandler.js +132 -32
  787. package/lib/node/tx/txParamProcessor.d.ts +47 -0
  788. package/lib/node/tx/txParamProcessor.d.ts.map +1 -1
  789. package/lib/node/tx/txParamProcessor.js +47 -0
  790. package/lib/node/tx/types.d.ts +46 -0
  791. package/lib/node/tx/types.d.ts.map +1 -1
  792. package/lib/node/tx/types.js +5 -0
  793. package/lib/node/tx/utils.d.ts +26 -0
  794. package/lib/node/tx/utils.d.ts.map +1 -1
  795. package/lib/node/tx/utils.js +26 -0
  796. package/lib/node/tx/whileValidTxSender.d.ts +82 -0
  797. package/lib/node/tx/whileValidTxSender.d.ts.map +1 -1
  798. package/lib/node/tx/whileValidTxSender.js +81 -0
  799. package/lib/node/types.d.ts +785 -13
  800. package/lib/node/types.d.ts.map +1 -1
  801. package/lib/node/types.js +126 -9
  802. package/lib/node/user.d.ts +660 -84
  803. package/lib/node/user.d.ts.map +1 -1
  804. package/lib/node/user.js +816 -97
  805. package/lib/node/userMap/PollingSubscription.d.ts +10 -0
  806. package/lib/node/userMap/PollingSubscription.d.ts.map +1 -1
  807. package/lib/node/userMap/PollingSubscription.js +14 -2
  808. package/lib/node/userMap/WebsocketSubscription.d.ts +9 -0
  809. package/lib/node/userMap/WebsocketSubscription.d.ts.map +1 -1
  810. package/lib/node/userMap/WebsocketSubscription.js +9 -0
  811. package/lib/node/userMap/grpcSubscription.d.ts +8 -0
  812. package/lib/node/userMap/grpcSubscription.d.ts.map +1 -1
  813. package/lib/node/userMap/grpcSubscription.js +8 -0
  814. package/lib/node/userMap/referrerMap.d.ts +72 -2
  815. package/lib/node/userMap/referrerMap.d.ts.map +1 -1
  816. package/lib/node/userMap/referrerMap.js +84 -2
  817. package/lib/node/userMap/revenueShareEscrowMap.d.ts +37 -10
  818. package/lib/node/userMap/revenueShareEscrowMap.d.ts.map +1 -1
  819. package/lib/node/userMap/revenueShareEscrowMap.js +38 -11
  820. package/lib/node/userMap/userMap.d.ts +81 -3
  821. package/lib/node/userMap/userMap.d.ts.map +1 -1
  822. package/lib/node/userMap/userMap.js +81 -4
  823. package/lib/node/userMap/userMapConfig.d.ts +23 -0
  824. package/lib/node/userMap/userMapConfig.d.ts.map +1 -1
  825. package/lib/node/userMap/userStatsMap.d.ts +22 -0
  826. package/lib/node/userMap/userStatsMap.d.ts.map +1 -1
  827. package/lib/node/userMap/userStatsMap.js +22 -0
  828. package/lib/node/userName.d.ts +16 -0
  829. package/lib/node/userName.d.ts.map +1 -1
  830. package/lib/node/userName.js +16 -0
  831. package/lib/node/userStats.d.ts +28 -1
  832. package/lib/node/userStats.d.ts.map +1 -1
  833. package/lib/node/userStats.js +28 -1
  834. package/lib/node/util/TransactionConfirmationManager.d.ts +33 -0
  835. package/lib/node/util/TransactionConfirmationManager.d.ts.map +1 -1
  836. package/lib/node/util/TransactionConfirmationManager.js +33 -0
  837. package/lib/node/util/chainClock.d.ts +24 -0
  838. package/lib/node/util/chainClock.d.ts.map +1 -1
  839. package/lib/node/util/chainClock.js +20 -0
  840. package/lib/node/util/computeUnits.d.ts +32 -0
  841. package/lib/node/util/computeUnits.d.ts.map +1 -1
  842. package/lib/node/util/computeUnits.js +32 -0
  843. package/lib/node/util/digest.d.ts +17 -0
  844. package/lib/node/util/digest.d.ts.map +1 -1
  845. package/lib/node/util/digest.js +17 -0
  846. package/lib/node/util/ed25519Utils.d.ts +12 -2
  847. package/lib/node/util/ed25519Utils.d.ts.map +1 -1
  848. package/lib/node/util/ed25519Utils.js +12 -2
  849. package/lib/node/util/promiseTimeout.d.ts +9 -0
  850. package/lib/node/util/promiseTimeout.d.ts.map +1 -1
  851. package/lib/node/util/promiseTimeout.js +9 -0
  852. package/lib/node/velocityClient.d.ts +3363 -220
  853. package/lib/node/velocityClient.d.ts.map +1 -1
  854. package/lib/node/velocityClient.js +3514 -275
  855. package/lib/node/wallet.d.ts +37 -0
  856. package/lib/node/wallet.d.ts.map +1 -1
  857. package/lib/node/wallet.js +37 -0
  858. package/package.json +8 -3
  859. package/.prettierignore +0 -1
  860. package/CHANGELOG.md +0 -81
  861. package/build-browser.js +0 -58
  862. package/bunfig.toml +0 -3
  863. package/esbuild-shims.js +0 -12
  864. package/scripts/deposit-isolated-positions.ts +0 -110
  865. package/scripts/find-flagged-users.ts +0 -213
  866. package/scripts/grpc-client-test-comparison.ts +0 -372
  867. package/scripts/grpc-multiuser-client-test-comparison.ts +0 -158
  868. package/scripts/postbuild.js +0 -95
  869. package/scripts/single-grpc-client-test.ts +0 -284
  870. package/scripts/withdraw-isolated-positions.ts +0 -174
  871. package/src/accounts/README_WebSocketAccountSubscriberV2.md +0 -95
  872. package/src/accounts/README_WebSocketProgramAccountSubscriberV2.md +0 -135
  873. package/src/accounts/basicUserAccountSubscriber.ts +0 -61
  874. package/src/accounts/basicUserStatsAccountSubscriber.ts +0 -69
  875. package/src/accounts/bulkAccountLoader.ts +0 -306
  876. package/src/accounts/bulkUserStatsSubscription.ts +0 -33
  877. package/src/accounts/bulkUserSubscription.ts +0 -33
  878. package/src/accounts/customizedCadenceBulkAccountLoader.ts +0 -213
  879. package/src/accounts/fetch.ts +0 -143
  880. package/src/accounts/grpcAccountSubscriber.ts +0 -195
  881. package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +0 -57
  882. package/src/accounts/grpcMultiAccountSubscriber.ts +0 -483
  883. package/src/accounts/grpcMultiUserAccountSubscriber.ts +0 -290
  884. package/src/accounts/grpcProgramAccountSubscriber.ts +0 -231
  885. package/src/accounts/grpcUserAccountSubscriber.ts +0 -48
  886. package/src/accounts/grpcUserStatsAccountSubscriber.ts +0 -50
  887. package/src/accounts/grpcVelocityClientAccountSubscriber.ts +0 -216
  888. package/src/accounts/grpcVelocityClientAccountSubscriberV2.ts +0 -782
  889. package/src/accounts/laserProgramAccountSubscriber.ts +0 -232
  890. package/src/accounts/oneShotUserAccountSubscriber.ts +0 -69
  891. package/src/accounts/oneShotUserStatsAccountSubscriber.ts +0 -75
  892. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -192
  893. package/src/accounts/pollingOracleAccountSubscriber.ts +0 -132
  894. package/src/accounts/pollingTokenAccountSubscriber.ts +0 -125
  895. package/src/accounts/pollingUserAccountSubscriber.ts +0 -166
  896. package/src/accounts/pollingUserStatsAccountSubscriber.ts +0 -158
  897. package/src/accounts/pollingVelocityClientAccountSubscriber.ts +0 -691
  898. package/src/accounts/testBulkAccountLoader.ts +0 -51
  899. package/src/accounts/types.ts +0 -279
  900. package/src/accounts/utils.ts +0 -72
  901. package/src/accounts/webSocketAccountSubscriber.ts +0 -263
  902. package/src/accounts/webSocketAccountSubscriberV2.ts +0 -528
  903. package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +0 -144
  904. package/src/accounts/webSocketProgramAccountSubscriber.ts +0 -208
  905. package/src/accounts/webSocketProgramAccountSubscriberV2.ts +0 -1022
  906. package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +0 -1021
  907. package/src/accounts/webSocketUserAccountSubscriber.ts +0 -113
  908. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +0 -111
  909. package/src/accounts/webSocketVelocityClientAccountSubscriber.ts +0 -740
  910. package/src/accounts/webSocketVelocityClientAccountSubscriberV2.ts +0 -787
  911. package/src/accounts/websocketProgramUserAccountSubscriber.ts +0 -94
  912. package/src/addresses/marketAddresses.ts +0 -18
  913. package/src/addresses/pda.ts +0 -404
  914. package/src/adminClient.ts +0 -5984
  915. package/src/assert/assert.ts +0 -5
  916. package/src/auctionSubscriber/auctionSubscriber.ts +0 -71
  917. package/src/auctionSubscriber/auctionSubscriberGrpc.ts +0 -80
  918. package/src/auctionSubscriber/index.ts +0 -3
  919. package/src/auctionSubscriber/types.ts +0 -23
  920. package/src/bankrun/bankrunConnection.ts +0 -630
  921. package/src/blockhashSubscriber/BlockhashSubscriber.ts +0 -127
  922. package/src/blockhashSubscriber/index.ts +0 -1
  923. package/src/blockhashSubscriber/types.ts +0 -12
  924. package/src/clock/clockSubscriber.ts +0 -122
  925. package/src/config.ts +0 -225
  926. package/src/constants/index.ts +0 -9
  927. package/src/constants/numericConstants.ts +0 -124
  928. package/src/constants/perpMarkets.ts +0 -1042
  929. package/src/constants/spotMarkets.ts +0 -874
  930. package/src/constants/txConstants.ts +0 -1
  931. package/src/constituentMap/constituentMap.ts +0 -305
  932. package/src/constituentMap/pollingConstituentAccountSubscriber.ts +0 -99
  933. package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +0 -121
  934. package/src/core/VelocityCore.ts +0 -328
  935. package/src/core/index.ts +0 -12
  936. package/src/core/instructions/deposit.ts +0 -42
  937. package/src/core/instructions/fill.ts +0 -34
  938. package/src/core/instructions/funding.ts +0 -21
  939. package/src/core/instructions/liquidation.ts +0 -37
  940. package/src/core/instructions/orders.ts +0 -56
  941. package/src/core/instructions/perpOrders.ts +0 -206
  942. package/src/core/instructions/settlement.ts +0 -26
  943. package/src/core/instructions/trigger.ts +0 -26
  944. package/src/core/instructions/withdraw.ts +0 -44
  945. package/src/core/remainingAccounts.ts +0 -276
  946. package/src/core/signedMsg.ts +0 -71
  947. package/src/decode/customCoder.ts +0 -105
  948. package/src/decode/user.ts +0 -379
  949. package/src/dlob/DLOB.ts +0 -2222
  950. package/src/dlob/DLOBNode.ts +0 -213
  951. package/src/dlob/DLOBSubscriber.ts +0 -232
  952. package/src/dlob/NodeList.ts +0 -175
  953. package/src/dlob/orderBookLevels.ts +0 -601
  954. package/src/dlob/types.ts +0 -22
  955. package/src/events/eventList.ts +0 -100
  956. package/src/events/eventSubscriber.ts +0 -440
  957. package/src/events/eventsServerLogProvider.ts +0 -161
  958. package/src/events/fetchLogs.ts +0 -169
  959. package/src/events/parse.ts +0 -248
  960. package/src/events/pollingLogProvider.ts +0 -89
  961. package/src/events/sort.ts +0 -39
  962. package/src/events/txEventCache.ts +0 -80
  963. package/src/events/types.ts +0 -217
  964. package/src/events/webSocketLogProvider.ts +0 -123
  965. package/src/factory/bigNum.ts +0 -709
  966. package/src/factory/oracleClient.ts +0 -73
  967. package/src/idl/pyth.json +0 -142
  968. package/src/idl/pyth.ts +0 -97
  969. package/src/idl/pyth_solana_receiver.json +0 -628
  970. package/src/idl/token_faucet.json +0 -229
  971. package/src/idl/token_faucet.ts +0 -197
  972. package/src/idl/velocity.json +0 -23974
  973. package/src/idl/velocity.ts +0 -23980
  974. package/src/index.ts +0 -150
  975. package/src/indicative-quotes/indicativeQuotesSender.ts +0 -233
  976. package/src/isomorphic/README.md +0 -19
  977. package/src/isomorphic/anchor.browser.ts +0 -44
  978. package/src/isomorphic/anchor.node.ts +0 -1
  979. package/src/isomorphic/anchor.ts +0 -1
  980. package/src/isomorphic/anchor29.browser.ts +0 -24
  981. package/src/isomorphic/anchor29.node.ts +0 -1
  982. package/src/isomorphic/anchor29.ts +0 -1
  983. package/src/isomorphic/grpc.browser.ts +0 -4
  984. package/src/isomorphic/grpc.node.ts +0 -130
  985. package/src/isomorphic/grpc.ts +0 -1
  986. package/src/jupiter/jupiterClient.ts +0 -502
  987. package/src/keypair.ts +0 -24
  988. package/src/margin/README.md +0 -138
  989. package/src/marginCalculation.ts +0 -256
  990. package/src/marinade/idl/idl.json +0 -1962
  991. package/src/marinade/index.ts +0 -73
  992. package/src/marinade/types.ts +0 -3925
  993. package/src/math/amm.ts +0 -1423
  994. package/src/math/auction.ts +0 -371
  995. package/src/math/bankruptcy.ts +0 -35
  996. package/src/math/builder.ts +0 -64
  997. package/src/math/conversion.ts +0 -24
  998. package/src/math/exchangeStatus.ts +0 -146
  999. package/src/math/funding.ts +0 -458
  1000. package/src/math/insurance.ts +0 -109
  1001. package/src/math/liquidation.ts +0 -223
  1002. package/src/math/margin.ts +0 -261
  1003. package/src/math/market.ts +0 -356
  1004. package/src/math/oracles.ts +0 -353
  1005. package/src/math/orders.ts +0 -378
  1006. package/src/math/position.ts +0 -334
  1007. package/src/math/repeg.ts +0 -185
  1008. package/src/math/spotBalance.ts +0 -756
  1009. package/src/math/spotMarket.ts +0 -82
  1010. package/src/math/spotPosition.ts +0 -191
  1011. package/src/math/state.ts +0 -40
  1012. package/src/math/superStake.ts +0 -479
  1013. package/src/math/tiers.ts +0 -44
  1014. package/src/math/trade.ts +0 -809
  1015. package/src/math/utils.ts +0 -121
  1016. package/src/memcmp.ts +0 -177
  1017. package/src/oracles/oracleClientCache.ts +0 -25
  1018. package/src/oracles/oracleId.ts +0 -66
  1019. package/src/oracles/prelaunchOracleClient.ts +0 -43
  1020. package/src/oracles/pythClient.ts +0 -94
  1021. package/src/oracles/pythLazerClient.ts +0 -107
  1022. package/src/oracles/quoteAssetOracleClient.ts +0 -25
  1023. package/src/oracles/strictOraclePrice.ts +0 -19
  1024. package/src/oracles/types.ts +0 -37
  1025. package/src/oracles/utils.ts +0 -25
  1026. package/src/orderParams.ts +0 -79
  1027. package/src/orderSubscriber/OrderSubscriber.ts +0 -322
  1028. package/src/orderSubscriber/PollingSubscription.ts +0 -39
  1029. package/src/orderSubscriber/WebsocketSubscription.ts +0 -119
  1030. package/src/orderSubscriber/grpcSubscription.ts +0 -139
  1031. package/src/orderSubscriber/index.ts +0 -7
  1032. package/src/orderSubscriber/types.ts +0 -55
  1033. package/src/priorityFee/averageOverSlotsStrategy.ts +0 -16
  1034. package/src/priorityFee/averageStrategy.ts +0 -12
  1035. package/src/priorityFee/ewmaStrategy.ts +0 -41
  1036. package/src/priorityFee/heliusPriorityFeeMethod.ts +0 -57
  1037. package/src/priorityFee/index.ts +0 -16
  1038. package/src/priorityFee/maxOverSlotsStrategy.ts +0 -17
  1039. package/src/priorityFee/maxStrategy.ts +0 -7
  1040. package/src/priorityFee/priorityFeeSubscriber.ts +0 -289
  1041. package/src/priorityFee/priorityFeeSubscriberMap.ts +0 -115
  1042. package/src/priorityFee/solanaPriorityFeeMethod.ts +0 -34
  1043. package/src/priorityFee/types.ts +0 -64
  1044. package/src/priorityFee/velocityPriorityFeeMethod.ts +0 -42
  1045. package/src/pyth/constants.ts +0 -9
  1046. package/src/pyth/index.ts +0 -15
  1047. package/src/pyth/pythLazerSubscriber.ts +0 -365
  1048. package/src/pyth/types.ts +0 -4451
  1049. package/src/pyth/utils.ts +0 -13
  1050. package/src/slot/SlotSubscriber.ts +0 -108
  1051. package/src/slot/SlothashSubscriber.ts +0 -137
  1052. package/src/swap/UnifiedSwapClient.ts +0 -315
  1053. package/src/swift/grpcSignedMsgUserAccountSubscriber.ts +0 -81
  1054. package/src/swift/index.ts +0 -10
  1055. package/src/swift/signedMsgUserAccountSubscriber.ts +0 -251
  1056. package/src/swift/swiftOrderSubscriber.ts +0 -351
  1057. package/src/testClient.ts +0 -42
  1058. package/src/titan/titanClient.ts +0 -438
  1059. package/src/token/index.ts +0 -13
  1060. package/src/tokenFaucet.ts +0 -296
  1061. package/src/tx/baseTxSender.ts +0 -471
  1062. package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +0 -19
  1063. package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +0 -90
  1064. package/src/tx/blockhashFetcher/types.ts +0 -5
  1065. package/src/tx/fastSingleTxSender.ts +0 -146
  1066. package/src/tx/forwardOnlyTxSender.ts +0 -145
  1067. package/src/tx/priorityFeeCalculator.ts +0 -117
  1068. package/src/tx/reportTransactionError.ts +0 -164
  1069. package/src/tx/retryTxSender.ts +0 -137
  1070. package/src/tx/txHandler.ts +0 -898
  1071. package/src/tx/txParamProcessor.ts +0 -178
  1072. package/src/tx/types.ts +0 -71
  1073. package/src/tx/utils.ts +0 -107
  1074. package/src/tx/whileValidTxSender.ts +0 -295
  1075. package/src/types.ts +0 -1822
  1076. package/src/user.ts +0 -4557
  1077. package/src/userConfig.ts +0 -38
  1078. package/src/userMap/PollingSubscription.ts +0 -47
  1079. package/src/userMap/WebsocketSubscription.ts +0 -84
  1080. package/src/userMap/grpcSubscription.ts +0 -85
  1081. package/src/userMap/referrerMap.ts +0 -271
  1082. package/src/userMap/revenueShareEscrowMap.ts +0 -315
  1083. package/src/userMap/userMap.ts +0 -706
  1084. package/src/userMap/userMapConfig.ts +0 -69
  1085. package/src/userMap/userStatsMap.ts +0 -371
  1086. package/src/userName.ts +0 -21
  1087. package/src/userStats.ts +0 -132
  1088. package/src/userStatsConfig.ts +0 -35
  1089. package/src/util/TransactionConfirmationManager.ts +0 -300
  1090. package/src/util/chainClock.ts +0 -41
  1091. package/src/util/computeUnits.ts +0 -69
  1092. package/src/util/digest.ts +0 -16
  1093. package/src/util/ed25519Utils.ts +0 -85
  1094. package/src/util/promiseTimeout.ts +0 -14
  1095. package/src/velocityClient.ts +0 -11612
  1096. package/src/velocityClientConfig.ts +0 -119
  1097. package/src/wallet.ts +0 -54
  1098. package/tests/VelocityCore/decode.test.ts +0 -16
  1099. package/tests/VelocityCore/fill_trigger.test.ts +0 -73
  1100. package/tests/VelocityCore/instructions.test.ts +0 -46
  1101. package/tests/VelocityCore/pdas.test.ts +0 -30
  1102. package/tests/VelocityCore/perp_orders.test.ts +0 -205
  1103. package/tests/VelocityCore/remainingAccounts.test.ts +0 -72
  1104. package/tests/VelocityCore/settlement_liquidation.test.ts +0 -69
  1105. package/tests/accounts/customizedCadenceBulkAccountLoader.test.ts +0 -211
  1106. package/tests/amm/test.ts +0 -2300
  1107. package/tests/auctions/test.ts +0 -81
  1108. package/tests/bn/test.ts +0 -355
  1109. package/tests/ci/verifyConstants.ts +0 -393
  1110. package/tests/decode/test.ts +0 -262
  1111. package/tests/decode/userAccountBufferStrings.ts +0 -102
  1112. package/tests/dlob/helpers.ts +0 -748
  1113. package/tests/dlob/test.ts +0 -6969
  1114. package/tests/events/parseLogsForCuUsage.ts +0 -139
  1115. package/tests/insurance/test.ts +0 -40
  1116. package/tests/spot/test.ts +0 -226
  1117. package/tests/tx/TransactionConfirmationManager.test.ts +0 -312
  1118. package/tests/tx/cachedBlockhashFetcher.test.ts +0 -96
  1119. package/tests/tx/priorityFeeCalculator.ts +0 -77
  1120. package/tests/tx/priorityFeeStrategy.ts +0 -95
  1121. package/tests/user/getMarginCalculation.ts +0 -361
  1122. package/tests/user/helpers.ts +0 -184
  1123. package/tests/user/liquidations.ts +0 -129
  1124. package/tests/user/marginCalculations.test.ts +0 -321
  1125. package/tests/user/test.ts +0 -829
  1126. package/tsconfig.browser.json +0 -18
  1127. package/tsconfig.json +0 -36
package/src/user.ts DELETED
@@ -1,4557 +0,0 @@
1
- /**
2
- * User — read-oriented abstraction over the on-chain `User` account.
3
- *
4
- * Responsibilities:
5
- * - Margin and free-collateral calculations (mirrors `programs/velocity/src/math/margin.rs`).
6
- * - Position accessors: perp positions, spot positions, unrealized PnL, leverage.
7
- * - Open order queries and filtering.
8
- * - Health factor and liquidation threshold checks.
9
- * - Subscribes to and caches the latest `User` account state from chain.
10
- *
11
- * To send instructions (deposit, place order, etc.) use {@link VelocityClient}.
12
- * For referral/volume stats see {@link UserStats} (userStats.ts).
13
- */
14
- import { PublicKey } from '@solana/web3.js';
15
- import { EventEmitter } from 'events';
16
- import StrictEventEmitter from 'strict-event-emitter-types';
17
- import { VelocityClient } from './velocityClient';
18
- import {
19
- HealthComponent,
20
- HealthComponents,
21
- isVariant,
22
- MarginCategory,
23
- Order,
24
- PerpMarketAccount,
25
- PerpPosition,
26
- ReferrerStatus,
27
- SpotPosition,
28
- UserAccount,
29
- UserStatus,
30
- UserStatsAccount,
31
- AccountLiquidatableStatus,
32
- } from './types';
33
- import {
34
- calculateEntryPrice,
35
- calculateUnsettledFundingPnl,
36
- positionIsAvailable,
37
- } from './math/position';
38
- import {
39
- AMM_TO_QUOTE_PRECISION_RATIO,
40
- BASE_PRECISION,
41
- BN_MAX,
42
- DUST_POSITION_SIZE,
43
- FIVE_MINUTE,
44
- MARGIN_PRECISION,
45
- OPEN_ORDER_MARGIN_REQUIREMENT,
46
- PRICE_PRECISION,
47
- QUOTE_PRECISION,
48
- QUOTE_PRECISION_EXP,
49
- QUOTE_SPOT_MARKET_INDEX,
50
- SPOT_MARKET_WEIGHT_PRECISION,
51
- TEN_THOUSAND,
52
- TWO,
53
- ZERO,
54
- ACCOUNT_AGE_DELETION_CUTOFF_SECONDS,
55
- } from './constants/numericConstants';
56
- import {
57
- DataAndSlot,
58
- UserAccountEvents,
59
- UserAccountSubscriber,
60
- } from './accounts/types';
61
- import { assertDataAndSlot } from './accounts/utils';
62
- import { BigNum } from './factory/bigNum';
63
- import { BN } from './isomorphic/anchor';
64
- import { calculateBaseAssetValue, calculatePositionPNL } from './math/position';
65
- import {
66
- calculateMarketMarginRatio,
67
- calculateReservePrice,
68
- calculateUnrealizedAssetWeight,
69
- } from './math/market';
70
- import {
71
- calculatePerpLiabilityValue,
72
- calculateWorstCasePerpLiabilityValue,
73
- } from './math/margin';
74
- import { calculateSpotMarketMarginRatio } from './math/spotMarket';
75
- import { divCeil, sigNum } from './math/utils';
76
- import {
77
- getBalance,
78
- getSignedTokenAmount,
79
- getStrictTokenValue,
80
- getTokenValue,
81
- } from './math/spotBalance';
82
- import { getUser30dRollingVolumeEstimate } from './math/trade';
83
- import {
84
- MarketType,
85
- PositionDirection,
86
- PositionFlag,
87
- SpotBalanceType,
88
- SpotMarketAccount,
89
- } from './types';
90
- import { standardizeBaseAssetAmount } from './math/orders';
91
- import { WebSocketProgramUserAccountSubscriber } from './accounts/websocketProgramUserAccountSubscriber';
92
- import {
93
- calculateAssetWeight,
94
- calculateLiabilityWeight,
95
- calculateWithdrawLimit,
96
- getSpotAssetValue,
97
- getSpotLiabilityValue,
98
- getTokenAmount,
99
- } from './math/spotBalance';
100
- import {
101
- calculateBaseAssetValueWithOracle,
102
- calculateCollateralDepositRequiredForTrade,
103
- calculateMarginUSDCRequiredForTrade,
104
- calculateWorstCaseBaseAssetAmount,
105
- } from './math/margin';
106
- import { MMOraclePriceData, OraclePriceData } from './oracles/types';
107
- import { UserConfig } from './userConfig';
108
- import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
109
- import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
110
- import {
111
- calculateWeightedTokenValue,
112
- getWorstCaseTokenAmounts,
113
- isSpotPositionAvailable,
114
- } from './math/spotPosition';
115
- import {
116
- calculateLiveOracleTwap,
117
- getMultipleBetweenOracleSources,
118
- } from './math/oracles';
119
- import { getPerpMarketTierNumber, getSpotMarketTierNumber } from './math/tiers';
120
- import { StrictOraclePrice } from './oracles/strictOraclePrice';
121
-
122
- import { grpcUserAccountSubscriber } from './accounts/grpcUserAccountSubscriber';
123
- import {
124
- IsolatedMarginCalculation,
125
- MarginCalculation,
126
- MarginContext,
127
- } from './marginCalculation';
128
-
129
- export type MarginType = 'Cross' | 'Isolated';
130
-
131
- export class User {
132
- velocityClient: VelocityClient;
133
- userAccountPublicKey: PublicKey;
134
- accountSubscriber: UserAccountSubscriber;
135
- _isSubscribed = false;
136
- eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
137
-
138
- public get isSubscribed() {
139
- return this._isSubscribed && this.accountSubscriber.isSubscribed;
140
- }
141
-
142
- public set isSubscribed(val: boolean) {
143
- this._isSubscribed = val;
144
- }
145
-
146
- public constructor(config: UserConfig) {
147
- // Type-system guarantees at least one of the two is supplied.
148
- const velocityClient = config.velocityClient!;
149
- this.velocityClient = velocityClient;
150
- this.userAccountPublicKey = config.userAccountPublicKey;
151
- if (config.accountSubscription?.type === 'polling') {
152
- this.accountSubscriber = new PollingUserAccountSubscriber(
153
- velocityClient.connection,
154
- config.userAccountPublicKey,
155
- config.accountSubscription.accountLoader,
156
- (
157
- this.velocityClient.program.account as any
158
- ).user.coder.accounts.decodeUnchecked.bind(
159
- (this.velocityClient.program.account as any).user.coder.accounts
160
- )
161
- );
162
- } else if (config.accountSubscription?.type === 'custom') {
163
- this.accountSubscriber = config.accountSubscription.userAccountSubscriber;
164
- } else if (config.accountSubscription?.type === 'grpc') {
165
- if (config.accountSubscription.grpcMultiUserAccountSubscriber) {
166
- this.accountSubscriber =
167
- config.accountSubscription.grpcMultiUserAccountSubscriber.forUser(
168
- config.userAccountPublicKey
169
- );
170
- } else {
171
- this.accountSubscriber = new grpcUserAccountSubscriber(
172
- config.accountSubscription.grpcConfigs,
173
- velocityClient.program,
174
- config.userAccountPublicKey,
175
- {
176
- resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
177
- logResubMessages: config.accountSubscription?.logResubMessages,
178
- }
179
- );
180
- }
181
- } else {
182
- if (
183
- config.accountSubscription?.type === 'websocket' &&
184
- config.accountSubscription?.programUserAccountSubscriber
185
- ) {
186
- this.accountSubscriber = new WebSocketProgramUserAccountSubscriber(
187
- velocityClient.program,
188
- config.userAccountPublicKey,
189
- config.accountSubscription.programUserAccountSubscriber
190
- );
191
- } else {
192
- this.accountSubscriber = new WebSocketUserAccountSubscriber(
193
- velocityClient.program,
194
- config.userAccountPublicKey,
195
- {
196
- resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
197
- logResubMessages: config.accountSubscription?.logResubMessages,
198
- },
199
- config.accountSubscription?.commitment
200
- );
201
- }
202
- }
203
- this.eventEmitter = this.accountSubscriber.eventEmitter;
204
- }
205
-
206
- /**
207
- * Subscribe to User state accounts
208
- * @returns SusbcriptionSuccess result
209
- */
210
- public async subscribe(userAccount?: UserAccount): Promise<boolean> {
211
- this.isSubscribed = await this.accountSubscriber.subscribe(userAccount);
212
- return this.isSubscribed;
213
- }
214
-
215
- /**
216
- * Forces the accountSubscriber to fetch account updates from rpc
217
- */
218
- public async fetchAccounts(): Promise<void> {
219
- await this.accountSubscriber.fetch();
220
- }
221
-
222
- public async unsubscribe(): Promise<void> {
223
- this.eventEmitter.removeAllListeners();
224
- await this.accountSubscriber.unsubscribe();
225
- this.isSubscribed = false;
226
- }
227
-
228
- /**
229
- * Returns the cached user account.
230
- *
231
- * - **Throws** `NotSubscribedError` if the subscriber has not been subscribed
232
- * yet — reading the account before {@link subscribe} resolves is a
233
- * programming error, not a missing-account condition.
234
- * - Returns `undefined` when subscribed but no account was found on chain.
235
- * Because `subscribe()` awaits the initial fetch, an `undefined` here means
236
- * the account does not exist (or has not yet been observed), not that data
237
- * is "still loading".
238
- */
239
- public getUserAccount(): UserAccount | undefined {
240
- return this.accountSubscriber.getUserAccountAndSlot()?.data;
241
- }
242
-
243
- /**
244
- * Like {@link getUserAccount} but throws instead of returning `undefined`
245
- * when the account was not found. Use at call sites that structurally
246
- * require the account to exist. (Still propagates `NotSubscribedError` when
247
- * called before subscribing.)
248
- *
249
- * Delegates to {@link getUserAccount} (rather than the subscriber directly)
250
- * so callers that override `getUserAccount` see the override here too.
251
- */
252
- public getUserAccountOrThrow(): UserAccount {
253
- const userAccount = this.getUserAccount();
254
- if (!userAccount) {
255
- throw new Error(
256
- `User account not found: ${this.getUserAccountPublicKey().toString()}`
257
- );
258
- }
259
- return userAccount;
260
- }
261
-
262
- public async forceGetUserAccount(): Promise<UserAccount | undefined> {
263
- await this.fetchAccounts();
264
- const account = this.accountSubscriber.getUserAccountAndSlot();
265
- return account?.data;
266
- }
267
-
268
- public getUserAccountAndSlot(): DataAndSlot<UserAccount> | undefined {
269
- return this.accountSubscriber.getUserAccountAndSlot();
270
- }
271
-
272
- /**
273
- * Like {@link getUserAccountAndSlot} but throws instead of returning
274
- * `undefined` when the account was not found. Use at call sites that
275
- * structurally require the account to exist. (Still propagates
276
- * `NotSubscribedError` when called before subscribing.)
277
- */
278
- public getUserAccountAndSlotOrThrow(): DataAndSlot<UserAccount> {
279
- return assertDataAndSlot(
280
- this.accountSubscriber.getUserAccountAndSlot(),
281
- `User account not found: ${this.getUserAccountPublicKey().toString()}`
282
- );
283
- }
284
-
285
- public getPerpPositionForUserAccount(
286
- userAccount: UserAccount,
287
- marketIndex: number
288
- ): PerpPosition | undefined {
289
- return this.getActivePerpPositionsForUserAccount(userAccount).find(
290
- (position) => position.marketIndex === marketIndex
291
- );
292
- }
293
-
294
- /**
295
- * Gets the user's current position for a given perp market. If the user has no position returns undefined
296
- * @param marketIndex
297
- * @returns userPerpPosition
298
- */
299
- public getPerpPosition(marketIndex: number): PerpPosition | undefined {
300
- const userAccount = this.getUserAccountOrThrow();
301
- return this.getPerpPositionForUserAccount(userAccount, marketIndex);
302
- }
303
-
304
- public getPerpPositionOrEmpty(marketIndex: number): PerpPosition {
305
- const userAccount = this.getUserAccountOrThrow();
306
- return (
307
- this.getPerpPositionForUserAccount(userAccount, marketIndex) ??
308
- this.getEmptyPosition(marketIndex)
309
- );
310
- }
311
-
312
- public getPerpPositionOrThrow(marketIndex: number): PerpPosition {
313
- const position = this.getPerpPosition(marketIndex);
314
- if (!position) {
315
- throw new Error(`No perp position found for market ${marketIndex}`);
316
- }
317
- return position;
318
- }
319
-
320
- public getPerpPositionAndSlot(
321
- marketIndex: number
322
- ): DataAndSlot<PerpPosition | undefined> {
323
- const userAccount = this.getUserAccountAndSlotOrThrow();
324
- const perpPosition = this.getPerpPositionForUserAccount(
325
- userAccount.data,
326
- marketIndex
327
- );
328
- return {
329
- data: perpPosition,
330
- slot: userAccount.slot,
331
- };
332
- }
333
-
334
- public getSpotPositionForUserAccount(
335
- userAccount: UserAccount,
336
- marketIndex: number
337
- ): SpotPosition | undefined {
338
- return userAccount.spotPositions.find(
339
- (position) => position.marketIndex === marketIndex
340
- );
341
- }
342
-
343
- /**
344
- * Gets the user's current position for a given spot market. If the user has no position returns undefined
345
- * @param marketIndex
346
- * @returns userSpotPosition
347
- */
348
- public getSpotPosition(marketIndex: number): SpotPosition | undefined {
349
- const userAccount = this.getUserAccountOrThrow();
350
- return this.getSpotPositionForUserAccount(userAccount, marketIndex);
351
- }
352
-
353
- public getSpotPositionAndSlot(
354
- marketIndex: number
355
- ): DataAndSlot<SpotPosition | undefined> {
356
- const userAccount = this.getUserAccountAndSlotOrThrow();
357
- const spotPosition = this.getSpotPositionForUserAccount(
358
- userAccount.data,
359
- marketIndex
360
- );
361
- return {
362
- data: spotPosition,
363
- slot: userAccount.slot,
364
- };
365
- }
366
-
367
- getEmptySpotPosition(marketIndex: number): SpotPosition {
368
- return {
369
- marketIndex,
370
- scaledBalance: ZERO,
371
- balanceType: SpotBalanceType.DEPOSIT,
372
- cumulativeDeposits: ZERO,
373
- openAsks: ZERO,
374
- openBids: ZERO,
375
- openOrders: 0,
376
- };
377
- }
378
-
379
- /**
380
- * Returns the token amount for a given market. The spot market precision is based on the token mint decimals.
381
- * Positive if it is a deposit, negative if it is a borrow.
382
- *
383
- * @param marketIndex
384
- */
385
- public getTokenAmount(marketIndex: number): BN {
386
- const spotPosition = this.getSpotPosition(marketIndex);
387
- if (spotPosition === undefined) {
388
- return ZERO;
389
- }
390
- const spotMarket =
391
- this.velocityClient.getSpotMarketAccountOrThrow(marketIndex);
392
- return getSignedTokenAmount(
393
- getTokenAmount(
394
- spotPosition.scaledBalance,
395
- spotMarket,
396
- spotPosition.balanceType
397
- ),
398
- spotPosition.balanceType
399
- );
400
- }
401
-
402
- public getEmptyPosition(marketIndex: number): PerpPosition {
403
- return {
404
- baseAssetAmount: ZERO,
405
- remainderBaseAssetAmount: 0,
406
- lastCumulativeFundingRate: ZERO,
407
- marketIndex,
408
- quoteAssetAmount: ZERO,
409
- quoteEntryAmount: ZERO,
410
- quoteBreakEvenAmount: ZERO,
411
- openOrders: 0,
412
- openBids: ZERO,
413
- openAsks: ZERO,
414
- settledPnl: ZERO,
415
- maxMarginRatio: 0,
416
- isolatedPositionScaledBalance: ZERO,
417
- positionFlag: 0,
418
- };
419
- }
420
-
421
- public isPositionEmpty(position: PerpPosition): boolean {
422
- return position.baseAssetAmount.eq(ZERO) && position.openOrders === 0;
423
- }
424
-
425
- public getIsolatePerpPositionTokenAmount(perpMarketIndex: number): BN {
426
- const perpPosition = this.getPerpPosition(perpMarketIndex);
427
- if (!perpPosition) return ZERO;
428
- const perpMarket =
429
- this.velocityClient.getPerpMarketAccountOrThrow(perpMarketIndex);
430
- const spotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
431
- perpMarket.quoteSpotMarketIndex
432
- );
433
- if (perpPosition === undefined) {
434
- return ZERO;
435
- }
436
- return getTokenAmount(
437
- perpPosition.isolatedPositionScaledBalance ?? ZERO, //TODO remove ? later
438
- spotMarket,
439
- SpotBalanceType.DEPOSIT
440
- );
441
- }
442
-
443
- /**
444
- * Returns the total USD value of deposits across all isolated perp positions.
445
- */
446
- public getTotalIsolatedPositionDeposits(): BN {
447
- return this.getActivePerpPositions().reduce((total, perpPosition) => {
448
- if (!perpPosition.isolatedPositionScaledBalance?.gt(ZERO)) {
449
- return total;
450
- }
451
-
452
- const perpMarket = this.velocityClient.getPerpMarketAccountOrThrow(
453
- perpPosition.marketIndex
454
- );
455
- const quoteSpotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
456
- perpMarket.quoteSpotMarketIndex
457
- );
458
- const quoteOraclePriceData = this.getOracleDataForSpotMarket(
459
- perpMarket.quoteSpotMarketIndex
460
- );
461
- const strictOracle = new StrictOraclePrice(
462
- quoteOraclePriceData.price,
463
- quoteOraclePriceData.twap
464
- );
465
-
466
- const tokenAmount = getTokenAmount(
467
- perpPosition.isolatedPositionScaledBalance,
468
- quoteSpotMarket,
469
- SpotBalanceType.DEPOSIT
470
- );
471
-
472
- return total.add(
473
- getStrictTokenValue(tokenAmount, quoteSpotMarket.decimals, strictOracle)
474
- );
475
- }, ZERO);
476
- }
477
-
478
- public getClonedPosition(position: PerpPosition): PerpPosition {
479
- const clonedPosition = Object.assign({}, position);
480
- return clonedPosition;
481
- }
482
-
483
- public getOrderForUserAccount(
484
- userAccount: UserAccount,
485
- orderId: number
486
- ): Order | undefined {
487
- return userAccount.orders.find((order) => order.orderId === orderId);
488
- }
489
-
490
- /**
491
- * @param orderId
492
- * @returns Order
493
- */
494
- public getOrder(orderId: number): Order | undefined {
495
- const userAccount = this.getUserAccountOrThrow();
496
- return this.getOrderForUserAccount(userAccount, orderId);
497
- }
498
-
499
- public getOrderAndSlot(orderId: number): DataAndSlot<Order | undefined> {
500
- const userAccount = this.getUserAccountAndSlotOrThrow();
501
- const order = this.getOrderForUserAccount(userAccount.data, orderId);
502
- return {
503
- data: order,
504
- slot: userAccount.slot,
505
- };
506
- }
507
-
508
- public getOrderByUserIdForUserAccount(
509
- userAccount: UserAccount,
510
- userOrderId: number
511
- ): Order | undefined {
512
- return userAccount.orders.find(
513
- (order) => order.userOrderId === userOrderId
514
- );
515
- }
516
-
517
- /**
518
- * @param userOrderId
519
- * @returns Order
520
- */
521
- public getOrderByUserOrderId(userOrderId: number): Order | undefined {
522
- const userAccount = this.getUserAccountOrThrow();
523
- return this.getOrderByUserIdForUserAccount(userAccount, userOrderId);
524
- }
525
-
526
- public getOrderByUserOrderIdAndSlot(
527
- userOrderId: number
528
- ): DataAndSlot<Order | undefined> {
529
- const userAccount = this.getUserAccountAndSlotOrThrow();
530
- const order = this.getOrderByUserIdForUserAccount(
531
- userAccount.data,
532
- userOrderId
533
- );
534
- return {
535
- data: order,
536
- slot: userAccount.slot,
537
- };
538
- }
539
-
540
- public getOpenOrdersForUserAccount(
541
- userAccount?: UserAccount
542
- ): Order[] | undefined {
543
- return userAccount?.orders.filter((order) =>
544
- isVariant(order.status, 'open')
545
- );
546
- }
547
-
548
- public getOpenOrders(): Order[] {
549
- const userAccount = this.getUserAccount();
550
- return this.getOpenOrdersForUserAccount(userAccount) ?? [];
551
- }
552
-
553
- public getOpenOrdersAndSlot(): DataAndSlot<Order[]> {
554
- const userAccount = this.getUserAccountAndSlotOrThrow();
555
- const openOrders = this.getOpenOrdersForUserAccount(userAccount.data) ?? [];
556
- return {
557
- data: openOrders,
558
- slot: userAccount.slot,
559
- };
560
- }
561
-
562
- public getUserAccountPublicKey(): PublicKey {
563
- return this.userAccountPublicKey;
564
- }
565
-
566
- public async exists(): Promise<boolean> {
567
- const userAccountRPCResponse =
568
- await this.velocityClient.connection.getParsedAccountInfo(
569
- this.userAccountPublicKey
570
- );
571
- return userAccountRPCResponse.value !== null;
572
- }
573
-
574
- /**
575
- * calculates the total open bids/asks in a perp market (including lps)
576
- * @returns : open bids
577
- * @returns : open asks
578
- */
579
- public getPerpBidAsks(marketIndex: number): [BN, BN] {
580
- const position = this.getPerpPositionOrThrow(marketIndex);
581
-
582
- const totalOpenBids = position.openBids;
583
- const totalOpenAsks = position.openAsks;
584
-
585
- return [totalOpenBids, totalOpenAsks];
586
- }
587
-
588
- /**
589
- * calculates Buying Power = free collateral / initial margin ratio
590
- * @returns : Precision QUOTE_PRECISION
591
- */
592
- public getPerpBuyingPower(
593
- marketIndex: number,
594
- collateralBuffer = ZERO,
595
- maxMarginRatio: number | undefined = undefined,
596
- positionType: 'isolated' | 'cross' = 'cross'
597
- ): BN {
598
- const perpPosition = this.getPerpPositionOrEmpty(marketIndex);
599
-
600
- const perpMarket =
601
- this.velocityClient.getPerpMarketAccountOrThrow(marketIndex);
602
- const oraclePriceData = this.getOracleDataForPerpMarket(marketIndex);
603
- const worstCaseBaseAssetAmount = perpPosition
604
- ? calculateWorstCaseBaseAssetAmount(
605
- perpPosition,
606
- perpMarket,
607
- oraclePriceData.price
608
- )
609
- : ZERO;
610
-
611
- // if position is isolated, we always add on available quote from the cross account
612
- let freeCollateral: BN = ZERO;
613
- if (positionType === 'isolated') {
614
- const {
615
- totalAssetValue: quoteSpotMarketAssetValue,
616
- totalLiabilityValue: quoteSpotMarketLiabilityValue,
617
- } = this.getSpotMarketAssetAndLiabilityValue(
618
- perpMarket.quoteSpotMarketIndex,
619
- 'Initial',
620
- undefined,
621
- undefined,
622
- true
623
- );
624
-
625
- const usdcAvailableForIsolatedMargin = quoteSpotMarketAssetValue.sub(
626
- quoteSpotMarketLiabilityValue
627
- );
628
- const generalFreeCollateral = this.getFreeCollateral(
629
- 'Initial',
630
- undefined
631
- );
632
- freeCollateral = BN.min(
633
- usdcAvailableForIsolatedMargin,
634
- generalFreeCollateral
635
- ).sub(collateralBuffer);
636
- } else {
637
- // free collateral from the cross account only
638
- freeCollateral = this.getFreeCollateral('Initial', undefined).sub(
639
- collateralBuffer
640
- );
641
- }
642
-
643
- return this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
644
- marketIndex,
645
- freeCollateral,
646
- worstCaseBaseAssetAmount,
647
- maxMarginRatio || perpPosition.maxMarginRatio
648
- );
649
- }
650
-
651
- private resolveMaxMarginRatio(perpMarketMaxMarginRatio?: number): number {
652
- // 0 means "no custom margin ratio override", so Math.max returns
653
- // userAccount.maxMarginRatio unchanged — the expected semantic.
654
- return Math.max(
655
- perpMarketMaxMarginRatio ?? 0,
656
- this.getUserAccountOrThrow().maxMarginRatio
657
- );
658
- }
659
-
660
- getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
661
- marketIndex: number,
662
- freeCollateral: BN,
663
- baseAssetAmount: BN,
664
- perpMarketMaxMarginRatio: number | undefined = undefined
665
- ): BN {
666
- const maxMarginRatio = this.resolveMaxMarginRatio(perpMarketMaxMarginRatio);
667
- const marginRatio = calculateMarketMarginRatio(
668
- this.velocityClient.getPerpMarketAccountOrThrow(marketIndex),
669
- baseAssetAmount,
670
- 'Initial',
671
- maxMarginRatio
672
- );
673
-
674
- return freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio));
675
- }
676
-
677
- /**
678
- * calculates Free Collateral = Total collateral - margin requirement
679
- * @returns : Precision QUOTE_PRECISION
680
- */
681
- public getFreeCollateral(
682
- marginCategory: MarginCategory = 'Initial',
683
- perpMarketIndex?: number
684
- ): BN {
685
- const calc = this.getMarginCalculation(marginCategory, {
686
- strict: marginCategory === 'Initial',
687
- });
688
-
689
- if (perpMarketIndex !== undefined) {
690
- // getIsolatedFreeCollateral will throw if no existing isolated position but we are fetching for potential new position, so we wrap in a try/catch
691
- try {
692
- return calc.getIsolatedFreeCollateral(perpMarketIndex);
693
- } catch (error) {
694
- return ZERO;
695
- }
696
- } else {
697
- return calc.getCrossFreeCollateral();
698
- }
699
- }
700
-
701
- /**
702
- * @deprecated Use the overload that includes { marginType, perpMarketIndex }
703
- */
704
- public getMarginRequirement(
705
- marginCategory: MarginCategory,
706
- liquidationBuffer?: BN,
707
- strict?: boolean,
708
- includeOpenOrders?: boolean
709
- ): BN;
710
-
711
- /**
712
- * Calculates the margin requirement based on the specified parameters.
713
- *
714
- * @param marginCategory - The category of margin to calculate ('Initial' or 'Maintenance').
715
- * @param liquidationBuffer - Optional buffer amount to consider during liquidation scenarios.
716
- * @param strict - Optional flag to enforce strict margin calculations.
717
- * @param includeOpenOrders - Optional flag to include open orders in the margin calculation.
718
- * @param perpMarketIndex - Optional index of the perpetual market. Required if marginType is 'Isolated'.
719
- *
720
- * @returns The calculated margin requirement as a BN (BigNumber).
721
- */
722
- public getMarginRequirement(
723
- marginCategory: MarginCategory,
724
- liquidationBuffer?: BN,
725
- strict?: boolean,
726
- includeOpenOrders?: boolean,
727
- perpMarketIndex?: number
728
- ): BN;
729
-
730
- public getMarginRequirement(
731
- marginCategory: MarginCategory,
732
- liquidationBuffer?: BN,
733
- strict?: boolean,
734
- includeOpenOrders?: boolean,
735
- perpMarketIndex?: number
736
- ): BN {
737
- const liquidationBufferMap = new Map();
738
- if (liquidationBuffer && perpMarketIndex !== undefined) {
739
- liquidationBufferMap.set(perpMarketIndex, liquidationBuffer);
740
- } else if (liquidationBuffer) {
741
- liquidationBufferMap.set('cross', liquidationBuffer);
742
- }
743
-
744
- const marginCalc = this.getMarginCalculation(marginCategory, {
745
- strict,
746
- includeOpenOrders,
747
- liquidationBufferMap,
748
- });
749
-
750
- // If perpMarketIndex is provided, compute only for that market index
751
- if (perpMarketIndex !== undefined) {
752
- const isolatedMarginCalculation =
753
- marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
754
- if (!isolatedMarginCalculation) return ZERO;
755
- const { marginRequirement, marginRequirementPlusBuffer } =
756
- isolatedMarginCalculation;
757
-
758
- if (liquidationBuffer?.gt(ZERO)) {
759
- return marginRequirementPlusBuffer;
760
- }
761
- return marginRequirement;
762
- }
763
-
764
- // Default: Cross margin requirement
765
- if (liquidationBuffer?.gt(ZERO)) {
766
- return marginCalc.marginRequirementPlusBuffer;
767
- }
768
- return marginCalc.marginRequirement;
769
- }
770
-
771
- /**
772
- * @returns The initial margin requirement in USDC. : QUOTE_PRECISION
773
- */
774
- public getInitialMarginRequirement(perpMarketIndex?: number): BN {
775
- return this.getMarginRequirement(
776
- 'Initial',
777
- undefined,
778
- true,
779
- undefined,
780
- perpMarketIndex
781
- );
782
- }
783
-
784
- /**
785
- * @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
786
- */
787
- public getMaintenanceMarginRequirement(
788
- liquidationBuffer?: BN,
789
- perpMarketIndex?: number
790
- ): BN {
791
- return this.getMarginRequirement(
792
- 'Maintenance',
793
- liquidationBuffer,
794
- false, // strict default
795
- true, // includeOpenOrders default
796
- perpMarketIndex
797
- );
798
- }
799
-
800
- public getActivePerpPositionsForUserAccount(
801
- userAccount: UserAccount
802
- ): PerpPosition[] {
803
- return userAccount.perpPositions.filter(
804
- (pos) =>
805
- !pos.baseAssetAmount.eq(ZERO) ||
806
- !pos.quoteAssetAmount.eq(ZERO) ||
807
- !(pos.openOrders == 0) ||
808
- pos.isolatedPositionScaledBalance?.gt(ZERO)
809
- );
810
- }
811
-
812
- public getActivePerpPositions(): PerpPosition[] {
813
- const userAccount = this.getUserAccountOrThrow();
814
- return this.getActivePerpPositionsForUserAccount(userAccount);
815
- }
816
- public getActivePerpPositionsAndSlot(): DataAndSlot<PerpPosition[]> {
817
- const userAccount = this.getUserAccountAndSlotOrThrow();
818
- const positions = this.getActivePerpPositionsForUserAccount(
819
- userAccount.data
820
- );
821
- return {
822
- data: positions,
823
- slot: userAccount.slot,
824
- };
825
- }
826
-
827
- public getActiveSpotPositionsForUserAccount(
828
- userAccount: UserAccount
829
- ): SpotPosition[] {
830
- return userAccount.spotPositions.filter(
831
- (pos) => !isSpotPositionAvailable(pos)
832
- );
833
- }
834
-
835
- public getActiveSpotPositions(): SpotPosition[] {
836
- const userAccount = this.getUserAccountOrThrow();
837
- return this.getActiveSpotPositionsForUserAccount(userAccount);
838
- }
839
- public getActiveSpotPositionsAndSlot(): DataAndSlot<SpotPosition[]> {
840
- const userAccount = this.getUserAccountAndSlotOrThrow();
841
- const positions = this.getActiveSpotPositionsForUserAccount(
842
- userAccount.data
843
- );
844
- return {
845
- data: positions,
846
- slot: userAccount.slot,
847
- };
848
- }
849
-
850
- /**
851
- * calculates unrealized position price pnl
852
- * @returns : Precision QUOTE_PRECISION
853
- */
854
- public getUnrealizedPNL(
855
- withFunding?: boolean,
856
- marketIndex?: number,
857
- withWeightMarginCategory?: MarginCategory,
858
- strict = false,
859
- liquidationBuffer?: BN
860
- ): BN {
861
- return this.getActivePerpPositions()
862
- .filter((pos) =>
863
- marketIndex !== undefined ? pos.marketIndex === marketIndex : true
864
- )
865
- .reduce((unrealizedPnl, perpPosition) => {
866
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
867
- perpPosition.marketIndex
868
- );
869
- const oraclePriceData = this.getMMOracleDataForPerpMarket(
870
- market.marketIndex
871
- );
872
-
873
- const quoteSpotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
874
- market.quoteSpotMarketIndex
875
- );
876
- const quoteOraclePriceData = this.getOracleDataForSpotMarket(
877
- market.quoteSpotMarketIndex
878
- );
879
-
880
- let positionUnrealizedPnl = calculatePositionPNL(
881
- market,
882
- perpPosition,
883
- withFunding,
884
- oraclePriceData
885
- );
886
-
887
- let quotePrice;
888
- if (strict && positionUnrealizedPnl.gt(ZERO)) {
889
- quotePrice = BN.min(
890
- quoteOraclePriceData.price,
891
- quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
892
- );
893
- } else if (strict && positionUnrealizedPnl.lt(ZERO)) {
894
- quotePrice = BN.max(
895
- quoteOraclePriceData.price,
896
- quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
897
- );
898
- } else {
899
- quotePrice = quoteOraclePriceData.price;
900
- }
901
-
902
- positionUnrealizedPnl = positionUnrealizedPnl
903
- .mul(quotePrice)
904
- .div(PRICE_PRECISION);
905
-
906
- if (withWeightMarginCategory !== undefined) {
907
- if (positionUnrealizedPnl.gt(ZERO)) {
908
- positionUnrealizedPnl = positionUnrealizedPnl
909
- .mul(
910
- calculateUnrealizedAssetWeight(
911
- market,
912
- quoteSpotMarket,
913
- positionUnrealizedPnl,
914
- withWeightMarginCategory,
915
- oraclePriceData
916
- )
917
- )
918
- .div(new BN(SPOT_MARKET_WEIGHT_PRECISION));
919
- }
920
-
921
- if (liquidationBuffer && positionUnrealizedPnl.lt(ZERO)) {
922
- positionUnrealizedPnl = positionUnrealizedPnl.add(
923
- positionUnrealizedPnl.mul(liquidationBuffer).div(MARGIN_PRECISION)
924
- );
925
- }
926
- }
927
-
928
- return unrealizedPnl.add(positionUnrealizedPnl);
929
- }, ZERO);
930
- }
931
-
932
- /**
933
- * calculates unrealized funding payment pnl
934
- * @returns : Precision QUOTE_PRECISION
935
- */
936
- public getUnrealizedFundingPNL(marketIndex?: number): BN {
937
- return this.getUserAccountOrThrow()
938
- .perpPositions.filter((pos) =>
939
- marketIndex !== undefined ? pos.marketIndex === marketIndex : true
940
- )
941
- .reduce((pnl, perpPosition) => {
942
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
943
- perpPosition.marketIndex
944
- );
945
- return pnl.add(calculateUnsettledFundingPnl(market, perpPosition));
946
- }, ZERO);
947
- }
948
-
949
- public getSpotMarketAssetAndLiabilityValue(
950
- marketIndex?: number,
951
- marginCategory?: MarginCategory,
952
- liquidationBuffer?: BN,
953
- includeOpenOrders?: boolean,
954
- strict = false,
955
- now?: BN
956
- ): { totalAssetValue: BN; totalLiabilityValue: BN } {
957
- now = now || new BN(new Date().getTime() / 1000);
958
- let netQuoteValue = ZERO;
959
- let totalAssetValue = ZERO;
960
- let totalLiabilityValue = ZERO;
961
- for (const spotPosition of this.getUserAccountOrThrow().spotPositions) {
962
- const countForBase =
963
- marketIndex === undefined || spotPosition.marketIndex === marketIndex;
964
-
965
- const countForQuote =
966
- marketIndex === undefined ||
967
- marketIndex === QUOTE_SPOT_MARKET_INDEX ||
968
- (includeOpenOrders && spotPosition.openOrders !== 0);
969
- if (
970
- isSpotPositionAvailable(spotPosition) ||
971
- (!countForBase && !countForQuote)
972
- ) {
973
- continue;
974
- }
975
-
976
- const spotMarketAccount: SpotMarketAccount =
977
- this.velocityClient.getSpotMarketAccountOrThrow(
978
- spotPosition.marketIndex
979
- );
980
-
981
- const oraclePriceData = this.getOracleDataForSpotMarket(
982
- spotPosition.marketIndex
983
- );
984
-
985
- let twap5min;
986
- if (strict) {
987
- twap5min = calculateLiveOracleTwap(
988
- spotMarketAccount.historicalOracleData,
989
- oraclePriceData,
990
- now,
991
- FIVE_MINUTE // 5MIN
992
- );
993
- }
994
- const strictOraclePrice = new StrictOraclePrice(
995
- oraclePriceData.price,
996
- twap5min
997
- );
998
-
999
- if (
1000
- spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX &&
1001
- countForQuote
1002
- ) {
1003
- const tokenAmount = getSignedTokenAmount(
1004
- getTokenAmount(
1005
- spotPosition.scaledBalance,
1006
- spotMarketAccount,
1007
- spotPosition.balanceType
1008
- ),
1009
- spotPosition.balanceType
1010
- );
1011
-
1012
- if (isVariant(spotPosition.balanceType, 'borrow')) {
1013
- const weightedTokenValue = this.getSpotLiabilityValue(
1014
- tokenAmount,
1015
- strictOraclePrice,
1016
- spotMarketAccount,
1017
- marginCategory,
1018
- liquidationBuffer
1019
- ).abs();
1020
-
1021
- netQuoteValue = netQuoteValue.sub(weightedTokenValue);
1022
- } else {
1023
- const weightedTokenValue = this.getSpotAssetValue(
1024
- tokenAmount,
1025
- strictOraclePrice,
1026
- spotMarketAccount,
1027
- marginCategory
1028
- );
1029
-
1030
- netQuoteValue = netQuoteValue.add(weightedTokenValue);
1031
- }
1032
-
1033
- continue;
1034
- }
1035
-
1036
- if (!includeOpenOrders && countForBase) {
1037
- if (isVariant(spotPosition.balanceType, 'borrow')) {
1038
- const tokenAmount = getSignedTokenAmount(
1039
- getTokenAmount(
1040
- spotPosition.scaledBalance,
1041
- spotMarketAccount,
1042
- spotPosition.balanceType
1043
- ),
1044
- SpotBalanceType.BORROW
1045
- );
1046
- const liabilityValue = this.getSpotLiabilityValue(
1047
- tokenAmount,
1048
- strictOraclePrice,
1049
- spotMarketAccount,
1050
- marginCategory,
1051
- liquidationBuffer
1052
- ).abs();
1053
- totalLiabilityValue = totalLiabilityValue.add(liabilityValue);
1054
-
1055
- continue;
1056
- } else {
1057
- const tokenAmount = getTokenAmount(
1058
- spotPosition.scaledBalance,
1059
- spotMarketAccount,
1060
- spotPosition.balanceType
1061
- );
1062
- const assetValue = this.getSpotAssetValue(
1063
- tokenAmount,
1064
- strictOraclePrice,
1065
- spotMarketAccount,
1066
- marginCategory
1067
- );
1068
- totalAssetValue = totalAssetValue.add(assetValue);
1069
-
1070
- continue;
1071
- }
1072
- }
1073
-
1074
- const {
1075
- tokenAmount: worstCaseTokenAmount,
1076
- ordersValue: worstCaseQuoteTokenAmount,
1077
- } = getWorstCaseTokenAmounts(
1078
- spotPosition,
1079
- spotMarketAccount,
1080
- strictOraclePrice,
1081
- marginCategory,
1082
- this.getUserAccountOrThrow().maxMarginRatio
1083
- );
1084
-
1085
- if (worstCaseTokenAmount.gt(ZERO) && countForBase) {
1086
- const baseAssetValue = this.getSpotAssetValue(
1087
- worstCaseTokenAmount,
1088
- strictOraclePrice,
1089
- spotMarketAccount,
1090
- marginCategory
1091
- );
1092
-
1093
- totalAssetValue = totalAssetValue.add(baseAssetValue);
1094
- }
1095
-
1096
- if (worstCaseTokenAmount.lt(ZERO) && countForBase) {
1097
- const baseLiabilityValue = this.getSpotLiabilityValue(
1098
- worstCaseTokenAmount,
1099
- strictOraclePrice,
1100
- spotMarketAccount,
1101
- marginCategory,
1102
- liquidationBuffer
1103
- ).abs();
1104
-
1105
- totalLiabilityValue = totalLiabilityValue.add(baseLiabilityValue);
1106
- }
1107
-
1108
- if (worstCaseQuoteTokenAmount.gt(ZERO) && countForQuote) {
1109
- netQuoteValue = netQuoteValue.add(worstCaseQuoteTokenAmount);
1110
- }
1111
-
1112
- if (worstCaseQuoteTokenAmount.lt(ZERO) && countForQuote) {
1113
- let weight = SPOT_MARKET_WEIGHT_PRECISION;
1114
- if (marginCategory === 'Initial') {
1115
- weight = BN.max(
1116
- weight,
1117
- new BN(this.getUserAccountOrThrow().maxMarginRatio)
1118
- );
1119
- }
1120
-
1121
- const weightedTokenValue = worstCaseQuoteTokenAmount
1122
- .abs()
1123
- .mul(weight)
1124
- .div(SPOT_MARKET_WEIGHT_PRECISION);
1125
-
1126
- netQuoteValue = netQuoteValue.sub(weightedTokenValue);
1127
- }
1128
-
1129
- totalLiabilityValue = totalLiabilityValue.add(
1130
- new BN(spotPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
1131
- );
1132
- }
1133
-
1134
- if (marketIndex === undefined || marketIndex === QUOTE_SPOT_MARKET_INDEX) {
1135
- if (netQuoteValue.gt(ZERO)) {
1136
- totalAssetValue = totalAssetValue.add(netQuoteValue);
1137
- } else {
1138
- totalLiabilityValue = totalLiabilityValue.add(netQuoteValue.abs());
1139
- }
1140
- }
1141
-
1142
- return { totalAssetValue, totalLiabilityValue };
1143
- }
1144
-
1145
- public getSpotMarketLiabilityValue(
1146
- marketIndex?: number,
1147
- marginCategory?: MarginCategory,
1148
- liquidationBuffer?: BN,
1149
- includeOpenOrders?: boolean,
1150
- strict = false,
1151
- now?: BN
1152
- ): BN {
1153
- const { totalLiabilityValue } = this.getSpotMarketAssetAndLiabilityValue(
1154
- marketIndex,
1155
- marginCategory,
1156
- liquidationBuffer,
1157
- includeOpenOrders,
1158
- strict,
1159
- now
1160
- );
1161
- return totalLiabilityValue;
1162
- }
1163
-
1164
- getSpotLiabilityValue(
1165
- tokenAmount: BN,
1166
- strictOraclePrice: StrictOraclePrice,
1167
- spotMarketAccount: SpotMarketAccount,
1168
- marginCategory?: MarginCategory,
1169
- liquidationBuffer?: BN
1170
- ): BN {
1171
- return getSpotLiabilityValue(
1172
- tokenAmount,
1173
- strictOraclePrice,
1174
- spotMarketAccount,
1175
- this.getUserAccountOrThrow().maxMarginRatio,
1176
- marginCategory,
1177
- liquidationBuffer
1178
- );
1179
- }
1180
-
1181
- public getSpotMarketAssetValue(
1182
- marketIndex?: number,
1183
- marginCategory?: MarginCategory,
1184
- includeOpenOrders?: boolean,
1185
- strict = false,
1186
- now?: BN
1187
- ): BN {
1188
- const { totalAssetValue } = this.getSpotMarketAssetAndLiabilityValue(
1189
- marketIndex,
1190
- marginCategory,
1191
- undefined,
1192
- includeOpenOrders,
1193
- strict,
1194
- now
1195
- );
1196
- return totalAssetValue;
1197
- }
1198
-
1199
- getSpotAssetValue(
1200
- tokenAmount: BN,
1201
- strictOraclePrice: StrictOraclePrice,
1202
- spotMarketAccount: SpotMarketAccount,
1203
- marginCategory?: MarginCategory
1204
- ): BN {
1205
- return getSpotAssetValue(
1206
- tokenAmount,
1207
- strictOraclePrice,
1208
- spotMarketAccount,
1209
- this.getUserAccountOrThrow().maxMarginRatio,
1210
- marginCategory
1211
- );
1212
- }
1213
-
1214
- public getSpotPositionValue(
1215
- marketIndex: number,
1216
- marginCategory?: MarginCategory,
1217
- includeOpenOrders?: boolean,
1218
- strict = false,
1219
- now?: BN
1220
- ): BN {
1221
- const { totalAssetValue, totalLiabilityValue } =
1222
- this.getSpotMarketAssetAndLiabilityValue(
1223
- marketIndex,
1224
- marginCategory,
1225
- undefined,
1226
- includeOpenOrders,
1227
- strict,
1228
- now
1229
- );
1230
-
1231
- return totalAssetValue.sub(totalLiabilityValue);
1232
- }
1233
-
1234
- public getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN {
1235
- const { totalAssetValue, totalLiabilityValue } =
1236
- this.getSpotMarketAssetAndLiabilityValue(
1237
- undefined,
1238
- withWeightMarginCategory
1239
- );
1240
-
1241
- return totalAssetValue.sub(totalLiabilityValue);
1242
- }
1243
-
1244
- /**
1245
- * calculates TotalCollateral: collateral + unrealized pnl
1246
- * @returns : Precision QUOTE_PRECISION
1247
- */
1248
- public getTotalCollateral(
1249
- marginCategory: MarginCategory = 'Initial',
1250
- strict = false,
1251
- includeOpenOrders = true,
1252
- liquidationBuffer?: BN,
1253
- perpMarketIndex?: number
1254
- ): BN {
1255
- const liquidationBufferMap = (() => {
1256
- if (liquidationBuffer && perpMarketIndex !== undefined) {
1257
- return new Map([[perpMarketIndex, liquidationBuffer]]);
1258
- } else if (liquidationBuffer) {
1259
- return new Map([['cross', liquidationBuffer]]);
1260
- }
1261
- return new Map();
1262
- })();
1263
- const marginCalc = this.getMarginCalculation(marginCategory, {
1264
- strict,
1265
- includeOpenOrders,
1266
- liquidationBufferMap,
1267
- });
1268
-
1269
- if (perpMarketIndex !== undefined) {
1270
- const isolatedMarginCalculation =
1271
- marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
1272
- if (!isolatedMarginCalculation) {
1273
- throw new Error(
1274
- `No isolated margin calculation for perp market ${perpMarketIndex}`
1275
- );
1276
- }
1277
- const { totalCollateral, totalCollateralBuffer } =
1278
- isolatedMarginCalculation;
1279
- if (liquidationBuffer?.gt(ZERO)) {
1280
- return totalCollateralBuffer;
1281
- }
1282
- return totalCollateral;
1283
- }
1284
-
1285
- if (liquidationBuffer?.gt(ZERO)) {
1286
- return marginCalc.totalCollateralBuffer;
1287
- }
1288
- return marginCalc.totalCollateral;
1289
- }
1290
-
1291
- public getLiquidationBuffer(): Map<number | 'cross', BN> {
1292
- const liquidationBufferMap = new Map<number | 'cross', BN>();
1293
- if (this.isBeingLiquidated()) {
1294
- liquidationBufferMap.set(
1295
- 'cross',
1296
- new BN(
1297
- this.velocityClient.getStateAccount().liquidationMarginBufferRatio
1298
- )
1299
- );
1300
- }
1301
- for (const position of this.getActivePerpPositions()) {
1302
- if (
1303
- position.positionFlag &
1304
- (PositionFlag.BeingLiquidated | PositionFlag.Bankruptcy)
1305
- ) {
1306
- liquidationBufferMap.set(
1307
- position.marketIndex,
1308
- new BN(
1309
- this.velocityClient.getStateAccount().liquidationMarginBufferRatio
1310
- )
1311
- );
1312
- }
1313
- }
1314
- return liquidationBufferMap;
1315
- }
1316
-
1317
- /**
1318
- * calculates User Health by comparing total collateral and maint. margin requirement
1319
- * @returns : number (value from [0, 100])
1320
- */
1321
- public getHealth(perpMarketIndex?: number): number {
1322
- if (this.isCrossMarginBeingLiquidated() && !perpMarketIndex) {
1323
- return 0;
1324
- }
1325
- if (
1326
- perpMarketIndex &&
1327
- this.isIsolatedPositionBeingLiquidated(perpMarketIndex)
1328
- ) {
1329
- return 0;
1330
- }
1331
-
1332
- const marginCalc = this.getMarginCalculation('Maintenance');
1333
-
1334
- let totalCollateral: BN = ZERO;
1335
- let maintenanceMarginReq: BN = ZERO;
1336
-
1337
- if (perpMarketIndex != null) {
1338
- const isolatedMarginCalc =
1339
- marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
1340
- if (isolatedMarginCalc) {
1341
- totalCollateral = isolatedMarginCalc.totalCollateral;
1342
- maintenanceMarginReq = isolatedMarginCalc.marginRequirement;
1343
- }
1344
- } else {
1345
- totalCollateral = marginCalc.totalCollateral;
1346
- maintenanceMarginReq = marginCalc.marginRequirement;
1347
- }
1348
-
1349
- let health: number;
1350
-
1351
- if (maintenanceMarginReq.eq(ZERO) && totalCollateral.gte(ZERO)) {
1352
- health = 100;
1353
- } else if (totalCollateral.lte(ZERO)) {
1354
- health = 0;
1355
- } else {
1356
- health = Math.round(
1357
- Math.min(
1358
- 100,
1359
- Math.max(
1360
- 0,
1361
- (1 - maintenanceMarginReq.toNumber() / totalCollateral.toNumber()) *
1362
- 100
1363
- )
1364
- )
1365
- );
1366
- }
1367
-
1368
- return health;
1369
- }
1370
-
1371
- calculateWeightedPerpPositionLiability(
1372
- perpPosition: PerpPosition,
1373
- marginCategory?: MarginCategory,
1374
- liquidationBuffer?: BN,
1375
- includeOpenOrders?: boolean,
1376
- strict = false
1377
- ): BN {
1378
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
1379
- perpPosition.marketIndex
1380
- );
1381
-
1382
- let valuationPrice = this.getOracleDataForPerpMarket(
1383
- market.marketIndex
1384
- ).price;
1385
-
1386
- if (isVariant(market.status, 'settlement')) {
1387
- valuationPrice = market.expiryPrice;
1388
- }
1389
-
1390
- let baseAssetAmount: BN;
1391
- let liabilityValue;
1392
- if (includeOpenOrders) {
1393
- const { worstCaseBaseAssetAmount, worstCaseLiabilityValue } =
1394
- calculateWorstCasePerpLiabilityValue(
1395
- perpPosition,
1396
- market,
1397
- valuationPrice
1398
- );
1399
- baseAssetAmount = worstCaseBaseAssetAmount;
1400
- liabilityValue = worstCaseLiabilityValue;
1401
- } else {
1402
- baseAssetAmount = perpPosition.baseAssetAmount;
1403
- liabilityValue = calculatePerpLiabilityValue(
1404
- baseAssetAmount,
1405
- valuationPrice
1406
- );
1407
- }
1408
-
1409
- if (marginCategory) {
1410
- const userCustomMargin = Math.max(
1411
- perpPosition.maxMarginRatio,
1412
- this.getUserAccountOrThrow().maxMarginRatio
1413
- );
1414
- let marginRatio = new BN(
1415
- calculateMarketMarginRatio(
1416
- market,
1417
- baseAssetAmount.abs(),
1418
- marginCategory,
1419
- userCustomMargin
1420
- )
1421
- );
1422
-
1423
- if (liquidationBuffer !== undefined) {
1424
- marginRatio = marginRatio.add(liquidationBuffer);
1425
- }
1426
-
1427
- if (isVariant(market.status, 'settlement')) {
1428
- marginRatio = ZERO;
1429
- }
1430
-
1431
- const quoteSpotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
1432
- market.quoteSpotMarketIndex
1433
- );
1434
- const quoteOraclePriceData =
1435
- this.velocityClient.getOracleDataForSpotMarket(QUOTE_SPOT_MARKET_INDEX);
1436
-
1437
- let quotePrice;
1438
- if (strict) {
1439
- quotePrice = BN.max(
1440
- quoteOraclePriceData.price,
1441
- quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
1442
- );
1443
- } else {
1444
- quotePrice = quoteOraclePriceData.price;
1445
- }
1446
-
1447
- liabilityValue = liabilityValue
1448
- .mul(quotePrice)
1449
- .div(PRICE_PRECISION)
1450
- .mul(marginRatio)
1451
- .div(MARGIN_PRECISION);
1452
-
1453
- if (includeOpenOrders) {
1454
- liabilityValue = liabilityValue.add(
1455
- new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
1456
- );
1457
- }
1458
- }
1459
-
1460
- return liabilityValue;
1461
- }
1462
-
1463
- /**
1464
- * calculates position value of a single perp market in margin system
1465
- * @returns : Precision QUOTE_PRECISION
1466
- */
1467
- public getPerpMarketLiabilityValue(
1468
- marketIndex: number,
1469
- marginCategory?: MarginCategory,
1470
- liquidationBuffer?: BN,
1471
- includeOpenOrders?: boolean,
1472
- strict = false
1473
- ): BN {
1474
- const perpPosition = this.getPerpPositionOrThrow(marketIndex);
1475
- return this.calculateWeightedPerpPositionLiability(
1476
- perpPosition,
1477
- marginCategory,
1478
- liquidationBuffer,
1479
- includeOpenOrders,
1480
- strict
1481
- );
1482
- }
1483
-
1484
- /**
1485
- * calculates sum of position value across all positions in margin system
1486
- * @returns : Precision QUOTE_PRECISION
1487
- */
1488
- getTotalPerpPositionLiability(
1489
- marginCategory?: MarginCategory,
1490
- liquidationBuffer?: BN,
1491
- includeOpenOrders?: boolean,
1492
- strict = false
1493
- ): BN {
1494
- return this.getActivePerpPositions().reduce(
1495
- (totalPerpValue, perpPosition) => {
1496
- const baseAssetValue = this.calculateWeightedPerpPositionLiability(
1497
- perpPosition,
1498
- marginCategory,
1499
- liquidationBuffer,
1500
- includeOpenOrders,
1501
- strict
1502
- );
1503
- return totalPerpValue.add(baseAssetValue);
1504
- },
1505
- ZERO
1506
- );
1507
- }
1508
-
1509
- /**
1510
- * calculates position value based on oracle
1511
- * @returns : Precision QUOTE_PRECISION
1512
- */
1513
- public getPerpPositionValue(
1514
- marketIndex: number,
1515
- oraclePriceData: Pick<OraclePriceData, 'price'>,
1516
- includeOpenOrders = false
1517
- ): BN {
1518
- const userPosition = this.getPerpPositionOrEmpty(marketIndex);
1519
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
1520
- userPosition.marketIndex
1521
- );
1522
- return calculateBaseAssetValueWithOracle(
1523
- market,
1524
- userPosition,
1525
- oraclePriceData,
1526
- includeOpenOrders
1527
- );
1528
- }
1529
-
1530
- /**
1531
- * calculates position liabiltiy value in margin system
1532
- * @returns : Precision QUOTE_PRECISION
1533
- */
1534
- public getPerpLiabilityValue(
1535
- marketIndex: number,
1536
- oraclePriceData: OraclePriceData,
1537
- includeOpenOrders = false
1538
- ): BN {
1539
- const userPosition = this.getPerpPositionOrEmpty(marketIndex);
1540
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
1541
- userPosition.marketIndex
1542
- );
1543
-
1544
- if (includeOpenOrders) {
1545
- return calculateWorstCasePerpLiabilityValue(
1546
- userPosition,
1547
- market,
1548
- oraclePriceData.price
1549
- ).worstCaseLiabilityValue;
1550
- } else {
1551
- return calculatePerpLiabilityValue(
1552
- userPosition.baseAssetAmount,
1553
- oraclePriceData.price
1554
- );
1555
- }
1556
- }
1557
-
1558
- public getPositionSide(
1559
- currentPosition: Pick<PerpPosition, 'baseAssetAmount'>
1560
- ): PositionDirection | undefined {
1561
- if (currentPosition.baseAssetAmount.gt(ZERO)) {
1562
- return PositionDirection.LONG;
1563
- } else if (currentPosition.baseAssetAmount.lt(ZERO)) {
1564
- return PositionDirection.SHORT;
1565
- } else {
1566
- return undefined;
1567
- }
1568
- }
1569
-
1570
- /**
1571
- * calculates average exit price (optionally for closing up to 100% of position)
1572
- * @returns : Precision PRICE_PRECISION
1573
- */
1574
- public getPositionEstimatedExitPriceAndPnl(
1575
- position: PerpPosition,
1576
- amountToClose?: BN,
1577
- useAMMClose = false
1578
- ): [BN, BN] {
1579
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
1580
- position.marketIndex
1581
- );
1582
-
1583
- const entryPrice = calculateEntryPrice(position);
1584
-
1585
- const oraclePriceData = this.getMMOracleDataForPerpMarket(
1586
- position.marketIndex
1587
- );
1588
-
1589
- if (amountToClose) {
1590
- if (amountToClose.eq(ZERO)) {
1591
- return [calculateReservePrice(market, oraclePriceData), ZERO];
1592
- }
1593
- position = {
1594
- baseAssetAmount: amountToClose,
1595
- lastCumulativeFundingRate: position.lastCumulativeFundingRate,
1596
- marketIndex: position.marketIndex,
1597
- quoteAssetAmount: position.quoteAssetAmount,
1598
- } as PerpPosition;
1599
- }
1600
-
1601
- let baseAssetValue: BN;
1602
-
1603
- if (useAMMClose) {
1604
- baseAssetValue = calculateBaseAssetValue(
1605
- market,
1606
- position,
1607
- oraclePriceData
1608
- );
1609
- } else {
1610
- baseAssetValue = calculateBaseAssetValueWithOracle(
1611
- market,
1612
- position,
1613
- oraclePriceData
1614
- );
1615
- }
1616
- if (position.baseAssetAmount.eq(ZERO)) {
1617
- return [ZERO, ZERO];
1618
- }
1619
-
1620
- const exitPrice = baseAssetValue
1621
- .mul(AMM_TO_QUOTE_PRECISION_RATIO)
1622
- .mul(PRICE_PRECISION)
1623
- .div(position.baseAssetAmount.abs());
1624
-
1625
- const pnlPerBase = exitPrice.sub(entryPrice);
1626
- const pnl = pnlPerBase
1627
- .mul(position.baseAssetAmount)
1628
- .div(PRICE_PRECISION)
1629
- .div(AMM_TO_QUOTE_PRECISION_RATIO);
1630
-
1631
- return [exitPrice, pnl];
1632
- }
1633
-
1634
- /**
1635
- * calculates current user leverage which is (total liability size) / (net asset value)
1636
- * @returns : Precision TEN_THOUSAND
1637
- */
1638
- public getLeverage(includeOpenOrders = true, perpMarketIndex?: number): BN {
1639
- return this.calculateLeverageFromComponents(
1640
- this.getLeverageComponents(includeOpenOrders, undefined, perpMarketIndex)
1641
- );
1642
- }
1643
-
1644
- calculateLeverageFromComponents({
1645
- perpLiabilityValue,
1646
- perpPnl,
1647
- spotAssetValue,
1648
- spotLiabilityValue,
1649
- }: {
1650
- perpLiabilityValue: BN;
1651
- perpPnl: BN;
1652
- spotAssetValue: BN;
1653
- spotLiabilityValue: BN;
1654
- }): BN {
1655
- const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
1656
- const totalAssetValue = spotAssetValue.add(perpPnl);
1657
- const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
1658
-
1659
- if (netAssetValue.eq(ZERO)) {
1660
- return ZERO;
1661
- }
1662
-
1663
- return totalLiabilityValue.mul(TEN_THOUSAND).div(netAssetValue);
1664
- }
1665
-
1666
- getLeverageComponents(
1667
- includeOpenOrders = true,
1668
- marginCategory: MarginCategory | undefined = undefined,
1669
- perpMarketIndex?: number
1670
- ): {
1671
- perpLiabilityValue: BN;
1672
- perpPnl: BN;
1673
- spotAssetValue: BN;
1674
- spotLiabilityValue: BN;
1675
- } {
1676
- if (perpMarketIndex) {
1677
- const perpPosition = this.getPerpPositionOrEmpty(perpMarketIndex);
1678
- const perpLiability = this.calculateWeightedPerpPositionLiability(
1679
- perpPosition,
1680
- marginCategory,
1681
- undefined,
1682
- includeOpenOrders
1683
- );
1684
- const perpMarket = this.velocityClient.getPerpMarketAccountOrThrow(
1685
- perpPosition.marketIndex
1686
- );
1687
-
1688
- const oraclePriceData = this.getOracleDataForPerpMarket(
1689
- perpPosition.marketIndex
1690
- );
1691
- const quoteSpotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
1692
- perpMarket.quoteSpotMarketIndex
1693
- );
1694
- const quoteOraclePriceData = this.getOracleDataForSpotMarket(
1695
- perpMarket.quoteSpotMarketIndex
1696
- );
1697
- const strictOracle = new StrictOraclePrice(
1698
- quoteOraclePriceData.price,
1699
- quoteOraclePriceData.twap
1700
- );
1701
-
1702
- const positionUnrealizedPnl = calculatePositionPNL(
1703
- perpMarket,
1704
- perpPosition,
1705
- true,
1706
- oraclePriceData
1707
- );
1708
-
1709
- const tokenAmount = getTokenAmount(
1710
- perpPosition.isolatedPositionScaledBalance ?? ZERO,
1711
- quoteSpotMarket,
1712
- SpotBalanceType.DEPOSIT
1713
- );
1714
-
1715
- const spotAssetValue = getStrictTokenValue(
1716
- tokenAmount,
1717
- quoteSpotMarket.decimals,
1718
- strictOracle
1719
- );
1720
-
1721
- return {
1722
- perpLiabilityValue: perpLiability,
1723
- perpPnl: positionUnrealizedPnl,
1724
- spotAssetValue,
1725
- spotLiabilityValue: ZERO,
1726
- };
1727
- }
1728
-
1729
- const perpLiability = this.getTotalPerpPositionLiability(
1730
- marginCategory,
1731
- undefined,
1732
- includeOpenOrders
1733
- );
1734
- const perpPnl = this.getUnrealizedPNL(true, undefined, marginCategory);
1735
-
1736
- const {
1737
- totalAssetValue: spotAssetValue,
1738
- totalLiabilityValue: spotLiabilityValue,
1739
- } = this.getSpotMarketAssetAndLiabilityValue(
1740
- undefined,
1741
- marginCategory,
1742
- undefined,
1743
- includeOpenOrders
1744
- );
1745
-
1746
- const isolatedDeposits =
1747
- marginCategory === undefined
1748
- ? this.getTotalIsolatedPositionDeposits()
1749
- : ZERO;
1750
-
1751
- return {
1752
- perpLiabilityValue: perpLiability,
1753
- perpPnl,
1754
- spotAssetValue: spotAssetValue.add(isolatedDeposits),
1755
- spotLiabilityValue,
1756
- };
1757
- }
1758
-
1759
- isDustDepositPosition(spotMarketAccount: SpotMarketAccount): boolean {
1760
- const marketIndex = spotMarketAccount.marketIndex;
1761
-
1762
- const spotPosition = this.getSpotPosition(spotMarketAccount.marketIndex);
1763
-
1764
- if (!spotPosition) {
1765
- throw new Error(
1766
- `No spot position found for market ${spotMarketAccount.marketIndex}`
1767
- );
1768
- }
1769
-
1770
- if (isSpotPositionAvailable(spotPosition)) {
1771
- return false;
1772
- }
1773
-
1774
- const depositAmount = this.getTokenAmount(spotMarketAccount.marketIndex);
1775
-
1776
- if (depositAmount.lte(ZERO)) {
1777
- return false;
1778
- }
1779
-
1780
- const oraclePriceData = this.getOracleDataForSpotMarket(marketIndex);
1781
-
1782
- const strictOraclePrice = new StrictOraclePrice(
1783
- oraclePriceData.price,
1784
- oraclePriceData.twap
1785
- );
1786
-
1787
- const balanceValue = this.getSpotAssetValue(
1788
- depositAmount,
1789
- strictOraclePrice,
1790
- spotMarketAccount
1791
- );
1792
-
1793
- if (balanceValue.lt(DUST_POSITION_SIZE)) {
1794
- return true;
1795
- }
1796
-
1797
- return false;
1798
- }
1799
-
1800
- getSpotMarketAccountsWithDustPosition() {
1801
- const spotMarketAccounts = this.velocityClient.getSpotMarketAccounts();
1802
-
1803
- const dustPositionAccounts: SpotMarketAccount[] = [];
1804
-
1805
- for (const spotMarketAccount of spotMarketAccounts) {
1806
- const isDust = this.isDustDepositPosition(spotMarketAccount);
1807
- if (isDust) {
1808
- dustPositionAccounts.push(spotMarketAccount);
1809
- }
1810
- }
1811
-
1812
- return dustPositionAccounts;
1813
- }
1814
-
1815
- getTotalLiabilityValue(marginCategory?: MarginCategory): BN {
1816
- return this.getTotalPerpPositionLiability(
1817
- marginCategory,
1818
- undefined,
1819
- true
1820
- ).add(
1821
- this.getSpotMarketLiabilityValue(
1822
- undefined,
1823
- marginCategory,
1824
- undefined,
1825
- true
1826
- )
1827
- );
1828
- }
1829
-
1830
- getTotalAssetValue(marginCategory?: MarginCategory): BN {
1831
- const value = this.getSpotMarketAssetValue(
1832
- undefined,
1833
- marginCategory,
1834
- true
1835
- ).add(this.getUnrealizedPNL(true, undefined, marginCategory));
1836
- if (marginCategory === undefined) {
1837
- return value.add(this.getTotalIsolatedPositionDeposits());
1838
- }
1839
- return value;
1840
- }
1841
-
1842
- getNetUsdValue(): BN {
1843
- const netSpotValue = this.getNetSpotMarketValue();
1844
- const unrealizedPnl = this.getUnrealizedPNL(true, undefined, undefined);
1845
- const isolatedDeposits = this.getTotalIsolatedPositionDeposits();
1846
- return netSpotValue.add(unrealizedPnl).add(isolatedDeposits);
1847
- }
1848
-
1849
- /**
1850
- * Calculates the all time P&L of the user.
1851
- *
1852
- * Net withdraws + Net spot market value + Net unrealized P&L -
1853
- */
1854
- getTotalAllTimePnl(): BN {
1855
- const netUsdValue = this.getNetUsdValue();
1856
- const totalDeposits = this.getUserAccountOrThrow().totalDeposits;
1857
- const totalWithdraws = this.getUserAccountOrThrow().totalWithdraws;
1858
-
1859
- const totalPnl = netUsdValue.add(totalWithdraws).sub(totalDeposits);
1860
-
1861
- return totalPnl;
1862
- }
1863
-
1864
- /**
1865
- * calculates max allowable leverage exceeding hitting requirement category
1866
- * for large sizes where imf factor activates, result is a lower bound
1867
- * @param marginCategory {Initial, Maintenance}
1868
- * @returns : Precision TEN_THOUSAND
1869
- */
1870
- public getMaxLeverageForPerp(
1871
- perpMarketIndex: number,
1872
- _marginCategory: MarginCategory = 'Initial'
1873
- ): BN {
1874
- const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
1875
- this.getLeverageComponents();
1876
-
1877
- const totalAssetValue = spotAssetValue.add(perpPnl);
1878
-
1879
- const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
1880
-
1881
- if (netAssetValue.eq(ZERO)) {
1882
- return ZERO;
1883
- }
1884
-
1885
- const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
1886
-
1887
- // absolute max fesible size (upper bound)
1888
- const maxSizeQuote = BN.max(
1889
- BN.min(
1890
- this.getMaxTradeSizeUSDCForPerp(perpMarketIndex, PositionDirection.LONG)
1891
- .tradeSize,
1892
- this.getMaxTradeSizeUSDCForPerp(
1893
- perpMarketIndex,
1894
- PositionDirection.SHORT
1895
- ).tradeSize
1896
- ),
1897
- ZERO
1898
- );
1899
-
1900
- return totalLiabilityValue
1901
- .add(maxSizeQuote)
1902
- .mul(TEN_THOUSAND)
1903
- .div(netAssetValue);
1904
- }
1905
-
1906
- /**
1907
- * calculates max allowable leverage exceeding hitting requirement category
1908
- * @param spotMarketIndex
1909
- * @param direction
1910
- * @returns : Precision TEN_THOUSAND
1911
- */
1912
- public getMaxLeverageForSpot(
1913
- spotMarketIndex: number,
1914
- direction: PositionDirection
1915
- ): BN {
1916
- const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
1917
- this.getLeverageComponents();
1918
-
1919
- const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
1920
- const totalAssetValue = spotAssetValue.add(perpPnl);
1921
-
1922
- const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
1923
-
1924
- if (netAssetValue.eq(ZERO)) {
1925
- return ZERO;
1926
- }
1927
-
1928
- const currentQuoteAssetValue = this.getSpotMarketAssetValue(
1929
- QUOTE_SPOT_MARKET_INDEX
1930
- );
1931
- const currentQuoteLiabilityValue = this.getSpotMarketLiabilityValue(
1932
- QUOTE_SPOT_MARKET_INDEX
1933
- );
1934
- const currentQuoteValue = currentQuoteAssetValue.sub(
1935
- currentQuoteLiabilityValue
1936
- );
1937
-
1938
- const currentSpotMarketAssetValue =
1939
- this.getSpotMarketAssetValue(spotMarketIndex);
1940
- const currentSpotMarketLiabilityValue =
1941
- this.getSpotMarketLiabilityValue(spotMarketIndex);
1942
- const currentSpotMarketNetValue = currentSpotMarketAssetValue.sub(
1943
- currentSpotMarketLiabilityValue
1944
- );
1945
-
1946
- const tradeQuoteAmount = this.getMaxTradeSizeUSDCForSpot(
1947
- spotMarketIndex,
1948
- direction,
1949
- currentQuoteAssetValue,
1950
- currentSpotMarketNetValue
1951
- );
1952
-
1953
- let assetValueToAdd = ZERO;
1954
- let liabilityValueToAdd = ZERO;
1955
-
1956
- const newQuoteNetValue = isVariant(direction, 'short')
1957
- ? currentQuoteValue.add(tradeQuoteAmount)
1958
- : currentQuoteValue.sub(tradeQuoteAmount);
1959
- const newQuoteAssetValue = BN.max(newQuoteNetValue, ZERO);
1960
- const newQuoteLiabilityValue = BN.min(newQuoteNetValue, ZERO).abs();
1961
-
1962
- assetValueToAdd = assetValueToAdd.add(
1963
- newQuoteAssetValue.sub(currentQuoteAssetValue)
1964
- );
1965
- liabilityValueToAdd = liabilityValueToAdd.add(
1966
- newQuoteLiabilityValue.sub(currentQuoteLiabilityValue)
1967
- );
1968
-
1969
- const newSpotMarketNetValue = isVariant(direction, 'long')
1970
- ? currentSpotMarketNetValue.add(tradeQuoteAmount)
1971
- : currentSpotMarketNetValue.sub(tradeQuoteAmount);
1972
- const newSpotMarketAssetValue = BN.max(newSpotMarketNetValue, ZERO);
1973
- const newSpotMarketLiabilityValue = BN.min(
1974
- newSpotMarketNetValue,
1975
- ZERO
1976
- ).abs();
1977
-
1978
- assetValueToAdd = assetValueToAdd.add(
1979
- newSpotMarketAssetValue.sub(currentSpotMarketAssetValue)
1980
- );
1981
- liabilityValueToAdd = liabilityValueToAdd.add(
1982
- newSpotMarketLiabilityValue.sub(currentSpotMarketLiabilityValue)
1983
- );
1984
-
1985
- const finalTotalAssetValue = totalAssetValue.add(assetValueToAdd);
1986
- const finalTotalSpotLiability = spotLiabilityValue.add(liabilityValueToAdd);
1987
-
1988
- const finalTotalLiabilityValue =
1989
- totalLiabilityValue.add(liabilityValueToAdd);
1990
-
1991
- const finalNetAssetValue = finalTotalAssetValue.sub(
1992
- finalTotalSpotLiability
1993
- );
1994
-
1995
- return finalTotalLiabilityValue.mul(TEN_THOUSAND).div(finalNetAssetValue);
1996
- }
1997
-
1998
- /**
1999
- * calculates margin ratio: 1 / leverage
2000
- * @returns : Precision TEN_THOUSAND
2001
- */
2002
- public getMarginRatio(): BN {
2003
- const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
2004
- this.getLeverageComponents();
2005
-
2006
- const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
2007
- const totalAssetValue = spotAssetValue.add(perpPnl);
2008
-
2009
- if (totalLiabilityValue.eq(ZERO)) {
2010
- return BN_MAX;
2011
- }
2012
-
2013
- const netAssetValue = totalAssetValue.sub(spotLiabilityValue);
2014
-
2015
- return netAssetValue.mul(TEN_THOUSAND).div(totalLiabilityValue);
2016
- }
2017
-
2018
- public canBeLiquidated(): AccountLiquidatableStatus & {
2019
- isolatedPositions: Map<number, AccountLiquidatableStatus>;
2020
- } {
2021
- // Deprecated signature retained for backward compatibility in type only
2022
- // but implementation now delegates to the new Map-based API and returns cross margin status.
2023
- const map = this.getLiquidationStatuses();
2024
- const cross = map.get('cross');
2025
- const isolatedPositions: Map<number, AccountLiquidatableStatus> = new Map(
2026
- Array.from(map.entries())
2027
- .filter(
2028
- (e): e is [number, AccountLiquidatableStatus] => e[0] !== 'cross'
2029
- )
2030
- .map(([key, value]) => [key, value])
2031
- );
2032
- return cross
2033
- ? { ...cross, isolatedPositions }
2034
- : {
2035
- canBeLiquidated: false,
2036
- marginRequirement: ZERO,
2037
- totalCollateral: ZERO,
2038
- isolatedPositions,
2039
- };
2040
- }
2041
-
2042
- /**
2043
- * New API: Returns liquidation status for cross and each isolated perp position.
2044
- * Map keys:
2045
- * - 'cross' for cross margin
2046
- * - marketIndex (number) for each isolated perp position
2047
- */
2048
- public getLiquidationStatuses(
2049
- marginCalc?: MarginCalculation
2050
- ): Map<'cross' | number, AccountLiquidatableStatus> {
2051
- // If not provided, use buffer-aware calc for canBeLiquidated checks
2052
- if (!marginCalc) {
2053
- const liquidationBufferMap = this.getLiquidationBuffer();
2054
- marginCalc = this.getMarginCalculation('Maintenance', {
2055
- liquidationBufferMap,
2056
- });
2057
- }
2058
-
2059
- const result = new Map<'cross' | number, AccountLiquidatableStatus>();
2060
-
2061
- // Cross margin status
2062
- const crossTotalCollateral = marginCalc.totalCollateral;
2063
- const crossMarginRequirement = marginCalc.marginRequirement;
2064
- result.set('cross', {
2065
- canBeLiquidated: crossTotalCollateral.lt(crossMarginRequirement),
2066
- marginRequirement: crossMarginRequirement,
2067
- totalCollateral: crossTotalCollateral,
2068
- });
2069
-
2070
- // Isolated positions status
2071
- for (const [
2072
- marketIndex,
2073
- isoCalc,
2074
- ] of marginCalc.isolatedMarginCalculations) {
2075
- const isoTotalCollateral = isoCalc.totalCollateral;
2076
- const isoMarginRequirement = isoCalc.marginRequirement;
2077
- result.set(marketIndex, {
2078
- canBeLiquidated: isoTotalCollateral.lt(isoMarginRequirement),
2079
- marginRequirement: isoMarginRequirement,
2080
- totalCollateral: isoTotalCollateral,
2081
- });
2082
- }
2083
-
2084
- return result;
2085
- }
2086
-
2087
- public isBeingLiquidated(): boolean {
2088
- return (
2089
- this.isCrossMarginBeingLiquidated() ||
2090
- this.hasIsolatedPositionBeingLiquidated()
2091
- );
2092
- }
2093
-
2094
- public isCrossMarginBeingLiquidated(): boolean {
2095
- return (
2096
- (this.getUserAccountOrThrow().status &
2097
- (UserStatus.BEING_LIQUIDATED | UserStatus.BANKRUPT)) >
2098
- 0
2099
- );
2100
- }
2101
-
2102
- /** Returns true if cross margin is currently below maintenance requirement (no buffer). */
2103
- public canCrossMarginBeLiquidated(marginCalc?: MarginCalculation): boolean {
2104
- const calc = marginCalc ?? this.getMarginCalculation('Maintenance');
2105
- return calc.totalCollateral.lt(calc.marginRequirement);
2106
- }
2107
-
2108
- public hasIsolatedPositionBeingLiquidated(): boolean {
2109
- return this.getActivePerpPositions().some(
2110
- (position) =>
2111
- (position.positionFlag &
2112
- (PositionFlag.BeingLiquidated | PositionFlag.Bankruptcy)) >
2113
- 0
2114
- );
2115
- }
2116
-
2117
- public isIsolatedPositionBeingLiquidated(perpMarketIndex: number): boolean {
2118
- const position = this.getActivePerpPositions().find(
2119
- (position) => position.marketIndex === perpMarketIndex
2120
- );
2121
-
2122
- return (
2123
- ((position?.positionFlag ?? 0) &
2124
- (PositionFlag.BeingLiquidated | PositionFlag.Bankruptcy)) >
2125
- 0
2126
- );
2127
- }
2128
-
2129
- /** Returns true if any isolated perp position is currently below its maintenance requirement (no buffer). */
2130
- public getLiquidatableIsolatedPositions(
2131
- marginCalc?: MarginCalculation
2132
- ): number[] {
2133
- const liquidatableIsolatedPositions = [];
2134
- const calc = marginCalc ?? this.getMarginCalculation('Maintenance');
2135
- for (const [marketIndex, isoCalc] of calc.isolatedMarginCalculations) {
2136
- if (this.canIsolatedPositionMarginBeLiquidated(isoCalc)) {
2137
- liquidatableIsolatedPositions.push(marketIndex);
2138
- }
2139
- }
2140
- return liquidatableIsolatedPositions;
2141
- }
2142
-
2143
- public canIsolatedPositionMarginBeLiquidated(
2144
- isolatedMarginCalculation: IsolatedMarginCalculation
2145
- ): boolean {
2146
- return isolatedMarginCalculation.totalCollateral.lt(
2147
- isolatedMarginCalculation.marginRequirement
2148
- );
2149
- }
2150
-
2151
- public hasStatus(status: UserStatus): boolean {
2152
- return (this.getUserAccountOrThrow().status & status) > 0;
2153
- }
2154
-
2155
- public isBankrupt(): boolean {
2156
- return (this.getUserAccountOrThrow().status & UserStatus.BANKRUPT) > 0;
2157
- }
2158
-
2159
- /**
2160
- * Checks if any user position cumulative funding differs from respective market cumulative funding
2161
- * @returns
2162
- */
2163
- public needsToSettleFundingPayment(): boolean {
2164
- for (const userPosition of this.getUserAccountOrThrow().perpPositions) {
2165
- if (userPosition.baseAssetAmount.eq(ZERO)) {
2166
- continue;
2167
- }
2168
-
2169
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
2170
- userPosition.marketIndex
2171
- );
2172
- if (
2173
- market.cumulativeFundingRateLong.eq(
2174
- userPosition.lastCumulativeFundingRate
2175
- ) ||
2176
- market.cumulativeFundingRateShort.eq(
2177
- userPosition.lastCumulativeFundingRate
2178
- )
2179
- ) {
2180
- continue;
2181
- }
2182
-
2183
- return true;
2184
- }
2185
- return false;
2186
- }
2187
-
2188
- /**
2189
- * Calculate the liquidation price of a spot position
2190
- * @param marketIndex
2191
- * @returns Precision : PRICE_PRECISION
2192
- */
2193
- public spotLiquidationPrice(
2194
- marketIndex: number,
2195
- positionBaseSizeChange: BN = ZERO
2196
- ): BN {
2197
- const currentSpotPosition = this.getSpotPosition(marketIndex);
2198
-
2199
- if (!currentSpotPosition) {
2200
- return new BN(-1);
2201
- }
2202
-
2203
- const totalCollateral = this.getTotalCollateral('Maintenance');
2204
- const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
2205
- const freeCollateral = BN.max(
2206
- ZERO,
2207
- totalCollateral.sub(maintenanceMarginRequirement)
2208
- );
2209
-
2210
- const market = this.velocityClient.getSpotMarketAccountOrThrow(marketIndex);
2211
- let signedTokenAmount = getSignedTokenAmount(
2212
- getTokenAmount(
2213
- currentSpotPosition.scaledBalance,
2214
- market,
2215
- currentSpotPosition.balanceType
2216
- ),
2217
- currentSpotPosition.balanceType
2218
- );
2219
- signedTokenAmount = signedTokenAmount.add(positionBaseSizeChange);
2220
-
2221
- if (signedTokenAmount.eq(ZERO)) {
2222
- return new BN(-1);
2223
- }
2224
-
2225
- let freeCollateralDelta = this.calculateFreeCollateralDeltaForSpot(
2226
- market,
2227
- signedTokenAmount
2228
- );
2229
-
2230
- const oracle = market.oracle;
2231
- const perpMarketWithSameOracle = this.velocityClient
2232
- .getPerpMarketAccounts()
2233
- .find((market) => market.oracle.equals(oracle));
2234
- const oraclePrice =
2235
- this.velocityClient.getOracleDataForSpotMarket(marketIndex).price;
2236
- if (perpMarketWithSameOracle) {
2237
- const perpPosition = this.getPerpPositionOrEmpty(
2238
- perpMarketWithSameOracle.marketIndex
2239
- );
2240
- if (perpPosition) {
2241
- let freeCollateralDeltaForPerp =
2242
- this.calculateFreeCollateralDeltaForPerp(
2243
- perpMarketWithSameOracle,
2244
- perpPosition,
2245
- ZERO,
2246
- oraclePrice
2247
- );
2248
-
2249
- if (freeCollateralDeltaForPerp) {
2250
- const { numerator, denominator } = getMultipleBetweenOracleSources(
2251
- market.oracleSource,
2252
- perpMarketWithSameOracle.oracleSource
2253
- );
2254
- freeCollateralDeltaForPerp = freeCollateralDeltaForPerp
2255
- .mul(numerator)
2256
- .div(denominator);
2257
- }
2258
-
2259
- freeCollateralDelta = freeCollateralDelta.add(
2260
- freeCollateralDeltaForPerp || ZERO
2261
- );
2262
- }
2263
- }
2264
-
2265
- if (freeCollateralDelta.eq(ZERO)) {
2266
- return new BN(-1);
2267
- }
2268
-
2269
- const liqPriceDelta = freeCollateral
2270
- .mul(QUOTE_PRECISION)
2271
- .div(freeCollateralDelta);
2272
-
2273
- const liqPrice = oraclePrice.sub(liqPriceDelta);
2274
-
2275
- if (liqPrice.lt(ZERO)) {
2276
- return new BN(-1);
2277
- }
2278
-
2279
- return liqPrice;
2280
- }
2281
-
2282
- /**
2283
- * Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
2284
- * @param marketIndex
2285
- * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^9
2286
- * @param estimatedEntryPrice
2287
- * @param marginCategory // allow Initial to be passed in if we are trying to calculate price for DLP de-risking
2288
- * @param includeOpenOrders
2289
- * @param offsetCollateral // allows calculating the liquidation price after this offset collateral is added to the user's account (e.g. : what will the liquidation price be for this position AFTER I deposit $x worth of collateral)
2290
- * @returns Precision : PRICE_PRECISION
2291
- */
2292
- public liquidationPrice(
2293
- marketIndex: number,
2294
- positionBaseSizeChange: BN = ZERO,
2295
- estimatedEntryPrice: BN = ZERO,
2296
- marginCategory: MarginCategory = 'Maintenance',
2297
- includeOpenOrders = false,
2298
- offsetCollateral = ZERO,
2299
- marginType?: MarginType
2300
- ): BN {
2301
- const market = this.velocityClient.getPerpMarketAccountOrThrow(marketIndex);
2302
-
2303
- const oracle = market.oracle;
2304
-
2305
- const oraclePrice =
2306
- this.velocityClient.getOracleDataForPerpMarket(marketIndex).price;
2307
-
2308
- const currentPerpPosition = this.getPerpPositionOrEmpty(marketIndex);
2309
-
2310
- if (marginType === 'Isolated') {
2311
- const marginCalculation = this.getMarginCalculation(marginCategory, {
2312
- strict: false,
2313
- includeOpenOrders,
2314
- });
2315
- const isolatedMarginCalculation =
2316
- marginCalculation.isolatedMarginCalculations.get(marketIndex);
2317
- if (!isolatedMarginCalculation) return new BN(-1);
2318
- const { totalCollateral, marginRequirement } = isolatedMarginCalculation;
2319
-
2320
- const freeCollateral = BN.max(
2321
- ZERO,
2322
- totalCollateral.sub(marginRequirement)
2323
- ).add(offsetCollateral);
2324
-
2325
- const freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
2326
- market,
2327
- currentPerpPosition,
2328
- positionBaseSizeChange,
2329
- oraclePrice,
2330
- marginCategory,
2331
- includeOpenOrders
2332
- );
2333
-
2334
- if (!freeCollateralDelta || freeCollateralDelta.eq(ZERO)) {
2335
- return new BN(-1);
2336
- }
2337
-
2338
- const liqPriceDelta = freeCollateral
2339
- .mul(QUOTE_PRECISION)
2340
- .div(freeCollateralDelta);
2341
-
2342
- const liqPrice = oraclePrice.sub(liqPriceDelta);
2343
-
2344
- if (liqPrice.lt(ZERO)) {
2345
- return new BN(-1);
2346
- }
2347
-
2348
- return liqPrice;
2349
- }
2350
-
2351
- const totalCollateral = this.getTotalCollateral(
2352
- marginCategory,
2353
- false,
2354
- includeOpenOrders
2355
- );
2356
-
2357
- const marginRequirement = this.getMarginRequirement(
2358
- marginCategory,
2359
- undefined,
2360
- false,
2361
- includeOpenOrders
2362
- );
2363
-
2364
- let freeCollateral = BN.max(
2365
- ZERO,
2366
- totalCollateral.sub(marginRequirement)
2367
- ).add(offsetCollateral);
2368
-
2369
- positionBaseSizeChange = standardizeBaseAssetAmount(
2370
- positionBaseSizeChange,
2371
- market.orderStepSize
2372
- );
2373
-
2374
- const freeCollateralChangeFromNewPosition =
2375
- this.calculateEntriesEffectOnFreeCollateral(
2376
- market,
2377
- oraclePrice,
2378
- currentPerpPosition,
2379
- positionBaseSizeChange,
2380
- estimatedEntryPrice,
2381
- includeOpenOrders
2382
- );
2383
-
2384
- freeCollateral = freeCollateral.add(freeCollateralChangeFromNewPosition);
2385
-
2386
- let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
2387
- market,
2388
- currentPerpPosition,
2389
- positionBaseSizeChange,
2390
- oraclePrice,
2391
- marginCategory,
2392
- includeOpenOrders
2393
- );
2394
-
2395
- if (!freeCollateralDelta) {
2396
- return new BN(-1);
2397
- }
2398
-
2399
- const spotMarketWithSameOracle = this.velocityClient
2400
- .getSpotMarketAccounts()
2401
- .find((market) => market.oracle.equals(oracle));
2402
- if (spotMarketWithSameOracle) {
2403
- const spotPosition = this.getSpotPosition(
2404
- spotMarketWithSameOracle.marketIndex
2405
- );
2406
- if (spotPosition) {
2407
- const signedTokenAmount = getSignedTokenAmount(
2408
- getTokenAmount(
2409
- spotPosition.scaledBalance,
2410
- spotMarketWithSameOracle,
2411
- spotPosition.balanceType
2412
- ),
2413
- spotPosition.balanceType
2414
- );
2415
-
2416
- let spotFreeCollateralDelta = this.calculateFreeCollateralDeltaForSpot(
2417
- spotMarketWithSameOracle,
2418
- signedTokenAmount,
2419
- marginCategory
2420
- );
2421
-
2422
- if (spotFreeCollateralDelta) {
2423
- const { numerator, denominator } = getMultipleBetweenOracleSources(
2424
- market.oracleSource,
2425
- spotMarketWithSameOracle.oracleSource
2426
- );
2427
- spotFreeCollateralDelta = spotFreeCollateralDelta
2428
- .mul(numerator)
2429
- .div(denominator);
2430
- }
2431
-
2432
- freeCollateralDelta = freeCollateralDelta.add(
2433
- spotFreeCollateralDelta || ZERO
2434
- );
2435
- }
2436
- }
2437
-
2438
- if (freeCollateralDelta.eq(ZERO)) {
2439
- return new BN(-1);
2440
- }
2441
-
2442
- const liqPriceDelta = freeCollateral
2443
- .mul(QUOTE_PRECISION)
2444
- .div(freeCollateralDelta);
2445
-
2446
- const liqPrice = oraclePrice.sub(liqPriceDelta);
2447
-
2448
- if (liqPrice.lt(ZERO)) {
2449
- return new BN(-1);
2450
- }
2451
-
2452
- return liqPrice;
2453
- }
2454
-
2455
- calculateEntriesEffectOnFreeCollateral(
2456
- market: PerpMarketAccount,
2457
- oraclePrice: BN,
2458
- perpPosition: PerpPosition,
2459
- positionBaseSizeChange: BN,
2460
- estimatedEntryPrice: BN,
2461
- includeOpenOrders: boolean,
2462
- marginCategory: MarginCategory = 'Maintenance'
2463
- ): BN {
2464
- let freeCollateralChange = ZERO;
2465
-
2466
- // update free collateral to account for change in pnl from new position
2467
- if (
2468
- !estimatedEntryPrice.eq(ZERO) &&
2469
- !positionBaseSizeChange.eq(ZERO) &&
2470
- marginCategory === 'Maintenance'
2471
- ) {
2472
- const costBasis = oraclePrice
2473
- .mul(positionBaseSizeChange.abs())
2474
- .div(BASE_PRECISION);
2475
- const newPositionValue = estimatedEntryPrice
2476
- .mul(positionBaseSizeChange.abs())
2477
- .div(BASE_PRECISION);
2478
- if (positionBaseSizeChange.gt(ZERO)) {
2479
- freeCollateralChange = costBasis.sub(newPositionValue);
2480
- } else {
2481
- freeCollateralChange = newPositionValue.sub(costBasis);
2482
- }
2483
-
2484
- // assume worst fee tier
2485
- const takerFeeTier =
2486
- this.velocityClient.getStateAccount().perpFeeStructure.feeTiers[0];
2487
- const takerFee = newPositionValue
2488
- .muln(takerFeeTier.feeNumerator)
2489
- .divn(takerFeeTier.feeDenominator);
2490
- freeCollateralChange = freeCollateralChange.sub(takerFee);
2491
- }
2492
-
2493
- const calculateMarginRequirement = (perpPosition: PerpPosition) => {
2494
- let baseAssetAmount: BN;
2495
- let liabilityValue: BN;
2496
- if (includeOpenOrders) {
2497
- const { worstCaseBaseAssetAmount, worstCaseLiabilityValue } =
2498
- calculateWorstCasePerpLiabilityValue(
2499
- perpPosition,
2500
- market,
2501
- oraclePrice
2502
- );
2503
- baseAssetAmount = worstCaseBaseAssetAmount;
2504
- liabilityValue = worstCaseLiabilityValue;
2505
- } else {
2506
- baseAssetAmount = perpPosition.baseAssetAmount;
2507
- liabilityValue = calculatePerpLiabilityValue(
2508
- baseAssetAmount,
2509
- oraclePrice
2510
- );
2511
- }
2512
-
2513
- const userCustomMargin = Math.max(
2514
- perpPosition.maxMarginRatio,
2515
- this.getUserAccountOrThrow().maxMarginRatio
2516
- );
2517
- const marginRatio = calculateMarketMarginRatio(
2518
- market,
2519
- baseAssetAmount.abs(),
2520
- marginCategory,
2521
- userCustomMargin
2522
- );
2523
-
2524
- return liabilityValue.mul(new BN(marginRatio)).div(MARGIN_PRECISION);
2525
- };
2526
-
2527
- const freeCollateralConsumptionBefore =
2528
- calculateMarginRequirement(perpPosition);
2529
-
2530
- const perpPositionAfter = Object.assign({}, perpPosition);
2531
- perpPositionAfter.baseAssetAmount = perpPositionAfter.baseAssetAmount.add(
2532
- positionBaseSizeChange
2533
- );
2534
-
2535
- const freeCollateralConsumptionAfter =
2536
- calculateMarginRequirement(perpPositionAfter);
2537
-
2538
- return freeCollateralChange.sub(
2539
- freeCollateralConsumptionAfter.sub(freeCollateralConsumptionBefore)
2540
- );
2541
- }
2542
-
2543
- calculateFreeCollateralDeltaForPerp(
2544
- market: PerpMarketAccount,
2545
- perpPosition: PerpPosition,
2546
- positionBaseSizeChange: BN,
2547
- oraclePrice: BN,
2548
- marginCategory: MarginCategory = 'Maintenance',
2549
- includeOpenOrders = false
2550
- ): BN | undefined {
2551
- const baseAssetAmount = includeOpenOrders
2552
- ? calculateWorstCaseBaseAssetAmount(perpPosition, market, oraclePrice)
2553
- : perpPosition.baseAssetAmount;
2554
-
2555
- // zero if include orders == false
2556
- const orderBaseAssetAmount = baseAssetAmount.sub(
2557
- perpPosition.baseAssetAmount
2558
- );
2559
-
2560
- const proposedBaseAssetAmount = baseAssetAmount.add(positionBaseSizeChange);
2561
-
2562
- const userCustomMargin = Math.max(
2563
- perpPosition.maxMarginRatio,
2564
- this.getUserAccountOrThrow().maxMarginRatio
2565
- );
2566
-
2567
- const marginRatio = calculateMarketMarginRatio(
2568
- market,
2569
- proposedBaseAssetAmount.abs(),
2570
- marginCategory,
2571
- userCustomMargin
2572
- );
2573
-
2574
- const marginRatioQuotePrecision = new BN(marginRatio)
2575
- .mul(QUOTE_PRECISION)
2576
- .div(MARGIN_PRECISION);
2577
-
2578
- if (proposedBaseAssetAmount.eq(ZERO)) {
2579
- return undefined;
2580
- }
2581
-
2582
- let freeCollateralDelta = ZERO;
2583
-
2584
- if (proposedBaseAssetAmount.gt(ZERO)) {
2585
- freeCollateralDelta = QUOTE_PRECISION.sub(marginRatioQuotePrecision)
2586
- .mul(proposedBaseAssetAmount)
2587
- .div(BASE_PRECISION);
2588
- } else {
2589
- freeCollateralDelta = QUOTE_PRECISION.neg()
2590
- .sub(marginRatioQuotePrecision)
2591
- .mul(proposedBaseAssetAmount.abs())
2592
- .div(BASE_PRECISION);
2593
- }
2594
-
2595
- if (!orderBaseAssetAmount.eq(ZERO)) {
2596
- freeCollateralDelta = freeCollateralDelta.sub(
2597
- marginRatioQuotePrecision
2598
- .mul(orderBaseAssetAmount.abs())
2599
- .div(BASE_PRECISION)
2600
- );
2601
- }
2602
-
2603
- return freeCollateralDelta;
2604
- }
2605
-
2606
- calculateFreeCollateralDeltaForSpot(
2607
- market: SpotMarketAccount,
2608
- signedTokenAmount: BN,
2609
- marginCategory: MarginCategory = 'Maintenance'
2610
- ): BN {
2611
- const tokenPrecision = new BN(Math.pow(10, market.decimals));
2612
-
2613
- if (signedTokenAmount.gt(ZERO)) {
2614
- const assetWeight = calculateAssetWeight(
2615
- signedTokenAmount,
2616
- this.velocityClient.getOracleDataForSpotMarket(market.marketIndex)
2617
- .price,
2618
- market,
2619
- marginCategory
2620
- );
2621
-
2622
- return QUOTE_PRECISION.mul(assetWeight)
2623
- .div(SPOT_MARKET_WEIGHT_PRECISION)
2624
- .mul(signedTokenAmount)
2625
- .div(tokenPrecision);
2626
- } else {
2627
- const liabilityWeight = calculateLiabilityWeight(
2628
- signedTokenAmount.abs(),
2629
- market,
2630
- marginCategory
2631
- );
2632
-
2633
- return QUOTE_PRECISION.neg()
2634
- .mul(liabilityWeight)
2635
- .div(SPOT_MARKET_WEIGHT_PRECISION)
2636
- .mul(signedTokenAmount.abs())
2637
- .div(tokenPrecision);
2638
- }
2639
- }
2640
-
2641
- /**
2642
- * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
2643
- * @param positionMarketIndex
2644
- * @param closeQuoteAmount
2645
- * @returns : Precision PRICE_PRECISION
2646
- */
2647
- public liquidationPriceAfterClose(
2648
- positionMarketIndex: number,
2649
- closeQuoteAmount: BN,
2650
- estimatedEntryPrice: BN = ZERO
2651
- ): BN {
2652
- const currentPosition = this.getPerpPositionOrEmpty(positionMarketIndex);
2653
-
2654
- const closeBaseAmount = currentPosition.baseAssetAmount
2655
- .mul(closeQuoteAmount)
2656
- .div(currentPosition.quoteAssetAmount.abs())
2657
- .add(
2658
- currentPosition.baseAssetAmount
2659
- .mul(closeQuoteAmount)
2660
- .mod(currentPosition.quoteAssetAmount.abs())
2661
- )
2662
- .neg();
2663
-
2664
- return this.liquidationPrice(
2665
- positionMarketIndex,
2666
- closeBaseAmount,
2667
- estimatedEntryPrice
2668
- );
2669
- }
2670
-
2671
- public getMarginUSDCRequiredForTrade(
2672
- targetMarketIndex: number,
2673
- baseSize: BN,
2674
- estEntryPrice?: BN,
2675
- perpMarketMaxMarginRatio?: number
2676
- ): BN {
2677
- const maxMarginRatio = this.resolveMaxMarginRatio(perpMarketMaxMarginRatio);
2678
- return calculateMarginUSDCRequiredForTrade(
2679
- this.velocityClient,
2680
- targetMarketIndex,
2681
- baseSize,
2682
- maxMarginRatio,
2683
- estEntryPrice
2684
- );
2685
- }
2686
-
2687
- public getCollateralDepositRequiredForTrade(
2688
- targetMarketIndex: number,
2689
- baseSize: BN,
2690
- collateralIndex: number,
2691
- perpMarketMaxMarginRatio?: number
2692
- ): BN {
2693
- const maxMarginRatio = this.resolveMaxMarginRatio(perpMarketMaxMarginRatio);
2694
- return calculateCollateralDepositRequiredForTrade(
2695
- this.velocityClient,
2696
- targetMarketIndex,
2697
- baseSize,
2698
- collateralIndex,
2699
- maxMarginRatio
2700
- );
2701
- }
2702
-
2703
- /**
2704
- * Separates the max trade size into two parts:
2705
- * - tradeSize: The maximum trade size for target direction
2706
- * - oppositeSideTradeSize: the trade size for closing the opposite direction
2707
- * @param targetMarketIndex
2708
- * @param tradeSide
2709
- * @returns { tradeSize: BN, oppositeSideTradeSize: BN} : Precision QUOTE_PRECISION
2710
- */
2711
- public getMaxTradeSizeUSDCForPerp(
2712
- targetMarketIndex: number,
2713
- tradeSide: PositionDirection,
2714
- maxMarginRatio: number | undefined = undefined,
2715
- positionType: 'isolated' | 'cross' = 'cross'
2716
- ): { tradeSize: BN; oppositeSideTradeSize: BN } {
2717
- let tradeSize = ZERO;
2718
- let oppositeSideTradeSize = ZERO;
2719
- const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
2720
-
2721
- const targetSide = isVariant(tradeSide, 'short') ? 'short' : 'long';
2722
-
2723
- const currentPositionSide = currentPosition?.baseAssetAmount.isNeg()
2724
- ? 'short'
2725
- : 'long';
2726
-
2727
- const targetingSameSide = !currentPosition
2728
- ? true
2729
- : targetSide === currentPositionSide;
2730
-
2731
- const oracleData = this.getMMOracleDataForPerpMarket(targetMarketIndex);
2732
-
2733
- const marketAccount =
2734
- this.velocityClient.getPerpMarketAccountOrThrow(targetMarketIndex);
2735
-
2736
- // add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
2737
- const oppositeSizeLiabilityValue = targetingSameSide
2738
- ? ZERO
2739
- : calculatePerpLiabilityValue(
2740
- currentPosition.baseAssetAmount,
2741
- oracleData.price
2742
- );
2743
-
2744
- const maxPositionSize = this.getPerpBuyingPower(
2745
- targetMarketIndex,
2746
- ZERO,
2747
- maxMarginRatio,
2748
- positionType
2749
- );
2750
-
2751
- if (maxPositionSize.gte(ZERO)) {
2752
- if (oppositeSizeLiabilityValue.eq(ZERO)) {
2753
- // case 1 : Regular trade where current total position less than max, and no opposite position to account for
2754
- // do nothing
2755
- tradeSize = maxPositionSize;
2756
- } else {
2757
- // case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
2758
- tradeSize = maxPositionSize.add(oppositeSizeLiabilityValue);
2759
- oppositeSideTradeSize = oppositeSizeLiabilityValue;
2760
- }
2761
- } else {
2762
- // current leverage is greater than max leverage - can only reduce position size
2763
-
2764
- if (!targetingSameSide) {
2765
- const perpLiabilityValue = calculatePerpLiabilityValue(
2766
- currentPosition.baseAssetAmount,
2767
- oracleData.price
2768
- );
2769
- const totalCollateral = this.getTotalCollateral();
2770
- const marginRequirement = this.getInitialMarginRequirement();
2771
- const marginRatio = Math.max(
2772
- currentPosition.maxMarginRatio,
2773
- this.getUserAccountOrThrow().maxMarginRatio
2774
- );
2775
- const marginFreedByClosing = perpLiabilityValue
2776
- .mul(new BN(marginRatio))
2777
- .div(MARGIN_PRECISION);
2778
- const marginRequirementAfterClosing =
2779
- marginRequirement.sub(marginFreedByClosing);
2780
-
2781
- if (marginRequirementAfterClosing.gt(totalCollateral)) {
2782
- oppositeSideTradeSize = perpLiabilityValue;
2783
- } else {
2784
- const freeCollateralAfterClose = totalCollateral.sub(
2785
- marginRequirementAfterClosing
2786
- );
2787
-
2788
- const buyingPowerAfterClose =
2789
- this.getPerpBuyingPowerFromFreeCollateralAndBaseAssetAmount(
2790
- targetMarketIndex,
2791
- freeCollateralAfterClose,
2792
- ZERO,
2793
- currentPosition.maxMarginRatio
2794
- );
2795
- oppositeSideTradeSize = perpLiabilityValue;
2796
- tradeSize = buyingPowerAfterClose;
2797
- }
2798
- } else {
2799
- // do nothing if targetting same side
2800
- tradeSize = maxPositionSize;
2801
- }
2802
- }
2803
-
2804
- const freeCollateral = this.getFreeCollateral('Initial');
2805
-
2806
- let baseTradeSize =
2807
- targetSide === 'long'
2808
- ? tradeSize.mul(BASE_PRECISION).div(oracleData.price)
2809
- : tradeSize.mul(BASE_PRECISION).div(oracleData.price).neg();
2810
-
2811
- let freeCollateralChangeFromNewPosition =
2812
- this.calculateEntriesEffectOnFreeCollateral(
2813
- marketAccount,
2814
- oracleData.price,
2815
- currentPosition,
2816
- baseTradeSize,
2817
- oracleData.price,
2818
- false,
2819
- 'Initial'
2820
- );
2821
-
2822
- while (
2823
- freeCollateralChangeFromNewPosition.isNeg() &&
2824
- freeCollateralChangeFromNewPosition.abs().gt(freeCollateral)
2825
- ) {
2826
- tradeSize = tradeSize.mul(new BN(99)).div(new BN(100));
2827
- baseTradeSize =
2828
- targetSide === 'long'
2829
- ? tradeSize.mul(BASE_PRECISION).div(oracleData.price)
2830
- : tradeSize.mul(BASE_PRECISION).div(oracleData.price).neg();
2831
- freeCollateralChangeFromNewPosition =
2832
- this.calculateEntriesEffectOnFreeCollateral(
2833
- marketAccount,
2834
- oracleData.price,
2835
- currentPosition,
2836
- baseTradeSize,
2837
- oracleData.price,
2838
- false,
2839
- 'Initial'
2840
- );
2841
- }
2842
-
2843
- return { tradeSize, oppositeSideTradeSize };
2844
- }
2845
-
2846
- /**
2847
- * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
2848
- *
2849
- * @param targetMarketIndex
2850
- * @param direction
2851
- * @param currentQuoteAssetValue
2852
- * @param currentSpotMarketNetValue
2853
- * @returns tradeSizeAllowed : Precision QUOTE_PRECISION
2854
- */
2855
- public getMaxTradeSizeUSDCForSpot(
2856
- targetMarketIndex: number,
2857
- direction: PositionDirection,
2858
- currentQuoteAssetValue?: BN,
2859
- currentSpotMarketNetValue?: BN
2860
- ): BN {
2861
- const market =
2862
- this.velocityClient.getSpotMarketAccountOrThrow(targetMarketIndex);
2863
- const oraclePrice =
2864
- this.velocityClient.getOracleDataForSpotMarket(targetMarketIndex).price;
2865
-
2866
- currentQuoteAssetValue = this.getSpotMarketAssetValue(
2867
- QUOTE_SPOT_MARKET_INDEX
2868
- );
2869
-
2870
- currentSpotMarketNetValue =
2871
- currentSpotMarketNetValue ?? this.getSpotPositionValue(targetMarketIndex);
2872
-
2873
- let freeCollateral = this.getFreeCollateral();
2874
- const marginRatio = calculateSpotMarketMarginRatio(
2875
- market,
2876
- oraclePrice,
2877
- 'Initial',
2878
- ZERO,
2879
- isVariant(direction, 'long')
2880
- ? SpotBalanceType.DEPOSIT
2881
- : SpotBalanceType.BORROW,
2882
- this.getUserAccountOrThrow().maxMarginRatio
2883
- );
2884
-
2885
- let tradeAmount = ZERO;
2886
- if (this.getUserAccountOrThrow().isMarginTradingEnabled) {
2887
- // if the user is buying/selling and already short/long, need to account for closing out short/long
2888
- if (isVariant(direction, 'long') && currentSpotMarketNetValue.lt(ZERO)) {
2889
- tradeAmount = currentSpotMarketNetValue.abs();
2890
- const marginRatio = calculateSpotMarketMarginRatio(
2891
- market,
2892
- oraclePrice,
2893
- 'Initial',
2894
- this.getTokenAmount(targetMarketIndex).abs(),
2895
- SpotBalanceType.BORROW,
2896
- this.getUserAccountOrThrow().maxMarginRatio
2897
- );
2898
- freeCollateral = freeCollateral.add(
2899
- tradeAmount.mul(new BN(marginRatio)).div(MARGIN_PRECISION)
2900
- );
2901
- } else if (
2902
- isVariant(direction, 'short') &&
2903
- currentSpotMarketNetValue.gt(ZERO)
2904
- ) {
2905
- tradeAmount = currentSpotMarketNetValue;
2906
- const marginRatio = calculateSpotMarketMarginRatio(
2907
- market,
2908
- oraclePrice,
2909
- 'Initial',
2910
- this.getTokenAmount(targetMarketIndex),
2911
- SpotBalanceType.DEPOSIT,
2912
- this.getUserAccountOrThrow().maxMarginRatio
2913
- );
2914
- freeCollateral = freeCollateral.add(
2915
- tradeAmount.mul(new BN(marginRatio)).div(MARGIN_PRECISION)
2916
- );
2917
- }
2918
-
2919
- tradeAmount = tradeAmount.add(
2920
- freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio))
2921
- );
2922
- } else if (isVariant(direction, 'long')) {
2923
- tradeAmount = BN.min(
2924
- currentQuoteAssetValue,
2925
- freeCollateral.mul(MARGIN_PRECISION).div(new BN(marginRatio))
2926
- );
2927
- } else {
2928
- tradeAmount = BN.max(ZERO, currentSpotMarketNetValue);
2929
- }
2930
-
2931
- return tradeAmount;
2932
- }
2933
-
2934
- /**
2935
- * Calculates the max amount of token that can be swapped from inMarket to outMarket
2936
- * Assumes swap happens at oracle price
2937
- *
2938
- * @param inMarketIndex
2939
- * @param outMarketIndex
2940
- * @param calculateSwap function to similate in to out swa
2941
- * @param iterationLimit how long to run appromixation before erroring out
2942
- */
2943
- public getMaxSwapAmount({
2944
- inMarketIndex,
2945
- outMarketIndex,
2946
- calculateSwap,
2947
- iterationLimit = 1000,
2948
- }: {
2949
- inMarketIndex: number;
2950
- outMarketIndex: number;
2951
- calculateSwap?: (inAmount: BN) => BN;
2952
- iterationLimit?: number;
2953
- }): { inAmount: BN; outAmount: BN; leverage: BN } {
2954
- const inMarket =
2955
- this.velocityClient.getSpotMarketAccountOrThrow(inMarketIndex);
2956
- const outMarket =
2957
- this.velocityClient.getSpotMarketAccountOrThrow(outMarketIndex);
2958
-
2959
- const inOraclePriceData = this.getOracleDataForSpotMarket(inMarketIndex);
2960
- const inOraclePrice = inOraclePriceData.price;
2961
- const outOraclePriceData = this.getOracleDataForSpotMarket(outMarketIndex);
2962
- const outOraclePrice = outOraclePriceData.price;
2963
-
2964
- const inStrictOraclePrice = new StrictOraclePrice(inOraclePrice);
2965
- const outStrictOraclePrice = new StrictOraclePrice(outOraclePrice);
2966
-
2967
- const inPrecision = new BN(10 ** inMarket.decimals);
2968
- const outPrecision = new BN(10 ** outMarket.decimals);
2969
-
2970
- const inSpotPosition =
2971
- this.getSpotPosition(inMarketIndex) ||
2972
- this.getEmptySpotPosition(inMarketIndex);
2973
- const outSpotPosition =
2974
- this.getSpotPosition(outMarketIndex) ||
2975
- this.getEmptySpotPosition(outMarketIndex);
2976
-
2977
- const freeCollateral = this.getFreeCollateral();
2978
-
2979
- const inContributionInitial =
2980
- this.calculateSpotPositionFreeCollateralContribution(
2981
- inSpotPosition,
2982
- inStrictOraclePrice
2983
- );
2984
- const {
2985
- totalAssetValue: inTotalAssetValueInitial,
2986
- totalLiabilityValue: inTotalLiabilityValueInitial,
2987
- } = this.calculateSpotPositionLeverageContribution(
2988
- inSpotPosition,
2989
- inStrictOraclePrice
2990
- );
2991
- const outContributionInitial =
2992
- this.calculateSpotPositionFreeCollateralContribution(
2993
- outSpotPosition,
2994
- outStrictOraclePrice
2995
- );
2996
- const {
2997
- totalAssetValue: outTotalAssetValueInitial,
2998
- totalLiabilityValue: outTotalLiabilityValueInitial,
2999
- } = this.calculateSpotPositionLeverageContribution(
3000
- outSpotPosition,
3001
- outStrictOraclePrice
3002
- );
3003
- const initialContribution = inContributionInitial.add(
3004
- outContributionInitial
3005
- );
3006
-
3007
- const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
3008
- this.getLeverageComponents();
3009
-
3010
- if (!calculateSwap) {
3011
- calculateSwap = (inSwap: BN) => {
3012
- return inSwap
3013
- .mul(outPrecision)
3014
- .mul(inOraclePrice)
3015
- .div(outOraclePrice)
3016
- .div(inPrecision);
3017
- };
3018
- }
3019
-
3020
- let inSwap = ZERO;
3021
- let outSwap = ZERO;
3022
- const inTokenAmount = this.getTokenAmount(inMarketIndex);
3023
- const outTokenAmount = this.getTokenAmount(outMarketIndex);
3024
-
3025
- const inAssetWeight = calculateAssetWeight(
3026
- inTokenAmount,
3027
- inOraclePriceData.price,
3028
- inMarket,
3029
- 'Initial'
3030
- );
3031
- const outAssetWeight = calculateAssetWeight(
3032
- outTokenAmount,
3033
- outOraclePriceData.price,
3034
- outMarket,
3035
- 'Initial'
3036
- );
3037
-
3038
- const outSaferThanIn =
3039
- // selling asset to close borrow
3040
- (inTokenAmount.gt(ZERO) && outTokenAmount.lt(ZERO)) ||
3041
- // buying asset with higher initial asset weight
3042
- inAssetWeight.lte(outAssetWeight);
3043
-
3044
- if (freeCollateral.lt(PRICE_PRECISION.divn(100))) {
3045
- if (outSaferThanIn && inTokenAmount.gt(ZERO)) {
3046
- inSwap = inTokenAmount;
3047
- outSwap = calculateSwap(inSwap);
3048
- }
3049
- } else {
3050
- let minSwap = ZERO;
3051
- let maxSwap = BN.max(
3052
- freeCollateral.mul(inPrecision).mul(new BN(100)).div(inOraclePrice), // 100x current free collateral
3053
- inTokenAmount.abs().mul(new BN(10)) // 10x current position
3054
- );
3055
- inSwap = maxSwap.div(TWO);
3056
- const error = freeCollateral.div(new BN(10000));
3057
-
3058
- let i = 0;
3059
- let freeCollateralAfter = freeCollateral;
3060
- while (freeCollateralAfter.gt(error) || freeCollateralAfter.isNeg()) {
3061
- outSwap = calculateSwap(inSwap);
3062
-
3063
- const inPositionAfter = this.cloneAndUpdateSpotPosition(
3064
- inSpotPosition,
3065
- inSwap.neg(),
3066
- inMarket
3067
- );
3068
- const outPositionAfter = this.cloneAndUpdateSpotPosition(
3069
- outSpotPosition,
3070
- outSwap,
3071
- outMarket
3072
- );
3073
-
3074
- const inContributionAfter =
3075
- this.calculateSpotPositionFreeCollateralContribution(
3076
- inPositionAfter,
3077
- inStrictOraclePrice
3078
- );
3079
- const outContributionAfter =
3080
- this.calculateSpotPositionFreeCollateralContribution(
3081
- outPositionAfter,
3082
- outStrictOraclePrice
3083
- );
3084
-
3085
- const contributionAfter = inContributionAfter.add(outContributionAfter);
3086
-
3087
- const contributionDelta = contributionAfter.sub(initialContribution);
3088
-
3089
- freeCollateralAfter = freeCollateral.add(contributionDelta);
3090
-
3091
- if (freeCollateralAfter.gt(error)) {
3092
- minSwap = inSwap;
3093
- inSwap = minSwap.add(maxSwap).div(TWO);
3094
- } else if (freeCollateralAfter.isNeg()) {
3095
- maxSwap = inSwap;
3096
- inSwap = minSwap.add(maxSwap).div(TWO);
3097
- }
3098
-
3099
- if (i++ > iterationLimit) {
3100
- console.log('getMaxSwapAmount iteration limit reached');
3101
- break;
3102
- }
3103
- }
3104
- }
3105
-
3106
- const inPositionAfter = this.cloneAndUpdateSpotPosition(
3107
- inSpotPosition,
3108
- inSwap.neg(),
3109
- inMarket
3110
- );
3111
- const outPositionAfter = this.cloneAndUpdateSpotPosition(
3112
- outSpotPosition,
3113
- outSwap,
3114
- outMarket
3115
- );
3116
-
3117
- const {
3118
- totalAssetValue: inTotalAssetValueAfter,
3119
- totalLiabilityValue: inTotalLiabilityValueAfter,
3120
- } = this.calculateSpotPositionLeverageContribution(
3121
- inPositionAfter,
3122
- inStrictOraclePrice
3123
- );
3124
-
3125
- const {
3126
- totalAssetValue: outTotalAssetValueAfter,
3127
- totalLiabilityValue: outTotalLiabilityValueAfter,
3128
- } = this.calculateSpotPositionLeverageContribution(
3129
- outPositionAfter,
3130
- outStrictOraclePrice
3131
- );
3132
-
3133
- const spotAssetValueDelta = inTotalAssetValueAfter
3134
- .add(outTotalAssetValueAfter)
3135
- .sub(inTotalAssetValueInitial)
3136
- .sub(outTotalAssetValueInitial);
3137
- const spotLiabilityValueDelta = inTotalLiabilityValueAfter
3138
- .add(outTotalLiabilityValueAfter)
3139
- .sub(inTotalLiabilityValueInitial)
3140
- .sub(outTotalLiabilityValueInitial);
3141
-
3142
- const spotAssetValueAfter = spotAssetValue.add(spotAssetValueDelta);
3143
- const spotLiabilityValueAfter = spotLiabilityValue.add(
3144
- spotLiabilityValueDelta
3145
- );
3146
-
3147
- const leverage = this.calculateLeverageFromComponents({
3148
- perpLiabilityValue,
3149
- perpPnl,
3150
- spotAssetValue: spotAssetValueAfter,
3151
- spotLiabilityValue: spotLiabilityValueAfter,
3152
- });
3153
-
3154
- return { inAmount: inSwap, outAmount: outSwap, leverage };
3155
- }
3156
-
3157
- public cloneAndUpdateSpotPosition(
3158
- position: SpotPosition,
3159
- tokenAmount: BN,
3160
- market: SpotMarketAccount
3161
- ): SpotPosition {
3162
- const clonedPosition = Object.assign({}, position);
3163
- if (tokenAmount.eq(ZERO)) {
3164
- return clonedPosition;
3165
- }
3166
-
3167
- const preTokenAmount = getSignedTokenAmount(
3168
- getTokenAmount(position.scaledBalance, market, position.balanceType),
3169
- position.balanceType
3170
- );
3171
-
3172
- if (sigNum(preTokenAmount).eq(sigNum(tokenAmount))) {
3173
- const scaledBalanceDelta = getBalance(
3174
- tokenAmount.abs(),
3175
- market,
3176
- position.balanceType
3177
- );
3178
- clonedPosition.scaledBalance =
3179
- clonedPosition.scaledBalance.add(scaledBalanceDelta);
3180
- return clonedPosition;
3181
- }
3182
-
3183
- const updateDirection = tokenAmount.isNeg()
3184
- ? SpotBalanceType.BORROW
3185
- : SpotBalanceType.DEPOSIT;
3186
-
3187
- if (tokenAmount.abs().gte(preTokenAmount.abs())) {
3188
- clonedPosition.scaledBalance = getBalance(
3189
- tokenAmount.abs().sub(preTokenAmount.abs()),
3190
- market,
3191
- updateDirection
3192
- );
3193
- clonedPosition.balanceType = updateDirection;
3194
- } else {
3195
- const scaledBalanceDelta = getBalance(
3196
- tokenAmount.abs(),
3197
- market,
3198
- position.balanceType
3199
- );
3200
-
3201
- clonedPosition.scaledBalance =
3202
- clonedPosition.scaledBalance.sub(scaledBalanceDelta);
3203
- }
3204
- return clonedPosition;
3205
- }
3206
-
3207
- calculateSpotPositionFreeCollateralContribution(
3208
- spotPosition: SpotPosition,
3209
- strictOraclePrice: StrictOraclePrice
3210
- ): BN {
3211
- const marginCategory = 'Initial';
3212
-
3213
- const spotMarketAccount: SpotMarketAccount =
3214
- this.velocityClient.getSpotMarketAccountOrThrow(spotPosition.marketIndex);
3215
-
3216
- const { freeCollateralContribution } = getWorstCaseTokenAmounts(
3217
- spotPosition,
3218
- spotMarketAccount,
3219
- strictOraclePrice,
3220
- marginCategory,
3221
- this.getUserAccountOrThrow().maxMarginRatio
3222
- );
3223
-
3224
- return freeCollateralContribution;
3225
- }
3226
-
3227
- calculateSpotPositionLeverageContribution(
3228
- spotPosition: SpotPosition,
3229
- strictOraclePrice: StrictOraclePrice
3230
- ): {
3231
- totalAssetValue: BN;
3232
- totalLiabilityValue: BN;
3233
- } {
3234
- let totalAssetValue = ZERO;
3235
- let totalLiabilityValue = ZERO;
3236
-
3237
- const spotMarketAccount: SpotMarketAccount =
3238
- this.velocityClient.getSpotMarketAccountOrThrow(spotPosition.marketIndex);
3239
-
3240
- const { tokenValue, ordersValue } = getWorstCaseTokenAmounts(
3241
- spotPosition,
3242
- spotMarketAccount,
3243
- strictOraclePrice,
3244
- 'Initial',
3245
- this.getUserAccountOrThrow().maxMarginRatio
3246
- );
3247
-
3248
- if (tokenValue.gte(ZERO)) {
3249
- totalAssetValue = tokenValue;
3250
- } else {
3251
- totalLiabilityValue = tokenValue.abs();
3252
- }
3253
-
3254
- if (ordersValue.gt(ZERO)) {
3255
- totalAssetValue = totalAssetValue.add(ordersValue);
3256
- } else {
3257
- totalLiabilityValue = totalLiabilityValue.add(ordersValue.abs());
3258
- }
3259
-
3260
- return {
3261
- totalAssetValue,
3262
- totalLiabilityValue,
3263
- };
3264
- }
3265
-
3266
- /**
3267
- * Estimates what the user leverage will be after swap
3268
- * @param inMarketIndex
3269
- * @param outMarketIndex
3270
- * @param inAmount
3271
- * @param outAmount
3272
- */
3273
- public accountLeverageAfterSwap({
3274
- inMarketIndex,
3275
- outMarketIndex,
3276
- inAmount,
3277
- outAmount,
3278
- }: {
3279
- inMarketIndex: number;
3280
- outMarketIndex: number;
3281
- inAmount: BN;
3282
- outAmount: BN;
3283
- }): BN {
3284
- const inMarket =
3285
- this.velocityClient.getSpotMarketAccountOrThrow(inMarketIndex);
3286
- const outMarket =
3287
- this.velocityClient.getSpotMarketAccountOrThrow(outMarketIndex);
3288
-
3289
- const inOraclePriceData = this.getOracleDataForSpotMarket(inMarketIndex);
3290
- const inOraclePrice = inOraclePriceData.price;
3291
- const outOraclePriceData = this.getOracleDataForSpotMarket(outMarketIndex);
3292
- const outOraclePrice = outOraclePriceData.price;
3293
- const inStrictOraclePrice = new StrictOraclePrice(inOraclePrice);
3294
- const outStrictOraclePrice = new StrictOraclePrice(outOraclePrice);
3295
-
3296
- const inSpotPosition =
3297
- this.getSpotPosition(inMarketIndex) ||
3298
- this.getEmptySpotPosition(inMarketIndex);
3299
- const outSpotPosition =
3300
- this.getSpotPosition(outMarketIndex) ||
3301
- this.getEmptySpotPosition(outMarketIndex);
3302
-
3303
- const {
3304
- totalAssetValue: inTotalAssetValueInitial,
3305
- totalLiabilityValue: inTotalLiabilityValueInitial,
3306
- } = this.calculateSpotPositionLeverageContribution(
3307
- inSpotPosition,
3308
- inStrictOraclePrice
3309
- );
3310
- const {
3311
- totalAssetValue: outTotalAssetValueInitial,
3312
- totalLiabilityValue: outTotalLiabilityValueInitial,
3313
- } = this.calculateSpotPositionLeverageContribution(
3314
- outSpotPosition,
3315
- outStrictOraclePrice
3316
- );
3317
-
3318
- const { perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue } =
3319
- this.getLeverageComponents();
3320
-
3321
- const inPositionAfter = this.cloneAndUpdateSpotPosition(
3322
- inSpotPosition,
3323
- inAmount.abs().neg(),
3324
- inMarket
3325
- );
3326
- const outPositionAfter = this.cloneAndUpdateSpotPosition(
3327
- outSpotPosition,
3328
- outAmount.abs(),
3329
- outMarket
3330
- );
3331
-
3332
- const {
3333
- totalAssetValue: inTotalAssetValueAfter,
3334
- totalLiabilityValue: inTotalLiabilityValueAfter,
3335
- } = this.calculateSpotPositionLeverageContribution(
3336
- inPositionAfter,
3337
- inStrictOraclePrice
3338
- );
3339
-
3340
- const {
3341
- totalAssetValue: outTotalAssetValueAfter,
3342
- totalLiabilityValue: outTotalLiabilityValueAfter,
3343
- } = this.calculateSpotPositionLeverageContribution(
3344
- outPositionAfter,
3345
- outStrictOraclePrice
3346
- );
3347
-
3348
- const spotAssetValueDelta = inTotalAssetValueAfter
3349
- .add(outTotalAssetValueAfter)
3350
- .sub(inTotalAssetValueInitial)
3351
- .sub(outTotalAssetValueInitial);
3352
- const spotLiabilityValueDelta = inTotalLiabilityValueAfter
3353
- .add(outTotalLiabilityValueAfter)
3354
- .sub(inTotalLiabilityValueInitial)
3355
- .sub(outTotalLiabilityValueInitial);
3356
-
3357
- const spotAssetValueAfter = spotAssetValue.add(spotAssetValueDelta);
3358
- const spotLiabilityValueAfter = spotLiabilityValue.add(
3359
- spotLiabilityValueDelta
3360
- );
3361
-
3362
- return this.calculateLeverageFromComponents({
3363
- perpLiabilityValue,
3364
- perpPnl,
3365
- spotAssetValue: spotAssetValueAfter,
3366
- spotLiabilityValue: spotLiabilityValueAfter,
3367
- });
3368
- }
3369
-
3370
- // TODO - should this take the price impact of the trade into account for strict accuracy?
3371
-
3372
- /**
3373
- * Returns the leverage ratio for the account after adding (or subtracting) the given quote size to the given position
3374
- * @param targetMarketIndex
3375
- * @param: targetMarketType
3376
- * @param tradeQuoteAmount
3377
- * @param tradeSide
3378
- * @param includeOpenOrders
3379
- * @returns leverageRatio : Precision TEN_THOUSAND
3380
- */
3381
- public accountLeverageRatioAfterTrade(
3382
- targetMarketIndex: number,
3383
- targetMarketType: MarketType,
3384
- tradeQuoteAmount: BN,
3385
- tradeSide: PositionDirection,
3386
- includeOpenOrders = true
3387
- ): BN {
3388
- const tradeIsPerp = isVariant(targetMarketType, 'perp');
3389
-
3390
- if (!tradeIsPerp) {
3391
- // calculate new asset/liability values for base and quote market to find new account leverage
3392
- const totalLiabilityValue = this.getTotalLiabilityValue();
3393
- const totalAssetValue = this.getTotalAssetValue();
3394
- const spotLiabilityValue = this.getSpotMarketLiabilityValue(
3395
- undefined,
3396
- undefined,
3397
- undefined,
3398
- includeOpenOrders
3399
- );
3400
-
3401
- const currentQuoteAssetValue = this.getSpotMarketAssetValue(
3402
- QUOTE_SPOT_MARKET_INDEX,
3403
- undefined,
3404
- includeOpenOrders
3405
- );
3406
- const currentQuoteLiabilityValue = this.getSpotMarketLiabilityValue(
3407
- QUOTE_SPOT_MARKET_INDEX,
3408
- undefined,
3409
- undefined,
3410
- includeOpenOrders
3411
- );
3412
- const currentQuoteValue = currentQuoteAssetValue.sub(
3413
- currentQuoteLiabilityValue
3414
- );
3415
-
3416
- const currentSpotMarketAssetValue = this.getSpotMarketAssetValue(
3417
- targetMarketIndex,
3418
- undefined,
3419
- includeOpenOrders
3420
- );
3421
- const currentSpotMarketLiabilityValue = this.getSpotMarketLiabilityValue(
3422
- targetMarketIndex,
3423
- undefined,
3424
- undefined,
3425
- includeOpenOrders
3426
- );
3427
- const currentSpotMarketNetValue = currentSpotMarketAssetValue.sub(
3428
- currentSpotMarketLiabilityValue
3429
- );
3430
-
3431
- let assetValueToAdd = ZERO;
3432
- let liabilityValueToAdd = ZERO;
3433
-
3434
- const newQuoteNetValue =
3435
- tradeSide == PositionDirection.SHORT
3436
- ? currentQuoteValue.add(tradeQuoteAmount)
3437
- : currentQuoteValue.sub(tradeQuoteAmount);
3438
- const newQuoteAssetValue = BN.max(newQuoteNetValue, ZERO);
3439
- const newQuoteLiabilityValue = BN.min(newQuoteNetValue, ZERO).abs();
3440
-
3441
- assetValueToAdd = assetValueToAdd.add(
3442
- newQuoteAssetValue.sub(currentQuoteAssetValue)
3443
- );
3444
- liabilityValueToAdd = liabilityValueToAdd.add(
3445
- newQuoteLiabilityValue.sub(currentQuoteLiabilityValue)
3446
- );
3447
-
3448
- const newSpotMarketNetValue =
3449
- tradeSide == PositionDirection.LONG
3450
- ? currentSpotMarketNetValue.add(tradeQuoteAmount)
3451
- : currentSpotMarketNetValue.sub(tradeQuoteAmount);
3452
- const newSpotMarketAssetValue = BN.max(newSpotMarketNetValue, ZERO);
3453
- const newSpotMarketLiabilityValue = BN.min(
3454
- newSpotMarketNetValue,
3455
- ZERO
3456
- ).abs();
3457
-
3458
- assetValueToAdd = assetValueToAdd.add(
3459
- newSpotMarketAssetValue.sub(currentSpotMarketAssetValue)
3460
- );
3461
- liabilityValueToAdd = liabilityValueToAdd.add(
3462
- newSpotMarketLiabilityValue.sub(currentSpotMarketLiabilityValue)
3463
- );
3464
-
3465
- const totalAssetValueAfterTrade = totalAssetValue.add(assetValueToAdd);
3466
- const totalSpotLiabilityValueAfterTrade =
3467
- spotLiabilityValue.add(liabilityValueToAdd);
3468
-
3469
- const totalLiabilityValueAfterTrade =
3470
- totalLiabilityValue.add(liabilityValueToAdd);
3471
-
3472
- const netAssetValueAfterTrade = totalAssetValueAfterTrade.sub(
3473
- totalSpotLiabilityValueAfterTrade
3474
- );
3475
-
3476
- if (netAssetValueAfterTrade.eq(ZERO)) {
3477
- return ZERO;
3478
- }
3479
-
3480
- const newLeverage = totalLiabilityValueAfterTrade
3481
- .mul(TEN_THOUSAND)
3482
- .div(netAssetValueAfterTrade);
3483
-
3484
- return newLeverage;
3485
- }
3486
-
3487
- const currentPosition = this.getPerpPositionOrEmpty(targetMarketIndex);
3488
-
3489
- const perpMarket =
3490
- this.velocityClient.getPerpMarketAccountOrThrow(targetMarketIndex);
3491
- const oracleData = this.getOracleDataForPerpMarket(targetMarketIndex);
3492
-
3493
- let {
3494
- // eslint-disable-next-line prefer-const
3495
- worstCaseBaseAssetAmount: worstCaseBase,
3496
- worstCaseLiabilityValue: currentPositionQuoteAmount,
3497
- } = calculateWorstCasePerpLiabilityValue(
3498
- currentPosition,
3499
- perpMarket,
3500
- oracleData.price
3501
- );
3502
-
3503
- // current side is short if position base asset amount is negative OR there is no position open but open orders are short
3504
- const currentSide =
3505
- currentPosition.baseAssetAmount.isNeg() ||
3506
- (currentPosition.baseAssetAmount.eq(ZERO) && worstCaseBase.isNeg())
3507
- ? PositionDirection.SHORT
3508
- : PositionDirection.LONG;
3509
-
3510
- if (currentSide === PositionDirection.SHORT)
3511
- currentPositionQuoteAmount = currentPositionQuoteAmount.neg();
3512
-
3513
- if (tradeSide === PositionDirection.SHORT)
3514
- tradeQuoteAmount = tradeQuoteAmount.neg();
3515
-
3516
- const currentPerpPositionAfterTrade = currentPositionQuoteAmount
3517
- .add(tradeQuoteAmount)
3518
- .abs();
3519
-
3520
- const totalPositionAfterTradeExcludingTargetMarket =
3521
- this.getTotalPerpPositionValueExcludingMarket(
3522
- targetMarketIndex,
3523
- undefined,
3524
- undefined,
3525
- includeOpenOrders
3526
- );
3527
-
3528
- const totalAssetValue = this.getTotalAssetValue();
3529
-
3530
- const totalPerpPositionLiability = currentPerpPositionAfterTrade
3531
- .add(totalPositionAfterTradeExcludingTargetMarket)
3532
- .abs();
3533
-
3534
- const totalSpotLiability = this.getSpotMarketLiabilityValue(
3535
- undefined,
3536
- undefined,
3537
- undefined,
3538
- includeOpenOrders
3539
- );
3540
-
3541
- const totalLiabilitiesAfterTrade =
3542
- totalPerpPositionLiability.add(totalSpotLiability);
3543
-
3544
- const netAssetValue = totalAssetValue.sub(totalSpotLiability);
3545
-
3546
- if (netAssetValue.eq(ZERO)) {
3547
- return ZERO;
3548
- }
3549
-
3550
- const newLeverage = totalLiabilitiesAfterTrade
3551
- .mul(TEN_THOUSAND)
3552
- .div(netAssetValue);
3553
-
3554
- return newLeverage;
3555
- }
3556
-
3557
- public getUserFeeTier(marketType: MarketType, now?: BN) {
3558
- const state = this.velocityClient.getStateAccount();
3559
-
3560
- if (isVariant(marketType, 'perp')) {
3561
- const userStatsAccount: UserStatsAccount = this.velocityClient
3562
- .getUserStatsOrThrow()
3563
- .getAccountOrThrow();
3564
-
3565
- const total30dVolume = getUser30dRollingVolumeEstimate(
3566
- userStatsAccount,
3567
- now
3568
- );
3569
-
3570
- const volumeThresholds = [
3571
- new BN(2_000_000).mul(QUOTE_PRECISION),
3572
- new BN(10_000_000).mul(QUOTE_PRECISION),
3573
- new BN(20_000_000).mul(QUOTE_PRECISION),
3574
- new BN(80_000_000).mul(QUOTE_PRECISION),
3575
- new BN(200_000_000).mul(QUOTE_PRECISION),
3576
- ];
3577
-
3578
- let feeTierIndex = 5;
3579
- for (let i = 0; i < volumeThresholds.length; i++) {
3580
- if (total30dVolume.lt(volumeThresholds[i])) {
3581
- feeTierIndex = i;
3582
- break;
3583
- }
3584
- }
3585
-
3586
- return state.perpFeeStructure.feeTiers[feeTierIndex];
3587
- }
3588
-
3589
- return state.spotFeeStructure.feeTiers[0];
3590
- }
3591
-
3592
- /**
3593
- * Calculates how much perp fee will be taken for a given sized trade
3594
- * @param quoteAmount
3595
- * @returns feeForQuote : Precision QUOTE_PRECISION
3596
- */
3597
- public calculateFeeForQuoteAmount(quoteAmount: BN, marketIndex?: number): BN {
3598
- if (marketIndex !== undefined) {
3599
- const takerFeeMultiplier = this.velocityClient.getMarketFees(
3600
- MarketType.PERP,
3601
- marketIndex,
3602
- this
3603
- ).takerFee;
3604
- const feeAmountNum =
3605
- BigNum.from(quoteAmount, QUOTE_PRECISION_EXP).toNum() *
3606
- takerFeeMultiplier;
3607
- return BigNum.fromPrint(feeAmountNum.toString(), QUOTE_PRECISION_EXP).val;
3608
- } else {
3609
- const feeTier = this.getUserFeeTier(MarketType.PERP);
3610
- return quoteAmount
3611
- .mul(new BN(feeTier.feeNumerator))
3612
- .div(new BN(feeTier.feeDenominator));
3613
- }
3614
- }
3615
-
3616
- /**
3617
- * Calculates a user's max withdrawal amounts for a spot market. If reduceOnly is true,
3618
- * it will return the max withdrawal amount without opening a liability for the user
3619
- * @param marketIndex
3620
- * @returns withdrawalLimit : Precision is the token precision for the chosen SpotMarket
3621
- */
3622
- public getWithdrawalLimit(marketIndex: number, reduceOnly?: boolean): BN {
3623
- const nowTs = new BN(Math.floor(Date.now() / 1000));
3624
- const spotMarket =
3625
- this.velocityClient.getSpotMarketAccountOrThrow(marketIndex);
3626
-
3627
- // eslint-disable-next-line prefer-const
3628
- let { borrowLimit, withdrawLimit } = calculateWithdrawLimit(
3629
- spotMarket,
3630
- nowTs
3631
- );
3632
-
3633
- const freeCollateral = this.getFreeCollateral();
3634
- const initialMarginRequirement = this.getInitialMarginRequirement();
3635
- const oracleData = this.getOracleDataForSpotMarket(marketIndex);
3636
- const { numeratorScale, denominatorScale } =
3637
- spotMarket.decimals > 6
3638
- ? {
3639
- numeratorScale: new BN(10).pow(new BN(spotMarket.decimals - 6)),
3640
- denominatorScale: new BN(1),
3641
- }
3642
- : {
3643
- numeratorScale: new BN(1),
3644
- denominatorScale: new BN(10).pow(new BN(6 - spotMarket.decimals)),
3645
- };
3646
-
3647
- const { canBypass, depositAmount: userDepositAmount } =
3648
- this.canBypassWithdrawLimits(marketIndex);
3649
- if (canBypass) {
3650
- withdrawLimit = BN.max(withdrawLimit, userDepositAmount);
3651
- }
3652
-
3653
- const assetWeight = calculateAssetWeight(
3654
- userDepositAmount,
3655
- oracleData.price,
3656
- spotMarket,
3657
- 'Initial'
3658
- );
3659
-
3660
- let amountWithdrawable;
3661
- if (assetWeight.eq(ZERO)) {
3662
- amountWithdrawable = userDepositAmount;
3663
- } else if (initialMarginRequirement.eq(ZERO)) {
3664
- amountWithdrawable = userDepositAmount;
3665
- } else {
3666
- amountWithdrawable = divCeil(
3667
- divCeil(freeCollateral.mul(MARGIN_PRECISION), assetWeight).mul(
3668
- PRICE_PRECISION
3669
- ),
3670
- oracleData.price
3671
- )
3672
- .mul(numeratorScale)
3673
- .div(denominatorScale);
3674
- }
3675
-
3676
- const maxWithdrawValue = BN.min(
3677
- BN.min(amountWithdrawable, userDepositAmount),
3678
- withdrawLimit.abs()
3679
- );
3680
-
3681
- if (reduceOnly) {
3682
- return BN.max(maxWithdrawValue, ZERO);
3683
- } else {
3684
- const weightedAssetValue = this.getSpotMarketAssetValue(
3685
- marketIndex,
3686
- 'Initial',
3687
- false
3688
- );
3689
-
3690
- const freeCollatAfterWithdraw = userDepositAmount.gt(ZERO)
3691
- ? freeCollateral.sub(weightedAssetValue)
3692
- : freeCollateral;
3693
-
3694
- const maxLiabilityAllowed = freeCollatAfterWithdraw
3695
- .mul(MARGIN_PRECISION)
3696
- .div(new BN(spotMarket.initialLiabilityWeight))
3697
- .mul(PRICE_PRECISION)
3698
- .div(oracleData.price)
3699
- .mul(numeratorScale)
3700
- .div(denominatorScale);
3701
-
3702
- const maxBorrowValue = BN.min(
3703
- maxWithdrawValue.add(maxLiabilityAllowed),
3704
- borrowLimit.abs()
3705
- );
3706
-
3707
- return BN.max(maxBorrowValue, ZERO);
3708
- }
3709
- }
3710
-
3711
- public canBypassWithdrawLimits(marketIndex: number): {
3712
- canBypass: boolean;
3713
- netDeposits: BN;
3714
- depositAmount: BN;
3715
- maxDepositAmount: BN;
3716
- } {
3717
- const spotMarket =
3718
- this.velocityClient.getSpotMarketAccountOrThrow(marketIndex);
3719
- const maxDepositAmount = spotMarket.withdrawGuardThreshold.div(new BN(10));
3720
- const position = this.getSpotPosition(marketIndex);
3721
-
3722
- const netDeposits = this.getUserAccountOrThrow().totalDeposits.sub(
3723
- this.getUserAccountOrThrow().totalWithdraws
3724
- );
3725
-
3726
- if (!position) {
3727
- return {
3728
- canBypass: false,
3729
- maxDepositAmount,
3730
- depositAmount: ZERO,
3731
- netDeposits,
3732
- };
3733
- }
3734
-
3735
- if (isVariant(position.balanceType, 'borrow')) {
3736
- return {
3737
- canBypass: false,
3738
- maxDepositAmount,
3739
- netDeposits,
3740
- depositAmount: ZERO,
3741
- };
3742
- }
3743
-
3744
- const depositAmount = getTokenAmount(
3745
- position.scaledBalance,
3746
- spotMarket,
3747
- SpotBalanceType.DEPOSIT
3748
- );
3749
-
3750
- if (netDeposits.lt(ZERO)) {
3751
- return {
3752
- canBypass: false,
3753
- maxDepositAmount,
3754
- depositAmount,
3755
- netDeposits,
3756
- };
3757
- }
3758
-
3759
- return {
3760
- canBypass: depositAmount.lt(maxDepositAmount),
3761
- maxDepositAmount,
3762
- netDeposits,
3763
- depositAmount,
3764
- };
3765
- }
3766
-
3767
- public canMakeIdle(slot: BN): boolean {
3768
- const userAccount = this.getUserAccountOrThrow();
3769
- if (userAccount.idle) {
3770
- return false;
3771
- }
3772
-
3773
- const { totalAssetValue, totalLiabilityValue } =
3774
- this.getSpotMarketAssetAndLiabilityValue();
3775
- const equity = totalAssetValue.sub(totalLiabilityValue);
3776
-
3777
- let slotsBeforeIdle: BN;
3778
- if (equity.lt(QUOTE_PRECISION.muln(1000))) {
3779
- slotsBeforeIdle = new BN(9000); // 1 hour
3780
- } else {
3781
- slotsBeforeIdle = new BN(1512000); // 1 week
3782
- }
3783
-
3784
- const userLastActiveSlot = userAccount.lastActiveSlot;
3785
- const slotsSinceLastActive = slot.sub(userLastActiveSlot);
3786
- if (slotsSinceLastActive.lt(slotsBeforeIdle)) {
3787
- return false;
3788
- }
3789
-
3790
- if (this.isBeingLiquidated()) {
3791
- return false;
3792
- }
3793
-
3794
- for (const perpPosition of userAccount.perpPositions) {
3795
- if (!positionIsAvailable(perpPosition)) {
3796
- return false;
3797
- }
3798
- }
3799
-
3800
- for (const spotPosition of userAccount.spotPositions) {
3801
- if (
3802
- isVariant(spotPosition.balanceType, 'borrow') &&
3803
- spotPosition.scaledBalance.gt(ZERO)
3804
- ) {
3805
- return false;
3806
- }
3807
-
3808
- if (spotPosition.openOrders !== 0) {
3809
- return false;
3810
- }
3811
- }
3812
-
3813
- for (const order of userAccount.orders) {
3814
- if (isVariant(order.status, 'open')) {
3815
- return false;
3816
- }
3817
- }
3818
-
3819
- return true;
3820
- }
3821
-
3822
- public canBeDeleted(
3823
- userStatsAccount?: UserStatsAccount,
3824
- now?: BN
3825
- ): { canDelete: boolean; reason?: string } {
3826
- const userAccount = this.getUserAccountOrThrow();
3827
- const userStatsAccountToUse =
3828
- userStatsAccount ??
3829
- this.velocityClient.getUserStatsOrThrow().getAccount();
3830
- const nowInSeconds = now || new BN(Math.floor(Date.now() / 1000));
3831
- const stateAccount = this.velocityClient.getStateAccount();
3832
-
3833
- // Referrer cannot delete sub_account_id 0
3834
- const isReferrer =
3835
- userStatsAccountToUse !== undefined &&
3836
- (userStatsAccountToUse.referrerStatus & ReferrerStatus.IsReferrer) > 0;
3837
- if (isReferrer && userAccount.subAccountId === 0) {
3838
- return { canDelete: false, reason: 'is-subaccount-0-referrer' };
3839
- }
3840
-
3841
- if (this.isBankrupt()) {
3842
- return { canDelete: false, reason: 'is-bankrupt' };
3843
- }
3844
-
3845
- if (this.isBeingLiquidated()) {
3846
- return { canDelete: false, reason: 'is-being-liquidated' };
3847
- }
3848
-
3849
- // Any perp positions available
3850
- for (const perpPosition of userAccount.perpPositions) {
3851
- if (!positionIsAvailable(perpPosition)) {
3852
- return { canDelete: false, reason: 'has-perp-position' };
3853
- }
3854
- }
3855
-
3856
- // Any spot positions available
3857
- for (const spotPosition of userAccount.spotPositions) {
3858
- if (!isSpotPositionAvailable(spotPosition)) {
3859
- return { canDelete: false, reason: 'has-spot-position' };
3860
- }
3861
- }
3862
-
3863
- // No open orders
3864
- for (const order of userAccount.orders) {
3865
- if (isVariant(order.status, 'open')) {
3866
- return { canDelete: false, reason: 'has-open-order' };
3867
- }
3868
- }
3869
-
3870
- // Fresh account (< 13 days) with init fee must be idle
3871
- if (stateAccount.maxInitializeUserFee > 0 && userStatsAccountToUse) {
3872
- const minActionTs = BN.min(
3873
- userStatsAccountToUse.lastFillerVolume30DTs,
3874
- BN.min(
3875
- userStatsAccountToUse.lastMakerVolume30DTs,
3876
- userStatsAccountToUse.lastTakerVolume30DTs
3877
- )
3878
- );
3879
- const estimatedAge = BN.max(nowInSeconds.sub(minActionTs), ZERO);
3880
- if (estimatedAge.lt(new BN(ACCOUNT_AGE_DELETION_CUTOFF_SECONDS))) {
3881
- if (!userAccount.idle) {
3882
- return {
3883
- canDelete: false,
3884
- reason: 'is-not-idle-fresh-account',
3885
- };
3886
- }
3887
- }
3888
- }
3889
-
3890
- return { canDelete: true };
3891
- }
3892
-
3893
- public getSafestTiers(): { perpTier: number; spotTier: number } {
3894
- let safestPerpTier = 4;
3895
- let safestSpotTier = 4;
3896
-
3897
- for (const perpPosition of this.getActivePerpPositions()) {
3898
- safestPerpTier = Math.min(
3899
- safestPerpTier,
3900
- getPerpMarketTierNumber(
3901
- this.velocityClient.getPerpMarketAccountOrThrow(
3902
- perpPosition.marketIndex
3903
- )
3904
- )
3905
- );
3906
- }
3907
-
3908
- for (const spotPosition of this.getActiveSpotPositions()) {
3909
- if (isVariant(spotPosition.balanceType, 'deposit')) {
3910
- continue;
3911
- }
3912
-
3913
- safestSpotTier = Math.min(
3914
- safestSpotTier,
3915
- getSpotMarketTierNumber(
3916
- this.velocityClient.getSpotMarketAccountOrThrow(
3917
- spotPosition.marketIndex
3918
- )
3919
- )
3920
- );
3921
- }
3922
-
3923
- return {
3924
- perpTier: safestPerpTier,
3925
- spotTier: safestSpotTier,
3926
- };
3927
- }
3928
-
3929
- public getPerpPositionHealth({
3930
- marginCategory,
3931
- perpPosition,
3932
- oraclePriceData,
3933
- quoteOraclePriceData,
3934
- includeOpenOrders = true,
3935
- }: {
3936
- marginCategory: MarginCategory;
3937
- perpPosition: PerpPosition;
3938
- oraclePriceData?: OraclePriceData;
3939
- quoteOraclePriceData?: OraclePriceData;
3940
- includeOpenOrders?: boolean;
3941
- }): HealthComponent {
3942
- const perpMarket = this.velocityClient.getPerpMarketAccountOrThrow(
3943
- perpPosition.marketIndex
3944
- );
3945
- const _oraclePriceData =
3946
- oraclePriceData ||
3947
- this.velocityClient.getOracleDataForPerpMarket(perpMarket.marketIndex);
3948
- const oraclePrice = _oraclePriceData.price;
3949
-
3950
- let worstCaseBaseAmount;
3951
- let worstCaseLiabilityValue;
3952
- if (includeOpenOrders) {
3953
- const worstCaseIncludeOrders = calculateWorstCasePerpLiabilityValue(
3954
- perpPosition,
3955
- perpMarket,
3956
- oraclePrice
3957
- );
3958
- worstCaseBaseAmount = worstCaseIncludeOrders.worstCaseBaseAssetAmount;
3959
- worstCaseLiabilityValue = worstCaseIncludeOrders.worstCaseLiabilityValue;
3960
- } else {
3961
- worstCaseBaseAmount = perpPosition.baseAssetAmount;
3962
- worstCaseLiabilityValue = calculatePerpLiabilityValue(
3963
- perpPosition.baseAssetAmount,
3964
- oraclePrice
3965
- );
3966
- }
3967
-
3968
- const userCustomMargin = Math.max(
3969
- perpPosition.maxMarginRatio,
3970
- this.getUserAccountOrThrow().maxMarginRatio
3971
- );
3972
- const marginRatio = new BN(
3973
- calculateMarketMarginRatio(
3974
- perpMarket,
3975
- worstCaseBaseAmount.abs(),
3976
- marginCategory,
3977
- userCustomMargin
3978
- )
3979
- );
3980
-
3981
- const _quoteOraclePriceData =
3982
- quoteOraclePriceData ||
3983
- this.velocityClient.getOracleDataForSpotMarket(QUOTE_SPOT_MARKET_INDEX);
3984
-
3985
- let marginRequirement = worstCaseLiabilityValue
3986
- .mul(_quoteOraclePriceData.price)
3987
- .div(PRICE_PRECISION)
3988
- .mul(marginRatio)
3989
- .div(MARGIN_PRECISION);
3990
-
3991
- marginRequirement = marginRequirement.add(
3992
- new BN(perpPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
3993
- );
3994
-
3995
- return {
3996
- marketIndex: perpMarket.marketIndex,
3997
- size: worstCaseBaseAmount,
3998
- value: worstCaseLiabilityValue,
3999
- weight: marginRatio,
4000
- weightedValue: marginRequirement,
4001
- };
4002
- }
4003
-
4004
- public getHealthComponents({
4005
- marginCategory,
4006
- }: {
4007
- marginCategory: MarginCategory;
4008
- }): HealthComponents {
4009
- const healthComponents: HealthComponents = {
4010
- deposits: [],
4011
- borrows: [],
4012
- perpPositions: [],
4013
- perpPnl: [],
4014
- };
4015
-
4016
- for (const perpPosition of this.getActivePerpPositions()) {
4017
- const perpMarket = this.velocityClient.getPerpMarketAccountOrThrow(
4018
- perpPosition.marketIndex
4019
- );
4020
-
4021
- const oraclePriceData = this.velocityClient.getOracleDataForPerpMarket(
4022
- perpMarket.marketIndex
4023
- );
4024
-
4025
- const quoteOraclePriceData =
4026
- this.velocityClient.getOracleDataForSpotMarket(QUOTE_SPOT_MARKET_INDEX);
4027
-
4028
- healthComponents.perpPositions.push(
4029
- this.getPerpPositionHealth({
4030
- marginCategory,
4031
- perpPosition,
4032
- oraclePriceData,
4033
- quoteOraclePriceData,
4034
- })
4035
- );
4036
-
4037
- const quoteSpotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
4038
- perpMarket.quoteSpotMarketIndex
4039
- );
4040
-
4041
- const positionUnrealizedPnl = calculatePositionPNL(
4042
- perpMarket,
4043
- perpPosition,
4044
- true,
4045
- oraclePriceData
4046
- );
4047
-
4048
- let pnlWeight;
4049
- if (positionUnrealizedPnl.gt(ZERO)) {
4050
- pnlWeight = calculateUnrealizedAssetWeight(
4051
- perpMarket,
4052
- quoteSpotMarket,
4053
- positionUnrealizedPnl,
4054
- marginCategory,
4055
- oraclePriceData
4056
- );
4057
- } else {
4058
- pnlWeight = SPOT_MARKET_WEIGHT_PRECISION;
4059
- }
4060
-
4061
- const pnlValue = positionUnrealizedPnl
4062
- .mul(quoteOraclePriceData.price)
4063
- .div(PRICE_PRECISION);
4064
-
4065
- const wegithedPnlValue = pnlValue
4066
- .mul(pnlWeight)
4067
- .div(SPOT_MARKET_WEIGHT_PRECISION);
4068
-
4069
- healthComponents.perpPnl.push({
4070
- marketIndex: perpMarket.marketIndex,
4071
- size: positionUnrealizedPnl,
4072
- value: pnlValue,
4073
- weight: pnlWeight,
4074
- weightedValue: wegithedPnlValue,
4075
- });
4076
- }
4077
-
4078
- let netQuoteValue = ZERO;
4079
- for (const spotPosition of this.getActiveSpotPositions()) {
4080
- const spotMarketAccount: SpotMarketAccount =
4081
- this.velocityClient.getSpotMarketAccountOrThrow(
4082
- spotPosition.marketIndex
4083
- );
4084
-
4085
- const oraclePriceData = this.getOracleDataForSpotMarket(
4086
- spotPosition.marketIndex
4087
- );
4088
-
4089
- const strictOraclePrice = new StrictOraclePrice(oraclePriceData.price);
4090
-
4091
- if (spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX) {
4092
- const tokenAmount = getSignedTokenAmount(
4093
- getTokenAmount(
4094
- spotPosition.scaledBalance,
4095
- spotMarketAccount,
4096
- spotPosition.balanceType
4097
- ),
4098
- spotPosition.balanceType
4099
- );
4100
-
4101
- netQuoteValue = netQuoteValue.add(tokenAmount);
4102
- continue;
4103
- }
4104
-
4105
- const {
4106
- tokenAmount: worstCaseTokenAmount,
4107
- tokenValue: tokenValue,
4108
- weight,
4109
- weightedTokenValue: weightedTokenValue,
4110
- ordersValue: ordersValue,
4111
- } = getWorstCaseTokenAmounts(
4112
- spotPosition,
4113
- spotMarketAccount,
4114
- strictOraclePrice,
4115
- marginCategory,
4116
- this.getUserAccountOrThrow().maxMarginRatio
4117
- );
4118
-
4119
- netQuoteValue = netQuoteValue.add(ordersValue);
4120
-
4121
- const baseAssetValue = tokenValue.abs();
4122
- const weightedValue = weightedTokenValue.abs();
4123
-
4124
- if (weightedTokenValue.lt(ZERO)) {
4125
- healthComponents.borrows.push({
4126
- marketIndex: spotMarketAccount.marketIndex,
4127
- size: worstCaseTokenAmount,
4128
- value: baseAssetValue,
4129
- weight: weight,
4130
- weightedValue: weightedValue,
4131
- });
4132
- } else {
4133
- healthComponents.deposits.push({
4134
- marketIndex: spotMarketAccount.marketIndex,
4135
- size: worstCaseTokenAmount,
4136
- value: baseAssetValue,
4137
- weight: weight,
4138
- weightedValue: weightedValue,
4139
- });
4140
- }
4141
- }
4142
-
4143
- if (!netQuoteValue.eq(ZERO)) {
4144
- const spotMarketAccount = this.velocityClient.getQuoteSpotMarketAccount();
4145
- const oraclePriceData = this.getOracleDataForSpotMarket(
4146
- QUOTE_SPOT_MARKET_INDEX
4147
- );
4148
-
4149
- const baseAssetValue = getTokenValue(
4150
- netQuoteValue,
4151
- spotMarketAccount.decimals,
4152
- oraclePriceData
4153
- );
4154
-
4155
- const { weight, weightedTokenValue } = calculateWeightedTokenValue(
4156
- netQuoteValue,
4157
- baseAssetValue,
4158
- oraclePriceData.price,
4159
- spotMarketAccount,
4160
- marginCategory,
4161
- this.getUserAccountOrThrow().maxMarginRatio
4162
- );
4163
-
4164
- if (netQuoteValue.lt(ZERO)) {
4165
- healthComponents.borrows.push({
4166
- marketIndex: spotMarketAccount.marketIndex,
4167
- size: netQuoteValue,
4168
- value: baseAssetValue.abs(),
4169
- weight: weight,
4170
- weightedValue: weightedTokenValue.abs(),
4171
- });
4172
- } else {
4173
- healthComponents.deposits.push({
4174
- marketIndex: spotMarketAccount.marketIndex,
4175
- size: netQuoteValue,
4176
- value: baseAssetValue,
4177
- weight: weight,
4178
- weightedValue: weightedTokenValue,
4179
- });
4180
- }
4181
- }
4182
-
4183
- return healthComponents;
4184
- }
4185
-
4186
- /**
4187
- * Get the total position value, excluding any position coming from the given target market
4188
- * @param marketToIgnore
4189
- * @returns positionValue : Precision QUOTE_PRECISION
4190
- */
4191
- private getTotalPerpPositionValueExcludingMarket(
4192
- marketToIgnore: number,
4193
- marginCategory?: MarginCategory,
4194
- liquidationBuffer?: BN,
4195
- includeOpenOrders?: boolean
4196
- ): BN {
4197
- const currentPerpPosition = this.getPerpPositionOrEmpty(marketToIgnore);
4198
-
4199
- const oracleData = this.getOracleDataForPerpMarket(marketToIgnore);
4200
-
4201
- let currentPerpPositionValueUSDC = ZERO;
4202
- if (currentPerpPosition) {
4203
- currentPerpPositionValueUSDC = this.getPerpLiabilityValue(
4204
- marketToIgnore,
4205
- oracleData,
4206
- includeOpenOrders
4207
- );
4208
- }
4209
-
4210
- return this.getTotalPerpPositionLiability(
4211
- marginCategory,
4212
- liquidationBuffer,
4213
- includeOpenOrders
4214
- ).sub(currentPerpPositionValueUSDC);
4215
- }
4216
-
4217
- private getMMOracleDataForPerpMarket(marketIndex: number): MMOraclePriceData {
4218
- return this.velocityClient.getMMOracleDataForPerpMarket(marketIndex);
4219
- }
4220
-
4221
- private getOracleDataForPerpMarket(marketIndex: number): OraclePriceData {
4222
- return this.velocityClient.getOracleDataForPerpMarket(marketIndex);
4223
- }
4224
-
4225
- private getOracleDataForSpotMarket(marketIndex: number): OraclePriceData {
4226
- return this.velocityClient.getOracleDataForSpotMarket(marketIndex);
4227
- }
4228
-
4229
- /**
4230
- * Get the active perp and spot positions of the user.
4231
- */
4232
- public getActivePositions(): {
4233
- activePerpPositions: number[];
4234
- activeSpotPositions: number[];
4235
- } {
4236
- const activePerpMarkets = this.getActivePerpPositions().map(
4237
- (position) => position.marketIndex
4238
- );
4239
-
4240
- const activeSpotMarkets = this.getActiveSpotPositions().map(
4241
- (position) => position.marketIndex
4242
- );
4243
-
4244
- return {
4245
- activePerpPositions: activePerpMarkets,
4246
- activeSpotPositions: activeSpotMarkets,
4247
- };
4248
- }
4249
-
4250
- /**
4251
- * Compute the full margin calculation for the user's account.
4252
- * Prioritize using this function instead of calling getMarginRequirement or getTotalCollateral multiple times.
4253
- * Consumers can use this to avoid duplicating work across separate calls.
4254
- */
4255
- public getMarginCalculation(
4256
- marginCategory: MarginCategory = 'Initial',
4257
- opts?: {
4258
- strict?: boolean; // mirror StrictOraclePrice application
4259
- includeOpenOrders?: boolean;
4260
- liquidationBufferMap?: Map<number | 'cross', BN>; // margin_buffer analog for buffer mode
4261
- }
4262
- ): MarginCalculation {
4263
- const strict = opts?.strict ?? false;
4264
- const liquidationBufferMap = opts?.liquidationBufferMap ?? new Map();
4265
- const includeOpenOrders = opts?.includeOpenOrders ?? true;
4266
-
4267
- // Equivalent to on-chain user_custom_margin_ratio
4268
- const userCustomMarginRatio =
4269
- marginCategory === 'Initial'
4270
- ? this.getUserAccountOrThrow().maxMarginRatio
4271
- : 0;
4272
-
4273
- // Initialize calc via JS mirror of Rust/on-chain MarginCalculation
4274
- const isolatedMarginBuffers = new Map<number, BN>();
4275
- for (const [
4276
- marketIndex,
4277
- isolatedMarginBuffer,
4278
- ] of opts?.liquidationBufferMap ?? new Map()) {
4279
- if (marketIndex !== 'cross') {
4280
- isolatedMarginBuffers.set(marketIndex, isolatedMarginBuffer);
4281
- }
4282
- }
4283
- const ctx = MarginContext.standard(marginCategory)
4284
- .strictMode(strict)
4285
- .setCrossMarginBuffer(opts?.liquidationBufferMap?.get('cross') ?? ZERO)
4286
- .setIsolatedMarginBuffers(isolatedMarginBuffers);
4287
- const calc = new MarginCalculation(ctx);
4288
-
4289
- // SPOT POSITIONS
4290
- for (const spotPosition of this.getUserAccountOrThrow().spotPositions) {
4291
- if (isSpotPositionAvailable(spotPosition)) continue;
4292
-
4293
- const isQuote = spotPosition.marketIndex === QUOTE_SPOT_MARKET_INDEX;
4294
-
4295
- const spotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
4296
- spotPosition.marketIndex
4297
- );
4298
- const oraclePriceData = this.getOracleDataForSpotMarket(
4299
- spotPosition.marketIndex
4300
- );
4301
- const twap5 = strict
4302
- ? calculateLiveOracleTwap(
4303
- spotMarket.historicalOracleData,
4304
- oraclePriceData,
4305
- new BN(Math.floor(Date.now() / 1000)),
4306
- FIVE_MINUTE
4307
- )
4308
- : undefined;
4309
- const strictOracle = new StrictOraclePrice(oraclePriceData.price, twap5);
4310
-
4311
- if (isQuote) {
4312
- const tokenAmount = getSignedTokenAmount(
4313
- getTokenAmount(
4314
- spotPosition.scaledBalance,
4315
- spotMarket,
4316
- spotPosition.balanceType
4317
- ),
4318
- spotPosition.balanceType
4319
- );
4320
- if (isVariant(spotPosition.balanceType, 'deposit')) {
4321
- // add deposit value to total collateral
4322
- const weightedTokenValue = this.getSpotAssetValue(
4323
- tokenAmount,
4324
- strictOracle,
4325
- spotMarket,
4326
- marginCategory
4327
- );
4328
- calc.addCrossMarginTotalCollateral(weightedTokenValue);
4329
- } else {
4330
- // borrow on quote contributes to margin requirement
4331
- const tokenValueAbs = this.getSpotLiabilityValue(
4332
- tokenAmount,
4333
- strictOracle,
4334
- spotMarket,
4335
- marginCategory,
4336
- liquidationBufferMap.get('cross') ?? new BN(0)
4337
- ).abs();
4338
- calc.addCrossMarginRequirement(tokenValueAbs, tokenValueAbs);
4339
- }
4340
- continue;
4341
- }
4342
-
4343
- // Non-quote spot: worst-case simulation
4344
- const {
4345
- tokenAmount: worstCaseTokenAmount,
4346
- ordersValue: worstCaseOrdersValue,
4347
- } = getWorstCaseTokenAmounts(
4348
- spotPosition,
4349
- spotMarket,
4350
- strictOracle,
4351
- marginCategory,
4352
- userCustomMarginRatio,
4353
- includeOpenOrders
4354
- // false
4355
- );
4356
-
4357
- if (includeOpenOrders) {
4358
- // open order IM
4359
- calc.addCrossMarginRequirement(
4360
- new BN(spotPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT),
4361
- ZERO
4362
- );
4363
- }
4364
-
4365
- if (worstCaseTokenAmount.gt(ZERO)) {
4366
- const baseAssetValue = this.getSpotAssetValue(
4367
- worstCaseTokenAmount,
4368
- strictOracle,
4369
- spotMarket,
4370
- marginCategory
4371
- );
4372
- // asset side increases total collateral (weighted)
4373
- calc.addCrossMarginTotalCollateral(baseAssetValue);
4374
- } else if (worstCaseTokenAmount.lt(ZERO)) {
4375
- // liability side increases margin requirement (weighted >= abs(token_value))
4376
- const getSpotLiabilityValue = this.getSpotLiabilityValue(
4377
- worstCaseTokenAmount,
4378
- strictOracle,
4379
- spotMarket,
4380
- marginCategory,
4381
- liquidationBufferMap.get('cross')
4382
- );
4383
-
4384
- calc.addCrossMarginRequirement(
4385
- getSpotLiabilityValue.abs(),
4386
- getSpotLiabilityValue.abs()
4387
- );
4388
- }
4389
-
4390
- // orders value contributes to collateral or requirement
4391
- if (worstCaseOrdersValue.gt(ZERO)) {
4392
- calc.addCrossMarginTotalCollateral(worstCaseOrdersValue);
4393
- } else if (worstCaseOrdersValue.lt(ZERO)) {
4394
- const absVal = worstCaseOrdersValue.abs();
4395
- calc.addCrossMarginRequirement(absVal, absVal);
4396
- }
4397
- }
4398
-
4399
- // PERP POSITIONS
4400
- for (const marketPosition of this.getActivePerpPositions()) {
4401
- const market = this.velocityClient.getPerpMarketAccountOrThrow(
4402
- marketPosition.marketIndex
4403
- );
4404
- const quoteSpotMarket = this.velocityClient.getSpotMarketAccountOrThrow(
4405
- market.quoteSpotMarketIndex
4406
- );
4407
- const quoteOraclePriceData = this.getOracleDataForSpotMarket(
4408
- market.quoteSpotMarketIndex
4409
- );
4410
- const oraclePriceData = this.getMMOracleDataForPerpMarket(
4411
- market.marketIndex
4412
- );
4413
-
4414
- const nonMmmOraclePriceData = this.getOracleDataForPerpMarket(
4415
- market.marketIndex
4416
- );
4417
-
4418
- // Worst-case perp liability and weighted pnl
4419
- const { worstCaseBaseAssetAmount, worstCaseLiabilityValue } =
4420
- calculateWorstCasePerpLiabilityValue(
4421
- marketPosition,
4422
- market,
4423
- nonMmmOraclePriceData.price,
4424
- includeOpenOrders
4425
- );
4426
-
4427
- // margin ratio for this perp
4428
- const customMarginRatio = Math.max(
4429
- userCustomMarginRatio,
4430
- marketPosition.maxMarginRatio
4431
- );
4432
- let marginRatio = new BN(
4433
- calculateMarketMarginRatio(
4434
- market,
4435
- worstCaseBaseAssetAmount.abs(),
4436
- marginCategory,
4437
- customMarginRatio
4438
- )
4439
- );
4440
- if (isVariant(market.status, 'settlement')) {
4441
- marginRatio = ZERO;
4442
- }
4443
-
4444
- // convert liability to quote value and apply margin ratio
4445
- const quotePrice = strict
4446
- ? BN.max(
4447
- quoteOraclePriceData.price,
4448
- quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
4449
- )
4450
- : quoteOraclePriceData.price;
4451
- let perpMarginRequirement = worstCaseLiabilityValue
4452
- .mul(quotePrice)
4453
- .div(PRICE_PRECISION)
4454
- .mul(marginRatio)
4455
- .div(MARGIN_PRECISION);
4456
- // add open orders IM
4457
- if (includeOpenOrders) {
4458
- perpMarginRequirement = perpMarginRequirement.add(
4459
- new BN(marketPosition.openOrders).mul(OPEN_ORDER_MARGIN_REQUIREMENT)
4460
- );
4461
- }
4462
-
4463
- // weighted unrealized pnl
4464
- let positionUnrealizedPnl = calculatePositionPNL(
4465
- market,
4466
- marketPosition,
4467
- true,
4468
- oraclePriceData
4469
- );
4470
- let pnlQuotePrice: BN;
4471
- if (strict && positionUnrealizedPnl.gt(ZERO)) {
4472
- pnlQuotePrice = BN.min(
4473
- quoteOraclePriceData.price,
4474
- quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
4475
- );
4476
- } else if (strict && positionUnrealizedPnl.lt(ZERO)) {
4477
- pnlQuotePrice = BN.max(
4478
- quoteOraclePriceData.price,
4479
- quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
4480
- );
4481
- } else {
4482
- pnlQuotePrice = quoteOraclePriceData.price;
4483
- }
4484
- positionUnrealizedPnl = positionUnrealizedPnl
4485
- .mul(pnlQuotePrice)
4486
- .div(PRICE_PRECISION);
4487
-
4488
- if (marginCategory !== undefined) {
4489
- if (positionUnrealizedPnl.gt(ZERO)) {
4490
- positionUnrealizedPnl = positionUnrealizedPnl
4491
- .mul(
4492
- calculateUnrealizedAssetWeight(
4493
- market,
4494
- quoteSpotMarket,
4495
- positionUnrealizedPnl,
4496
- marginCategory,
4497
- oraclePriceData
4498
- )
4499
- )
4500
- .div(new BN(SPOT_MARKET_WEIGHT_PRECISION));
4501
- }
4502
- }
4503
-
4504
- // Add perp contribution: isolated vs cross
4505
- const isIsolated = this.isPerpPositionIsolated(marketPosition);
4506
- if (isIsolated) {
4507
- // derive isolated quote deposit value, mirroring on-chain logic
4508
- let depositValue = ZERO;
4509
- if (marketPosition.isolatedPositionScaledBalance?.gt(ZERO)) {
4510
- const quoteSpotMarket =
4511
- this.velocityClient.getSpotMarketAccountOrThrow(
4512
- market.quoteSpotMarketIndex
4513
- );
4514
- const quoteOraclePriceData = this.getOracleDataForSpotMarket(
4515
- market.quoteSpotMarketIndex
4516
- );
4517
- const strictQuote = new StrictOraclePrice(
4518
- quoteOraclePriceData.price,
4519
- strict
4520
- ? quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
4521
- : undefined
4522
- );
4523
- const quoteTokenAmount = getTokenAmount(
4524
- marketPosition.isolatedPositionScaledBalance ?? ZERO,
4525
- quoteSpotMarket,
4526
- SpotBalanceType.DEPOSIT
4527
- );
4528
- depositValue = getStrictTokenValue(
4529
- quoteTokenAmount,
4530
- quoteSpotMarket.decimals,
4531
- strictQuote
4532
- );
4533
- }
4534
- calc.addIsolatedMarginCalculation(
4535
- market.marketIndex,
4536
- depositValue,
4537
- positionUnrealizedPnl,
4538
- worstCaseLiabilityValue,
4539
- perpMarginRequirement
4540
- );
4541
- calc.addPerpLiabilityValue(worstCaseLiabilityValue);
4542
- } else {
4543
- // cross: add to global requirement and collateral
4544
- calc.addCrossMarginRequirement(
4545
- perpMarginRequirement,
4546
- worstCaseLiabilityValue
4547
- );
4548
- calc.addCrossMarginTotalCollateral(positionUnrealizedPnl);
4549
- }
4550
- }
4551
- return calc;
4552
- }
4553
-
4554
- public isPerpPositionIsolated(perpPosition: PerpPosition): boolean {
4555
- return (perpPosition.positionFlag & PositionFlag.IsolatedPosition) !== 0;
4556
- }
4557
- }