@velocity-exchange/sdk 0.4.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/README.md +3 -3
  2. package/lib/browser/adminClient.d.ts +52 -0
  3. package/lib/browser/adminClient.js +97 -0
  4. package/lib/browser/config.js +6 -7
  5. package/lib/browser/constants/numericConstants.d.ts +1 -1
  6. package/lib/browser/constants/numericConstants.js +1 -1
  7. package/lib/browser/decode/user.js +5 -1
  8. package/lib/browser/idl/velocity.d.ts +191 -15
  9. package/lib/browser/idl/velocity.json +192 -16
  10. package/lib/browser/orderSubscriber/OrderSubscriber.d.ts +1 -0
  11. package/lib/browser/orderSubscriber/OrderSubscriber.js +10 -4
  12. package/lib/browser/pyth/pythLazerSubscriber.js +37 -27
  13. package/lib/browser/types.d.ts +6 -0
  14. package/lib/browser/user.d.ts +20 -3
  15. package/lib/browser/user.js +52 -4
  16. package/lib/browser/velocityClient.d.ts +46 -10
  17. package/lib/browser/velocityClient.js +107 -35
  18. package/lib/node/adminClient.d.ts +52 -0
  19. package/lib/node/adminClient.d.ts.map +1 -1
  20. package/lib/node/adminClient.js +97 -0
  21. package/lib/node/config.d.ts.map +1 -1
  22. package/lib/node/config.js +6 -7
  23. package/lib/node/constants/numericConstants.d.ts +1 -1
  24. package/lib/node/constants/numericConstants.d.ts.map +1 -1
  25. package/lib/node/constants/numericConstants.js +1 -1
  26. package/lib/node/decode/user.d.ts.map +1 -1
  27. package/lib/node/decode/user.js +5 -1
  28. package/lib/node/idl/velocity.d.ts +191 -15
  29. package/lib/node/idl/velocity.d.ts.map +1 -1
  30. package/lib/node/idl/velocity.json +192 -16
  31. package/lib/node/orderSubscriber/OrderSubscriber.d.ts +1 -0
  32. package/lib/node/orderSubscriber/OrderSubscriber.d.ts.map +1 -1
  33. package/lib/node/orderSubscriber/OrderSubscriber.js +10 -4
  34. package/lib/node/pyth/pythLazerSubscriber.d.ts.map +1 -1
  35. package/lib/node/pyth/pythLazerSubscriber.js +37 -27
  36. package/lib/node/types.d.ts +6 -0
  37. package/lib/node/types.d.ts.map +1 -1
  38. package/lib/node/user.d.ts +20 -3
  39. package/lib/node/user.d.ts.map +1 -1
  40. package/lib/node/user.js +52 -4
  41. package/lib/node/velocityClient.d.ts +46 -10
  42. package/lib/node/velocityClient.d.ts.map +1 -1
  43. package/lib/node/velocityClient.js +107 -35
  44. package/package.json +7 -3
  45. package/.prettierignore +0 -1
  46. package/CHANGELOG.md +0 -132
  47. package/build-browser.js +0 -58
  48. package/bunfig.toml +0 -3
  49. package/esbuild-shims.js +0 -12
  50. package/scripts/deposit-isolated-positions.ts +0 -110
  51. package/scripts/find-flagged-users.ts +0 -213
  52. package/scripts/grpc-client-test-comparison.ts +0 -372
  53. package/scripts/grpc-multiuser-client-test-comparison.ts +0 -158
  54. package/scripts/postbuild.js +0 -95
  55. package/scripts/single-grpc-client-test.ts +0 -284
  56. package/scripts/withdraw-isolated-positions.ts +0 -174
  57. package/src/accounts/README_WebSocketAccountSubscriberV2.md +0 -95
  58. package/src/accounts/README_WebSocketProgramAccountSubscriberV2.md +0 -135
  59. package/src/accounts/basicUserAccountSubscriber.ts +0 -79
  60. package/src/accounts/basicUserStatsAccountSubscriber.ts +0 -87
  61. package/src/accounts/bulkAccountLoader.ts +0 -358
  62. package/src/accounts/bulkUserStatsSubscription.ts +0 -40
  63. package/src/accounts/bulkUserSubscription.ts +0 -39
  64. package/src/accounts/customizedCadenceBulkAccountLoader.ts +0 -250
  65. package/src/accounts/fetch.ts +0 -200
  66. package/src/accounts/grpcAccountSubscriber.ts +0 -225
  67. package/src/accounts/grpcInsuranceFundStakeAccountSubscriber.ts +0 -73
  68. package/src/accounts/grpcMultiAccountSubscriber.ts +0 -566
  69. package/src/accounts/grpcMultiUserAccountSubscriber.ts +0 -328
  70. package/src/accounts/grpcProgramAccountSubscriber.ts +0 -264
  71. package/src/accounts/grpcUserAccountSubscriber.ts +0 -63
  72. package/src/accounts/grpcUserStatsAccountSubscriber.ts +0 -65
  73. package/src/accounts/grpcVelocityClientAccountSubscriber.ts +0 -257
  74. package/src/accounts/grpcVelocityClientAccountSubscriberV2.ts +0 -941
  75. package/src/accounts/laserProgramAccountSubscriber.ts +0 -266
  76. package/src/accounts/oneShotUserAccountSubscriber.ts +0 -88
  77. package/src/accounts/oneShotUserStatsAccountSubscriber.ts +0 -94
  78. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -223
  79. package/src/accounts/pollingOracleAccountSubscriber.ts +0 -151
  80. package/src/accounts/pollingTokenAccountSubscriber.ts +0 -147
  81. package/src/accounts/pollingUserAccountSubscriber.ts +0 -198
  82. package/src/accounts/pollingUserStatsAccountSubscriber.ts +0 -180
  83. package/src/accounts/pollingVelocityClientAccountSubscriber.ts +0 -774
  84. package/src/accounts/testBulkAccountLoader.ts +0 -59
  85. package/src/accounts/types.ts +0 -428
  86. package/src/accounts/utils.ts +0 -90
  87. package/src/accounts/webSocketAccountSubscriber.ts +0 -304
  88. package/src/accounts/webSocketAccountSubscriberV2.ts +0 -536
  89. package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +0 -171
  90. package/src/accounts/webSocketProgramAccountSubscriber.ts +0 -244
  91. package/src/accounts/webSocketProgramAccountSubscriberV2.ts +0 -1048
  92. package/src/accounts/webSocketProgramAccountsSubscriberV2.ts +0 -1042
  93. package/src/accounts/webSocketUserAccountSubscriber.ts +0 -139
  94. package/src/accounts/webSocketUserStatsAccountSubsriber.ts +0 -131
  95. package/src/accounts/webSocketVelocityClientAccountSubscriber.ts +0 -865
  96. package/src/accounts/webSocketVelocityClientAccountSubscriberV2.ts +0 -897
  97. package/src/accounts/websocketProgramUserAccountSubscriber.ts +0 -127
  98. package/src/addresses/marketAddresses.ts +0 -28
  99. package/src/addresses/pda.ts +0 -620
  100. package/src/adminClient.ts +0 -8136
  101. package/src/assert/assert.ts +0 -5
  102. package/src/auctionSubscriber/auctionSubscriber.ts +0 -86
  103. package/src/auctionSubscriber/auctionSubscriberGrpc.ts +0 -99
  104. package/src/auctionSubscriber/index.ts +0 -9
  105. package/src/auctionSubscriber/types.ts +0 -30
  106. package/src/bankrun/bankrunConnection.ts +0 -630
  107. package/src/blockhashSubscriber/BlockhashSubscriber.ts +0 -160
  108. package/src/blockhashSubscriber/index.ts +0 -6
  109. package/src/blockhashSubscriber/types.ts +0 -13
  110. package/src/clock/clockSubscriber.ts +0 -146
  111. package/src/config.ts +0 -312
  112. package/src/constants/index.ts +0 -9
  113. package/src/constants/numericConstants.ts +0 -194
  114. package/src/constants/perpMarkets.ts +0 -127
  115. package/src/constants/spotMarkets.ts +0 -104
  116. package/src/constants/txConstants.ts +0 -2
  117. package/src/constituentMap/constituentMap.ts +0 -305
  118. package/src/constituentMap/pollingConstituentAccountSubscriber.ts +0 -99
  119. package/src/constituentMap/webSocketConstituentAccountSubscriber.ts +0 -121
  120. package/src/core/VelocityCore.ts +0 -606
  121. package/src/core/index.ts +0 -12
  122. package/src/core/instructions/deposit.ts +0 -64
  123. package/src/core/instructions/fill.ts +0 -51
  124. package/src/core/instructions/funding.ts +0 -33
  125. package/src/core/instructions/liquidation.ts +0 -55
  126. package/src/core/instructions/orders.ts +0 -84
  127. package/src/core/instructions/perpOrders.ts +0 -312
  128. package/src/core/instructions/settlement.ts +0 -40
  129. package/src/core/instructions/trigger.ts +0 -41
  130. package/src/core/instructions/withdraw.ts +0 -65
  131. package/src/core/remainingAccounts.ts +0 -320
  132. package/src/core/signedMsg.ts +0 -109
  133. package/src/decode/customCoder.ts +0 -148
  134. package/src/decode/user.ts +0 -401
  135. package/src/dlob/DLOB.ts +0 -2793
  136. package/src/dlob/DLOBNode.ts +0 -305
  137. package/src/dlob/DLOBSubscriber.ts +0 -269
  138. package/src/dlob/NodeList.ts +0 -244
  139. package/src/dlob/orderBookLevels.ts +0 -695
  140. package/src/dlob/types.ts +0 -37
  141. package/src/events/eventList.ts +0 -114
  142. package/src/events/eventSubscriber.ts +0 -521
  143. package/src/events/eventsServerLogProvider.ts +0 -189
  144. package/src/events/fetchLogs.ts +0 -219
  145. package/src/events/parse.ts +0 -271
  146. package/src/events/pollingLogProvider.ts +0 -113
  147. package/src/events/sort.ts +0 -51
  148. package/src/events/txEventCache.ts +0 -92
  149. package/src/events/types.ts +0 -337
  150. package/src/events/webSocketLogProvider.ts +0 -152
  151. package/src/factory/bigNum.ts +0 -709
  152. package/src/factory/oracleClient.ts +0 -73
  153. package/src/idl/pyth.json +0 -142
  154. package/src/idl/pyth.ts +0 -97
  155. package/src/idl/pyth_solana_receiver.json +0 -628
  156. package/src/idl/token_faucet.json +0 -229
  157. package/src/idl/token_faucet.ts +0 -197
  158. package/src/idl/velocity.json +0 -23974
  159. package/src/idl/velocity.ts +0 -23980
  160. package/src/index.ts +0 -150
  161. package/src/indicative-quotes/indicativeQuotesSender.ts +0 -233
  162. package/src/isomorphic/README.md +0 -19
  163. package/src/isomorphic/anchor.browser.ts +0 -44
  164. package/src/isomorphic/anchor.node.ts +0 -1
  165. package/src/isomorphic/anchor.ts +0 -1
  166. package/src/isomorphic/anchor29.browser.ts +0 -24
  167. package/src/isomorphic/anchor29.node.ts +0 -1
  168. package/src/isomorphic/anchor29.ts +0 -1
  169. package/src/isomorphic/grpc.browser.ts +0 -4
  170. package/src/isomorphic/grpc.node.ts +0 -130
  171. package/src/isomorphic/grpc.ts +0 -1
  172. package/src/jupiter/jupiterClient.ts +0 -502
  173. package/src/keypair.ts +0 -32
  174. package/src/margin/README.md +0 -138
  175. package/src/marginCalculation.ts +0 -407
  176. package/src/marinade/idl/idl.json +0 -1962
  177. package/src/marinade/index.ts +0 -73
  178. package/src/marinade/types.ts +0 -3925
  179. package/src/math/amm.ts +0 -1758
  180. package/src/math/auction.ts +0 -480
  181. package/src/math/bankruptcy.ts +0 -138
  182. package/src/math/builder.ts +0 -130
  183. package/src/math/conversion.ts +0 -45
  184. package/src/math/exchangeStatus.ts +0 -261
  185. package/src/math/funding.ts +0 -498
  186. package/src/math/insurance.ts +0 -171
  187. package/src/math/liquidation.ts +0 -433
  188. package/src/math/margin.ts +0 -327
  189. package/src/math/market.ts +0 -487
  190. package/src/math/oracles.ts +0 -477
  191. package/src/math/orders.ts +0 -500
  192. package/src/math/position.ts +0 -381
  193. package/src/math/repeg.ts +0 -223
  194. package/src/math/spotBalance.ts +0 -996
  195. package/src/math/spotMarket.ts +0 -115
  196. package/src/math/spotPosition.ts +0 -263
  197. package/src/math/state.ts +0 -71
  198. package/src/math/superStake.ts +0 -602
  199. package/src/math/tiers.ts +0 -73
  200. package/src/math/trade.ts +0 -879
  201. package/src/math/utils.ts +0 -183
  202. package/src/memcmp.ts +0 -279
  203. package/src/oracles/oracleClientCache.ts +0 -41
  204. package/src/oracles/oracleId.ts +0 -99
  205. package/src/oracles/prelaunchOracleClient.ts +0 -63
  206. package/src/oracles/pythClient.ts +0 -125
  207. package/src/oracles/pythLazerClient.ts +0 -141
  208. package/src/oracles/quoteAssetOracleClient.ts +0 -43
  209. package/src/oracles/strictOraclePrice.ts +0 -40
  210. package/src/oracles/types.ts +0 -82
  211. package/src/oracles/utils.ts +0 -45
  212. package/src/orderParams.ts +0 -117
  213. package/src/orderSubscriber/OrderSubscriber.ts +0 -378
  214. package/src/orderSubscriber/PollingSubscription.ts +0 -50
  215. package/src/orderSubscriber/WebsocketSubscription.ts +0 -137
  216. package/src/orderSubscriber/grpcSubscription.ts +0 -155
  217. package/src/orderSubscriber/index.ts +0 -7
  218. package/src/orderSubscriber/types.ts +0 -64
  219. package/src/priorityFee/averageOverSlotsStrategy.ts +0 -17
  220. package/src/priorityFee/averageStrategy.ts +0 -13
  221. package/src/priorityFee/ewmaStrategy.ts +0 -51
  222. package/src/priorityFee/heliusPriorityFeeMethod.ts +0 -68
  223. package/src/priorityFee/index.ts +0 -16
  224. package/src/priorityFee/maxOverSlotsStrategy.ts +0 -18
  225. package/src/priorityFee/maxStrategy.ts +0 -8
  226. package/src/priorityFee/priorityFeeSubscriber.ts +0 -328
  227. package/src/priorityFee/priorityFeeSubscriberMap.ts +0 -134
  228. package/src/priorityFee/solanaPriorityFeeMethod.ts +0 -46
  229. package/src/priorityFee/types.ts +0 -82
  230. package/src/priorityFee/velocityPriorityFeeMethod.ts +0 -53
  231. package/src/pyth/constants.ts +0 -9
  232. package/src/pyth/index.ts +0 -15
  233. package/src/pyth/pythLazerSubscriber.ts +0 -365
  234. package/src/pyth/types.ts +0 -4451
  235. package/src/pyth/utils.ts +0 -13
  236. package/src/slot/SlotSubscriber.ts +0 -126
  237. package/src/slot/SlothashSubscriber.ts +0 -163
  238. package/src/swap/UnifiedSwapClient.ts +0 -315
  239. package/src/swift/grpcSignedMsgUserAccountSubscriber.ts +0 -81
  240. package/src/swift/index.ts +0 -10
  241. package/src/swift/signedMsgUserAccountSubscriber.ts +0 -251
  242. package/src/swift/swiftOrderSubscriber.ts +0 -351
  243. package/src/testClient.ts +0 -42
  244. package/src/titan/titanClient.ts +0 -438
  245. package/src/token/index.ts +0 -13
  246. package/src/tokenFaucet.ts +0 -296
  247. package/src/tx/baseTxSender.ts +0 -651
  248. package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +0 -31
  249. package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +0 -105
  250. package/src/tx/blockhashFetcher/types.ts +0 -9
  251. package/src/tx/fastSingleTxSender.ts +0 -200
  252. package/src/tx/forwardOnlyTxSender.ts +0 -193
  253. package/src/tx/priorityFeeCalculator.ts +0 -117
  254. package/src/tx/reportTransactionError.ts +0 -176
  255. package/src/tx/retryTxSender.ts +0 -177
  256. package/src/tx/txHandler.ts +0 -1009
  257. package/src/tx/txParamProcessor.ts +0 -225
  258. package/src/tx/types.ts +0 -117
  259. package/src/tx/utils.ts +0 -133
  260. package/src/tx/whileValidTxSender.ts +0 -377
  261. package/src/types.ts +0 -2575
  262. package/src/user.ts +0 -5316
  263. package/src/userConfig.ts +0 -38
  264. package/src/userMap/PollingSubscription.ts +0 -61
  265. package/src/userMap/WebsocketSubscription.ts +0 -93
  266. package/src/userMap/grpcSubscription.ts +0 -93
  267. package/src/userMap/referrerMap.ts +0 -360
  268. package/src/userMap/revenueShareEscrowMap.ts +0 -342
  269. package/src/userMap/userMap.ts +0 -784
  270. package/src/userMap/userMapConfig.ts +0 -82
  271. package/src/userMap/userStatsMap.ts +0 -393
  272. package/src/userName.ts +0 -37
  273. package/src/userStats.ts +0 -159
  274. package/src/userStatsConfig.ts +0 -35
  275. package/src/util/TransactionConfirmationManager.ts +0 -333
  276. package/src/util/chainClock.ts +0 -65
  277. package/src/util/computeUnits.ts +0 -101
  278. package/src/util/digest.ts +0 -33
  279. package/src/util/ed25519Utils.ts +0 -95
  280. package/src/util/promiseTimeout.ts +0 -23
  281. package/src/velocityClient.ts +0 -14802
  282. package/src/velocityClientConfig.ts +0 -119
  283. package/src/wallet.ts +0 -91
  284. package/tests/VelocityCore/builder_escrow.test.ts +0 -121
  285. package/tests/VelocityCore/decode.test.ts +0 -16
  286. package/tests/VelocityCore/fill_trigger.test.ts +0 -73
  287. package/tests/VelocityCore/instructions.test.ts +0 -46
  288. package/tests/VelocityCore/pdas.test.ts +0 -30
  289. package/tests/VelocityCore/perp_orders.test.ts +0 -205
  290. package/tests/VelocityCore/remainingAccounts.test.ts +0 -72
  291. package/tests/VelocityCore/settlement_liquidation.test.ts +0 -69
  292. package/tests/accounts/customizedCadenceBulkAccountLoader.test.ts +0 -211
  293. package/tests/amm/test.ts +0 -2402
  294. package/tests/auctions/test.ts +0 -81
  295. package/tests/bn/test.ts +0 -355
  296. package/tests/builder/builderFee.test.ts +0 -42
  297. package/tests/ci/verifyConstants.ts +0 -393
  298. package/tests/decode/test.ts +0 -262
  299. package/tests/decode/userAccountBufferStrings.ts +0 -102
  300. package/tests/dlob/helpers.ts +0 -748
  301. package/tests/dlob/test.ts +0 -6969
  302. package/tests/dlob/tickSizeStandardization.ts +0 -545
  303. package/tests/events/parseLogsForCuUsage.ts +0 -139
  304. package/tests/exchangeStatus/test.ts +0 -45
  305. package/tests/insurance/test.ts +0 -40
  306. package/tests/liquidation/test.ts +0 -125
  307. package/tests/oracles/mmOracleGate.test.ts +0 -379
  308. package/tests/oracles/pythPegSnap.test.ts +0 -76
  309. package/tests/sdkParity/enumParity.test.ts +0 -84
  310. package/tests/sdkParity/marginCategoryFill.test.ts +0 -143
  311. package/tests/sdkParity/memcmpOffsets.test.ts +0 -139
  312. package/tests/spot/test.ts +0 -281
  313. package/tests/tx/TransactionConfirmationManager.test.ts +0 -312
  314. package/tests/tx/cachedBlockhashFetcher.test.ts +0 -96
  315. package/tests/tx/priorityFeeCalculator.ts +0 -77
  316. package/tests/tx/priorityFeeStrategy.ts +0 -95
  317. package/tests/user/bankruptcy.ts +0 -165
  318. package/tests/user/feeAndWithdrawLimits.ts +0 -284
  319. package/tests/user/getMarginCalculation.ts +0 -586
  320. package/tests/user/helpers.ts +0 -184
  321. package/tests/user/liquidations.ts +0 -129
  322. package/tests/user/marginCalculations.test.ts +0 -321
  323. package/tests/user/test.ts +0 -833
  324. package/tsconfig.browser.json +0 -18
  325. package/tsconfig.json +0 -36
package/src/math/trade.ts DELETED
@@ -1,879 +0,0 @@
1
- import {
2
- MarketType,
3
- PerpMarketAccount,
4
- PositionDirection,
5
- UserStatsAccount,
6
- } from '../types';
7
- import { BN } from '../isomorphic/anchor';
8
- import { assert } from '../assert/assert';
9
- import {
10
- PRICE_PRECISION,
11
- PEG_PRECISION,
12
- AMM_TO_QUOTE_PRECISION_RATIO,
13
- ZERO,
14
- BASE_PRECISION,
15
- BN_MAX,
16
- } from '../constants/numericConstants';
17
- import {
18
- calculateBidPrice,
19
- calculateAskPrice,
20
- calculateReservePrice,
21
- } from './market';
22
- import {
23
- calculateAmmReservesAfterSwap,
24
- calculatePrice,
25
- getSwapDirection,
26
- AssetType,
27
- calculateUpdatedAMMSpreadReserves,
28
- calculateQuoteAssetAmountSwapped,
29
- calculateMarketOpenBidAsk,
30
- } from './amm';
31
- import { squareRootBN } from './utils';
32
- import { isVariant } from '../types';
33
- import { MMOraclePriceData } from '../oracles/types';
34
- import { DLOB } from '../dlob/DLOB';
35
- import { PublicKey } from '@solana/web3.js';
36
- import { L2OrderBook } from '../dlob/orderBookLevels';
37
-
38
- const MAXPCT = new BN(1000); //percentage units are [0,1000] => [0,1]
39
-
40
- /**
41
- * Enumerates the price-impact-related fields historically produced by trade-slippage helpers.
42
- * Not currently consumed as a parameter/return type by any function in this file — kept for
43
- * backward compatibility with callers that reference it as a key type.
44
- */
45
- export type PriceImpactUnit =
46
- | 'entryPrice'
47
- | 'maxPrice'
48
- | 'priceDelta'
49
- | 'priceDeltaAsNumber'
50
- | 'pctAvg'
51
- | 'pctMax'
52
- | 'quoteAssetAmount'
53
- | 'quoteAssetAmountPeg'
54
- | 'acquiredBaseAssetAmount'
55
- | 'acquiredQuoteAssetAmount'
56
- | 'all';
57
-
58
- /**
59
- * Calculates avg/max slippage (price impact) for a hypothetical AMM-only trade.
60
- *
61
- * @deprecated Use `calculateEstimatedPerpEntryPrice` instead (this ignores DLOB liquidity and
62
- * only swaps against the vAMM).
63
- *
64
- * @param {PositionDirection} direction - Taker's trade direction
65
- * @param {BN} amount - Trade size in `inputAssetType` units (base: BASE_PRECISION (1e9); quote: QUOTE_PRECISION (1e6))
66
- * @param {PerpMarketAccount} market - The perp market account
67
- * @param {AssetType} [inputAssetType] - Whether `amount` denominates base or quote; defaults to `'quote'`
68
- * @param {MMOraclePriceData} mmOraclePriceData - MM oracle price data used for spread reserve calc
69
- * @param {boolean} [useSpread] - Whether to consider the bid/ask spread when computing slippage; defaults to `true`
70
- * @param {BN} [latestSlot] - Slot used for spread-reserve staleness/decay calc when `useSpread` is true
71
- * @return {[BN, BN, BN, BN]} `[pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]`, all
72
- * PRICE_PRECISION (1e6): `pctAvgSlippage` is the percentage change from the pre-trade price to
73
- * `entryPrice` (average execution slippage); `pctMaxSlippage` is the percentage change from the
74
- * pre-trade price to `newPrice` (worst-case/marginal slippage); `entryPrice` is the trade's
75
- * average execution price; `newPrice` is the AMM's price after the trade
76
- */
77
- export function calculateTradeSlippage(
78
- direction: PositionDirection,
79
- amount: BN,
80
- market: PerpMarketAccount,
81
- inputAssetType: AssetType = 'quote',
82
- mmOraclePriceData: MMOraclePriceData,
83
- useSpread = true,
84
- latestSlot?: BN
85
- ): [BN, BN, BN, BN] {
86
- let oldPrice: BN;
87
-
88
- if (useSpread && market.amm.baseSpread > 0) {
89
- if (isVariant(direction, 'long')) {
90
- oldPrice = calculateAskPrice(market, mmOraclePriceData);
91
- } else {
92
- oldPrice = calculateBidPrice(market, mmOraclePriceData);
93
- }
94
- } else {
95
- oldPrice = calculateReservePrice(market, mmOraclePriceData);
96
- }
97
- if (amount.eq(ZERO)) {
98
- return [ZERO, ZERO, oldPrice, oldPrice];
99
- }
100
- const [acquiredBaseReserve, acquiredQuoteReserve, acquiredQuoteAssetAmount] =
101
- calculateTradeAcquiredAmounts(
102
- direction,
103
- amount,
104
- market,
105
- inputAssetType,
106
- mmOraclePriceData,
107
- useSpread
108
- );
109
-
110
- const entryPrice = acquiredQuoteAssetAmount
111
- .mul(AMM_TO_QUOTE_PRECISION_RATIO)
112
- .mul(PRICE_PRECISION)
113
- .div(acquiredBaseReserve.abs());
114
-
115
- let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
116
- if (useSpread && market.amm.baseSpread > 0) {
117
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
118
- calculateUpdatedAMMSpreadReserves(
119
- market.amm,
120
- market.marketStats,
121
- direction,
122
- mmOraclePriceData,
123
- latestSlot
124
- );
125
- amm = {
126
- baseAssetReserve,
127
- quoteAssetReserve,
128
- sqrtK: sqrtK,
129
- pegMultiplier: newPeg,
130
- };
131
- } else {
132
- amm = market.amm;
133
- }
134
-
135
- const newPrice = calculatePrice(
136
- amm.baseAssetReserve.sub(acquiredBaseReserve),
137
- amm.quoteAssetReserve.sub(acquiredQuoteReserve),
138
- amm.pegMultiplier
139
- );
140
-
141
- if (direction == PositionDirection.SHORT) {
142
- assert(newPrice.lte(oldPrice));
143
- } else {
144
- assert(oldPrice.lte(newPrice));
145
- }
146
-
147
- const pctMaxSlippage = newPrice
148
- .sub(oldPrice)
149
- .mul(PRICE_PRECISION)
150
- .div(oldPrice)
151
- .abs();
152
- const pctAvgSlippage = entryPrice
153
- .sub(oldPrice)
154
- .mul(PRICE_PRECISION)
155
- .div(oldPrice)
156
- .abs();
157
-
158
- return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice];
159
- }
160
-
161
- /**
162
- * Calculates the AMM reserve deltas and resulting quote amount for a hypothetical constant-product
163
- * swap against the vAMM, without executing anything on-chain.
164
- *
165
- * @param {PositionDirection} direction - Taker's trade direction
166
- * @param {BN} amount - Trade size in `inputAssetType` units (base: BASE_PRECISION (1e9); quote: QUOTE_PRECISION (1e6))
167
- * @param {PerpMarketAccount} market - The perp market account
168
- * @param {AssetType} [inputAssetType] - Whether `amount` denominates base or quote; defaults to `'quote'`
169
- * @param {MMOraclePriceData} mmOraclePriceData - MM oracle price data used for spread reserve calc
170
- * @param {boolean} [useSpread] - Whether to swap against the spread-adjusted reserves (bid/ask)
171
- * rather than the raw reserves; defaults to `true`
172
- * @param {BN} [latestSlot] - Slot used for spread-reserve staleness/decay calc when `useSpread` is true
173
- * @return {[BN, BN, BN]} `[acquiredBase, acquiredQuote, acquiredQuoteAssetAmount]` — the change
174
- * in the AMM's base and quote reserves (signed, `AMM_RESERVE_PRECISION` (1e9)), and the
175
- * resulting user-facing quote amount swapped, `QUOTE_PRECISION` (1e6)
176
- */
177
- export function calculateTradeAcquiredAmounts(
178
- direction: PositionDirection,
179
- amount: BN,
180
- market: PerpMarketAccount,
181
- inputAssetType: AssetType = 'quote',
182
- mmOraclePriceData: MMOraclePriceData,
183
- useSpread = true,
184
- latestSlot?: BN
185
- ): [BN, BN, BN] {
186
- if (amount.eq(ZERO)) {
187
- return [ZERO, ZERO, ZERO];
188
- }
189
-
190
- const swapDirection = getSwapDirection(inputAssetType, direction);
191
-
192
- let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
193
- if (useSpread && market.amm.baseSpread > 0) {
194
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
195
- calculateUpdatedAMMSpreadReserves(
196
- market.amm,
197
- market.marketStats,
198
- direction,
199
- mmOraclePriceData,
200
- latestSlot
201
- );
202
- amm = {
203
- baseAssetReserve,
204
- quoteAssetReserve,
205
- sqrtK: sqrtK,
206
- pegMultiplier: newPeg,
207
- };
208
- } else {
209
- amm = market.amm;
210
- }
211
-
212
- const [newQuoteAssetReserve, newBaseAssetReserve] =
213
- calculateAmmReservesAfterSwap(amm, inputAssetType, amount, swapDirection);
214
-
215
- const acquiredBase = amm.baseAssetReserve.sub(newBaseAssetReserve);
216
- const acquiredQuote = amm.quoteAssetReserve.sub(newQuoteAssetReserve);
217
- const acquiredQuoteAssetAmount = calculateQuoteAssetAmountSwapped(
218
- acquiredQuote.abs(),
219
- amm.pegMultiplier,
220
- swapDirection
221
- );
222
-
223
- return [acquiredBase, acquiredQuote, acquiredQuoteAssetAmount];
224
- }
225
-
226
- /**
227
- * Calculates the AMM-only trade (direction + size) required to push the market's reserve price
228
- * to (or `pct` of the way to) `targetPrice` — a simple arbitrage-sizing helper.
229
- *
230
- * @deprecated No longer actively maintained; ignores DLOB liquidity.
231
- *
232
- * @param {PerpMarketAccount} market - The perp market account
233
- * @param {BN} targetPrice - The price to arbitrage toward, PRICE_PRECISION (1e6)
234
- * @param {BN} [pct] - Fraction of the full price gap to close, out of `MAXPCT` (1000 = 100%);
235
- * defaults to fully closing the gap
236
- * @param {AssetType} [outputAssetType] - Whether the returned trade size is denominated in base
237
- * or quote; defaults to `'quote'`
238
- * @param {MMOraclePriceData} [mmOraclePriceData] - MM oracle price data used for spread reserve calc
239
- * @param {boolean} [useSpread] - Whether to consider the bid/ask spread when sizing the trade;
240
- * defaults to `true`. If `targetPrice` already sits within the current bid/ask spread, returns
241
- * a zero-size trade
242
- * @param {BN} [latestSlot] - Slot used for spread-reserve staleness/decay calc when `useSpread` is true
243
- * @return {[PositionDirection, BN, BN, BN]} `[direction, tradeSize, entryPrice, targetPrice]` —
244
- * `direction` required to move price toward `targetPrice`; `tradeSize` in `outputAssetType`
245
- * units (base: BASE_PRECISION (1e9); quote: QUOTE_PRECISION (1e6)); `entryPrice`/`targetPrice`
246
- * PRICE_PRECISION (1e6)
247
- */
248
- export function calculateTargetPriceTrade(
249
- market: PerpMarketAccount,
250
- targetPrice: BN,
251
- pct: BN = MAXPCT,
252
- outputAssetType: AssetType = 'quote',
253
- mmOraclePriceData?: MMOraclePriceData,
254
- useSpread = true,
255
- latestSlot?: BN
256
- ): [PositionDirection, BN, BN, BN] {
257
- assert(market.amm.baseAssetReserve.gt(ZERO));
258
- assert(targetPrice.gt(ZERO));
259
- assert(pct.lte(MAXPCT) && pct.gt(ZERO));
260
-
261
- const reservePriceBefore = calculateReservePrice(market, mmOraclePriceData);
262
- const bidPriceBefore = calculateBidPrice(market, mmOraclePriceData);
263
- const askPriceBefore = calculateAskPrice(market, mmOraclePriceData);
264
-
265
- let direction;
266
- if (targetPrice.gt(reservePriceBefore)) {
267
- const priceGap = targetPrice.sub(reservePriceBefore);
268
- const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
269
- targetPrice = reservePriceBefore.add(priceGapScaled);
270
- direction = PositionDirection.LONG;
271
- } else {
272
- const priceGap = reservePriceBefore.sub(targetPrice);
273
- const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
274
- targetPrice = reservePriceBefore.sub(priceGapScaled);
275
- direction = PositionDirection.SHORT;
276
- }
277
-
278
- let tradeSize;
279
- let baseSize;
280
-
281
- let baseAssetReserveBefore: BN;
282
- let quoteAssetReserveBefore: BN;
283
-
284
- let peg = market.amm.pegMultiplier;
285
-
286
- if (useSpread && market.amm.baseSpread > 0) {
287
- const { baseAssetReserve, quoteAssetReserve, newPeg } =
288
- calculateUpdatedAMMSpreadReserves(
289
- market.amm,
290
- market.marketStats,
291
- direction,
292
- mmOraclePriceData,
293
- latestSlot
294
- );
295
- baseAssetReserveBefore = baseAssetReserve;
296
- quoteAssetReserveBefore = quoteAssetReserve;
297
- peg = newPeg;
298
- } else {
299
- baseAssetReserveBefore = market.amm.baseAssetReserve;
300
- quoteAssetReserveBefore = market.amm.quoteAssetReserve;
301
- }
302
-
303
- const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
304
- const k = invariant.mul(PRICE_PRECISION);
305
-
306
- let baseAssetReserveAfter;
307
- let quoteAssetReserveAfter;
308
- const biasModifier = new BN(1);
309
- let markPriceAfter;
310
-
311
- if (
312
- useSpread &&
313
- targetPrice.lt(askPriceBefore) &&
314
- targetPrice.gt(bidPriceBefore)
315
- ) {
316
- // no trade, market is at target
317
- if (reservePriceBefore.gt(targetPrice)) {
318
- direction = PositionDirection.SHORT;
319
- } else {
320
- direction = PositionDirection.LONG;
321
- }
322
- tradeSize = ZERO;
323
- return [direction, tradeSize, targetPrice, targetPrice];
324
- } else if (reservePriceBefore.gt(targetPrice)) {
325
- // overestimate y2
326
- baseAssetReserveAfter = squareRootBN(
327
- k.div(targetPrice).mul(peg).div(PEG_PRECISION).sub(biasModifier)
328
- ).sub(new BN(1));
329
- quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
330
-
331
- markPriceAfter = calculatePrice(
332
- baseAssetReserveAfter,
333
- quoteAssetReserveAfter,
334
- peg
335
- );
336
- direction = PositionDirection.SHORT;
337
- tradeSize = quoteAssetReserveBefore
338
- .sub(quoteAssetReserveAfter)
339
- .mul(peg)
340
- .div(PEG_PRECISION)
341
- .div(AMM_TO_QUOTE_PRECISION_RATIO);
342
- baseSize = baseAssetReserveAfter.sub(baseAssetReserveBefore);
343
- } else if (reservePriceBefore.lt(targetPrice)) {
344
- // underestimate y2
345
- baseAssetReserveAfter = squareRootBN(
346
- k.div(targetPrice).mul(peg).div(PEG_PRECISION).add(biasModifier)
347
- ).add(new BN(1));
348
- quoteAssetReserveAfter = k.div(PRICE_PRECISION).div(baseAssetReserveAfter);
349
-
350
- markPriceAfter = calculatePrice(
351
- baseAssetReserveAfter,
352
- quoteAssetReserveAfter,
353
- peg
354
- );
355
-
356
- direction = PositionDirection.LONG;
357
- tradeSize = quoteAssetReserveAfter
358
- .sub(quoteAssetReserveBefore)
359
- .mul(peg)
360
- .div(PEG_PRECISION)
361
- .div(AMM_TO_QUOTE_PRECISION_RATIO);
362
- baseSize = baseAssetReserveBefore.sub(baseAssetReserveAfter);
363
- } else {
364
- // no trade, market is at target
365
- direction = PositionDirection.LONG;
366
- tradeSize = ZERO;
367
- return [direction, tradeSize, targetPrice, targetPrice];
368
- }
369
-
370
- let tp1 = targetPrice;
371
- let tp2 = markPriceAfter;
372
- let originalDiff = targetPrice.sub(reservePriceBefore);
373
-
374
- if (direction == PositionDirection.SHORT) {
375
- tp1 = markPriceAfter;
376
- tp2 = targetPrice;
377
- originalDiff = reservePriceBefore.sub(targetPrice);
378
- }
379
-
380
- const entryPrice = tradeSize
381
- .mul(AMM_TO_QUOTE_PRECISION_RATIO)
382
- .mul(PRICE_PRECISION)
383
- .div(baseSize.abs());
384
-
385
- assert(tp1.sub(tp2).lte(originalDiff), 'Target Price Calculation incorrect');
386
- assert(
387
- tp2.lte(tp1) || tp2.sub(tp1).abs().ltn(100000),
388
- 'Target Price Calculation incorrect' +
389
- tp2.toString() +
390
- '>=' +
391
- tp1.toString() +
392
- 'err: ' +
393
- tp2.sub(tp1).abs().toString()
394
- );
395
- if (outputAssetType == 'quote') {
396
- return [direction, tradeSize, entryPrice, targetPrice];
397
- } else {
398
- return [direction, baseSize, entryPrice, targetPrice];
399
- }
400
- }
401
-
402
- /**
403
- * Simulates walking the combined DLOB + vAMM liquidity to estimate the entry price and price
404
- * impact of a hypothetical taker order, filling against resting limit orders and the AMM's
405
- * spread-adjusted reserves in whichever is cheaper at each step. Price impact is the difference
406
- * between the estimated entry price and the best available price (top of book/AMM) before any
407
- * fill.
408
- *
409
- * @param {AssetType} assetType - Whether `amount` denominates base or quote
410
- * @param {BN} amount - Order size, `assetType === 'base'`: BASE_PRECISION (1e9); `'quote'`: QUOTE_PRECISION (1e6)
411
- * @param {PositionDirection} direction - Taker's trade direction
412
- * @param {PerpMarketAccount} market - The perp market account
413
- * @param {MMOraclePriceData} mmOraclePriceData - MM oracle price data used to price both the DLOB
414
- * resting orders and the AMM's spread-adjusted reserves
415
- * @param {DLOB} dlob - The order book to walk for resting limit orders
416
- * @param {number} slot - Current slot, used to resolve oracle-pegged/auction limit order prices
417
- * @param {Map<PublicKey, boolean>} [usersToSkip] - Maker user accounts to exclude from the fill
418
- * simulation (e.g. the taker's own resting orders); defaults to none
419
- * @return {{ entryPrice: BN; priceImpact: BN; bestPrice: BN; worstPrice: BN; baseFilled: BN;
420
- * quoteFilled: BN }} `entryPrice`/`bestPrice`/`worstPrice` are PRICE_PRECISION (1e6);
421
- * `priceImpact` is `|entryPrice - bestPrice| / bestPrice`, also scaled by PRICE_PRECISION
422
- * (1e6) but represents a ratio, not a price (e.g. `1e4` = 1% impact); `baseFilled` is
423
- * BASE_PRECISION (1e9); `quoteFilled` is QUOTE_PRECISION (1e6). All-zero only if `amount` is
424
- * zero; if liquidity runs out before `amount` fully fills, the returned fields reflect the
425
- * partial fill
426
- */
427
- export function calculateEstimatedPerpEntryPrice(
428
- assetType: AssetType,
429
- amount: BN,
430
- direction: PositionDirection,
431
- market: PerpMarketAccount,
432
- mmOraclePriceData: MMOraclePriceData,
433
- dlob: DLOB,
434
- slot: number,
435
- usersToSkip = new Map<PublicKey, boolean>()
436
- ): {
437
- entryPrice: BN;
438
- priceImpact: BN;
439
- bestPrice: BN;
440
- worstPrice: BN;
441
- baseFilled: BN;
442
- quoteFilled: BN;
443
- } {
444
- if (amount.eq(ZERO)) {
445
- return {
446
- entryPrice: ZERO,
447
- priceImpact: ZERO,
448
- bestPrice: ZERO,
449
- worstPrice: ZERO,
450
- baseFilled: ZERO,
451
- quoteFilled: ZERO,
452
- };
453
- }
454
-
455
- const takerIsLong = isVariant(direction, 'long');
456
- const limitOrders = dlob[
457
- takerIsLong ? 'getRestingLimitAsks' : 'getRestingLimitBids'
458
- ](
459
- market.marketIndex,
460
- slot,
461
- MarketType.PERP,
462
- mmOraclePriceData,
463
- undefined,
464
- market.orderTickSize
465
- );
466
-
467
- const swapDirection = getSwapDirection(assetType, direction);
468
-
469
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
470
- calculateUpdatedAMMSpreadReserves(
471
- market.amm,
472
- market.marketStats,
473
- direction,
474
- mmOraclePriceData,
475
- new BN(slot)
476
- );
477
- const amm = {
478
- baseAssetReserve,
479
- quoteAssetReserve,
480
- sqrtK: sqrtK,
481
- pegMultiplier: newPeg,
482
- };
483
-
484
- const [ammBids, ammAsks] = calculateMarketOpenBidAsk(
485
- market.amm.baseAssetReserve,
486
- market.amm.minBaseAssetReserve,
487
- market.amm.maxBaseAssetReserve,
488
- market.orderStepSize
489
- );
490
-
491
- let ammLiquidity: BN;
492
- if (assetType === 'base') {
493
- ammLiquidity = takerIsLong ? ammAsks.abs() : ammBids;
494
- } else {
495
- const [afterSwapQuoteReserves, _] = calculateAmmReservesAfterSwap(
496
- amm,
497
- 'base',
498
- takerIsLong ? ammAsks.abs() : ammBids,
499
- getSwapDirection('base', direction)
500
- );
501
-
502
- ammLiquidity = calculateQuoteAssetAmountSwapped(
503
- amm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
504
- amm.pegMultiplier,
505
- swapDirection
506
- );
507
- }
508
-
509
- const invariant = amm.sqrtK.mul(amm.sqrtK);
510
-
511
- let bestPrice = calculatePrice(
512
- amm.baseAssetReserve,
513
- amm.quoteAssetReserve,
514
- amm.pegMultiplier
515
- );
516
-
517
- let cumulativeBaseFilled = ZERO;
518
- let cumulativeQuoteFilled = ZERO;
519
-
520
- let limitOrder = limitOrders.next().value;
521
- if (limitOrder) {
522
- const limitOrderPrice = limitOrder.getPriceOrThrow(
523
- mmOraclePriceData,
524
- slot,
525
- market.orderTickSize
526
- );
527
- bestPrice = takerIsLong
528
- ? BN.min(limitOrderPrice, bestPrice)
529
- : BN.max(limitOrderPrice, bestPrice);
530
- }
531
-
532
- let worstPrice = bestPrice;
533
-
534
- if (assetType === 'base') {
535
- while (
536
- !cumulativeBaseFilled.eq(amount) &&
537
- (ammLiquidity.gt(ZERO) || limitOrder)
538
- ) {
539
- const limitOrderPrice = limitOrder?.getPrice(
540
- mmOraclePriceData,
541
- slot,
542
- market.orderTickSize
543
- );
544
-
545
- let maxAmmFill: BN;
546
- if (limitOrderPrice) {
547
- const newBaseReserves = squareRootBN(
548
- invariant
549
- .mul(PRICE_PRECISION)
550
- .mul(amm.pegMultiplier)
551
- .div(limitOrderPrice)
552
- .div(PEG_PRECISION)
553
- );
554
-
555
- // will be zero if the limit order price is better than the amm price
556
- maxAmmFill = takerIsLong
557
- ? amm.baseAssetReserve.sub(newBaseReserves)
558
- : newBaseReserves.sub(amm.baseAssetReserve);
559
- } else {
560
- maxAmmFill = amount.sub(cumulativeBaseFilled);
561
- }
562
-
563
- maxAmmFill = BN.min(maxAmmFill, ammLiquidity);
564
-
565
- if (maxAmmFill.gt(ZERO)) {
566
- const baseFilled = BN.min(amount.sub(cumulativeBaseFilled), maxAmmFill);
567
- const [afterSwapQuoteReserves, afterSwapBaseReserves] =
568
- calculateAmmReservesAfterSwap(amm, 'base', baseFilled, swapDirection);
569
-
570
- ammLiquidity = ammLiquidity.sub(baseFilled);
571
-
572
- const quoteFilled = calculateQuoteAssetAmountSwapped(
573
- amm.quoteAssetReserve.sub(afterSwapQuoteReserves).abs(),
574
- amm.pegMultiplier,
575
- swapDirection
576
- );
577
-
578
- cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
579
- cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
580
-
581
- amm.baseAssetReserve = afterSwapBaseReserves;
582
- amm.quoteAssetReserve = afterSwapQuoteReserves;
583
-
584
- worstPrice = calculatePrice(
585
- amm.baseAssetReserve,
586
- amm.quoteAssetReserve,
587
- amm.pegMultiplier
588
- );
589
-
590
- if (cumulativeBaseFilled.eq(amount)) {
591
- break;
592
- }
593
- }
594
-
595
- if (!limitOrder) {
596
- continue;
597
- }
598
-
599
- if (usersToSkip.has(limitOrder.userAccount)) {
600
- continue;
601
- }
602
-
603
- const baseFilled = BN.min(
604
- limitOrder.order.baseAssetAmount.sub(
605
- limitOrder.order.baseAssetAmountFilled
606
- ),
607
- amount.sub(cumulativeBaseFilled)
608
- );
609
- const quoteFilled = baseFilled.mul(limitOrderPrice).div(BASE_PRECISION);
610
-
611
- cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
612
- cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
613
-
614
- worstPrice = limitOrderPrice;
615
-
616
- if (cumulativeBaseFilled.eq(amount)) {
617
- break;
618
- }
619
-
620
- limitOrder = limitOrders.next().value;
621
- }
622
- } else {
623
- while (
624
- !cumulativeQuoteFilled.eq(amount) &&
625
- (ammLiquidity.gt(ZERO) || limitOrder)
626
- ) {
627
- const limitOrderPrice = limitOrder?.getPrice(
628
- mmOraclePriceData,
629
- slot,
630
- market.orderTickSize
631
- );
632
-
633
- let maxAmmFill: BN;
634
- if (limitOrderPrice) {
635
- const newQuoteReserves = squareRootBN(
636
- invariant
637
- .mul(PEG_PRECISION)
638
- .mul(limitOrderPrice)
639
- .div(amm.pegMultiplier)
640
- .div(PRICE_PRECISION)
641
- );
642
-
643
- // will be zero if the limit order price is better than the amm price
644
- maxAmmFill = takerIsLong
645
- ? newQuoteReserves.sub(amm.quoteAssetReserve)
646
- : amm.quoteAssetReserve.sub(newQuoteReserves);
647
- } else {
648
- maxAmmFill = amount.sub(cumulativeQuoteFilled);
649
- }
650
-
651
- maxAmmFill = BN.min(maxAmmFill, ammLiquidity);
652
-
653
- if (maxAmmFill.gt(ZERO)) {
654
- const quoteFilled = BN.min(
655
- amount.sub(cumulativeQuoteFilled),
656
- maxAmmFill
657
- );
658
- const [afterSwapQuoteReserves, afterSwapBaseReserves] =
659
- calculateAmmReservesAfterSwap(
660
- amm,
661
- 'quote',
662
- quoteFilled,
663
- swapDirection
664
- );
665
-
666
- ammLiquidity = ammLiquidity.sub(quoteFilled);
667
-
668
- const baseFilled = afterSwapBaseReserves
669
- .sub(amm.baseAssetReserve)
670
- .abs();
671
-
672
- cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
673
- cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
674
-
675
- amm.baseAssetReserve = afterSwapBaseReserves;
676
- amm.quoteAssetReserve = afterSwapQuoteReserves;
677
-
678
- worstPrice = calculatePrice(
679
- amm.baseAssetReserve,
680
- amm.quoteAssetReserve,
681
- amm.pegMultiplier
682
- );
683
-
684
- if (cumulativeQuoteFilled.eq(amount)) {
685
- break;
686
- }
687
- }
688
-
689
- if (!limitOrder) {
690
- continue;
691
- }
692
-
693
- if (usersToSkip.has(limitOrder.userAccount)) {
694
- continue;
695
- }
696
-
697
- const quoteFilled = BN.min(
698
- limitOrder.order.baseAssetAmount
699
- .sub(limitOrder.order.baseAssetAmountFilled)
700
- .mul(limitOrderPrice)
701
- .div(BASE_PRECISION),
702
- amount.sub(cumulativeQuoteFilled)
703
- );
704
-
705
- const baseFilled = quoteFilled.mul(BASE_PRECISION).div(limitOrderPrice);
706
-
707
- cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
708
- cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
709
-
710
- worstPrice = limitOrderPrice;
711
-
712
- if (cumulativeQuoteFilled.eq(amount)) {
713
- break;
714
- }
715
-
716
- limitOrder = limitOrders.next().value;
717
- }
718
- }
719
-
720
- const entryPrice =
721
- cumulativeBaseFilled && cumulativeBaseFilled.gt(ZERO)
722
- ? cumulativeQuoteFilled.mul(BASE_PRECISION).div(cumulativeBaseFilled)
723
- : ZERO;
724
-
725
- const priceImpact =
726
- bestPrice && bestPrice.gt(ZERO)
727
- ? entryPrice.sub(bestPrice).mul(PRICE_PRECISION).div(bestPrice).abs()
728
- : ZERO;
729
-
730
- return {
731
- entryPrice,
732
- priceImpact,
733
- bestPrice,
734
- worstPrice,
735
- baseFilled: cumulativeBaseFilled,
736
- quoteFilled: cumulativeQuoteFilled,
737
- };
738
- }
739
-
740
- /**
741
- * Estimates entry price and price impact of a hypothetical taker order by walking a pre-built L2
742
- * order book snapshot (asks for a long taker, bids for a short taker), rather than the live DLOB.
743
- * Useful when an L2 snapshot is already available and a fresh DLOB walk isn't needed.
744
- *
745
- * @param {AssetType} assetType - Whether `amount` denominates base or quote
746
- * @param {BN} amount - Order size, `basePrecision` for `'base'`; QUOTE_PRECISION (1e6) for `'quote'`
747
- * @param {PositionDirection} direction - Taker's trade direction
748
- * @param {BN} basePrecision - The base precision to use for size/price math (e.g. `BASE_PRECISION`)
749
- * @param {L2OrderBook} l2 - Pre-computed L2 order book (bids/asks with price + size levels)
750
- * @return {{ entryPrice: BN; priceImpact: BN; bestPrice: BN; worstPrice: BN; baseFilled: BN;
751
- * quoteFilled: BN }} `entryPrice`/`bestPrice`/`worstPrice` are PRICE_PRECISION (1e6);
752
- * `priceImpact` is `|entryPrice - bestPrice| / bestPrice` scaled by PRICE_PRECISION (1e6);
753
- * `baseFilled` is `basePrecision`-scaled; `quoteFilled` is QUOTE_PRECISION (1e6). If the book
754
- * is empty, `bestPrice`/`worstPrice` are `BN_MAX` (long) or `ZERO` (short) and `entryPrice`/
755
- * `priceImpact` are `ZERO`
756
- */
757
- export function calculateEstimatedEntryPriceWithL2(
758
- assetType: AssetType,
759
- amount: BN,
760
- direction: PositionDirection,
761
- basePrecision: BN,
762
- l2: L2OrderBook
763
- ): {
764
- entryPrice: BN;
765
- priceImpact: BN;
766
- bestPrice: BN;
767
- worstPrice: BN;
768
- baseFilled: BN;
769
- quoteFilled: BN;
770
- } {
771
- const takerIsLong = isVariant(direction, 'long');
772
-
773
- let cumulativeBaseFilled = ZERO;
774
- let cumulativeQuoteFilled = ZERO;
775
-
776
- const levels = [...(takerIsLong ? l2.asks : l2.bids)];
777
- let nextLevel = levels.shift();
778
-
779
- let bestPrice: BN;
780
- let worstPrice: BN;
781
- if (nextLevel) {
782
- bestPrice = nextLevel.price;
783
- worstPrice = nextLevel.price;
784
- } else {
785
- bestPrice = takerIsLong ? BN_MAX : ZERO;
786
- worstPrice = bestPrice;
787
- }
788
-
789
- if (assetType === 'base') {
790
- while (!cumulativeBaseFilled.eq(amount) && nextLevel) {
791
- const price = nextLevel.price;
792
- const size = nextLevel.size;
793
-
794
- worstPrice = price;
795
-
796
- const baseFilled = BN.min(size, amount.sub(cumulativeBaseFilled));
797
- const quoteFilled = baseFilled.mul(price).div(basePrecision);
798
-
799
- cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
800
- cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
801
-
802
- nextLevel = levels.shift();
803
- }
804
- } else {
805
- while (!cumulativeQuoteFilled.eq(amount) && nextLevel) {
806
- const price = nextLevel.price;
807
- const size = nextLevel.size;
808
-
809
- worstPrice = price;
810
-
811
- const quoteFilled = BN.min(
812
- size.mul(price).div(basePrecision),
813
- amount.sub(cumulativeQuoteFilled)
814
- );
815
- const baseFilled = quoteFilled.mul(basePrecision).div(price);
816
-
817
- cumulativeBaseFilled = cumulativeBaseFilled.add(baseFilled);
818
- cumulativeQuoteFilled = cumulativeQuoteFilled.add(quoteFilled);
819
-
820
- nextLevel = levels.shift();
821
- }
822
- }
823
-
824
- const entryPrice =
825
- cumulativeBaseFilled && cumulativeBaseFilled.gt(ZERO)
826
- ? cumulativeQuoteFilled.mul(basePrecision).div(cumulativeBaseFilled)
827
- : ZERO;
828
-
829
- const priceImpact =
830
- bestPrice && bestPrice.gt(ZERO)
831
- ? entryPrice.sub(bestPrice).mul(PRICE_PRECISION).div(bestPrice).abs()
832
- : ZERO;
833
-
834
- return {
835
- entryPrice,
836
- priceImpact,
837
- bestPrice,
838
- worstPrice,
839
- baseFilled: cumulativeBaseFilled,
840
- quoteFilled: cumulativeQuoteFilled,
841
- };
842
- }
843
-
844
- /**
845
- * Estimates a user's trailing-30-day taker + maker volume as of `now`, using the same
846
- * time-weighted decay shape as the on-chain `update_taker_volume_30d` / `update_maker_volume_30d`
847
- * (`calculate_rolling_sum`) but without requiring a new fill to trigger the on-chain update —
848
- * useful for e.g. displaying live fee-tier progress between actual `UserStats` refreshes.
849
- *
850
- * @param {UserStatsAccount} userStatsAccount - The user's stats account (`takerVolume30D`,
851
- * `makerVolume30D`, and their respective last-update timestamps)
852
- * @param {BN} [now] - Current unix timestamp (seconds); defaults to `Date.now() / 1000`
853
- * @return {BN} Estimated combined 30-day taker + maker volume, QUOTE_PRECISION (1e6)
854
- */
855
- export function getUser30dRollingVolumeEstimate(
856
- userStatsAccount: UserStatsAccount,
857
- now?: BN
858
- ) {
859
- now = now || new BN(new Date().getTime() / 1000);
860
- const sinceLastTaker = BN.max(
861
- now.sub(userStatsAccount.lastTakerVolume30DTs),
862
- ZERO
863
- );
864
- const sinceLastMaker = BN.max(
865
- now.sub(userStatsAccount.lastMakerVolume30DTs),
866
- ZERO
867
- );
868
- const thirtyDaysInSeconds = new BN(60 * 60 * 24 * 30);
869
- const last30dVolume = userStatsAccount.takerVolume30D
870
- .mul(BN.max(thirtyDaysInSeconds.sub(sinceLastTaker), ZERO))
871
- .div(thirtyDaysInSeconds)
872
- .add(
873
- userStatsAccount.makerVolume30D
874
- .mul(BN.max(thirtyDaysInSeconds.sub(sinceLastMaker), ZERO))
875
- .div(thirtyDaysInSeconds)
876
- );
877
-
878
- return last30dVolume;
879
- }