@velocity-exchange/sdk 0.0.1

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