@drift-labs/sdk 0.2.0-master.24 → 0.2.0-master.26

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 (193) hide show
  1. package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +13 -13
  2. package/lib/accounts/pollingClearingHouseAccountSubscriber.js +27 -27
  3. package/lib/accounts/types.d.ts +8 -9
  4. package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +14 -14
  5. package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +35 -34
  6. package/lib/addresses/pda.d.ts +8 -6
  7. package/lib/addresses/pda.js +35 -27
  8. package/lib/admin.d.ts +9 -6
  9. package/lib/admin.js +90 -54
  10. package/lib/clearingHouse.d.ts +71 -42
  11. package/lib/clearingHouse.js +765 -282
  12. package/lib/clearingHouseConfig.d.ts +2 -2
  13. package/lib/clearingHouseUser.d.ts +19 -17
  14. package/lib/clearingHouseUser.js +145 -123
  15. package/lib/config.d.ts +7 -7
  16. package/lib/config.js +21 -21
  17. package/lib/constants/numericConstants.d.ts +12 -12
  18. package/lib/constants/numericConstants.js +13 -13
  19. package/lib/constants/{markets.d.ts → perpMarkets.d.ts} +5 -5
  20. package/{src/constants/markets.js → lib/constants/perpMarkets.js} +4 -4
  21. package/lib/constants/{banks.d.ts → spotMarkets.d.ts} +6 -6
  22. package/lib/constants/{banks.js → spotMarkets.js} +16 -16
  23. package/lib/events/eventSubscriber.d.ts +4 -2
  24. package/lib/events/eventSubscriber.js +16 -9
  25. package/lib/events/fetchLogs.d.ts +10 -1
  26. package/lib/events/fetchLogs.js +27 -7
  27. package/lib/events/pollingLogProvider.d.ts +2 -1
  28. package/lib/events/pollingLogProvider.js +6 -2
  29. package/lib/events/types.d.ts +4 -2
  30. package/lib/events/types.js +2 -0
  31. package/lib/examples/makeTradeExample.js +18 -6
  32. package/lib/idl/clearing_house.json +1128 -347
  33. package/lib/index.d.ts +6 -3
  34. package/lib/index.js +6 -3
  35. package/lib/math/amm.d.ts +5 -3
  36. package/lib/math/amm.js +42 -4
  37. package/lib/math/funding.d.ts +6 -6
  38. package/lib/math/funding.js +2 -1
  39. package/lib/math/margin.d.ts +4 -4
  40. package/lib/math/margin.js +18 -11
  41. package/lib/math/market.d.ts +10 -9
  42. package/lib/math/market.js +29 -6
  43. package/lib/math/oracles.d.ts +2 -1
  44. package/lib/math/oracles.js +11 -1
  45. package/lib/math/orders.d.ts +5 -5
  46. package/lib/math/position.d.ts +13 -13
  47. package/lib/math/position.js +19 -19
  48. package/lib/math/spotBalance.d.ts +19 -0
  49. package/lib/math/spotBalance.js +176 -0
  50. package/lib/math/spotMarket.d.ts +4 -0
  51. package/lib/math/spotMarket.js +8 -0
  52. package/lib/math/spotPosition.d.ts +2 -0
  53. package/lib/math/spotPosition.js +8 -0
  54. package/lib/math/state.js +2 -2
  55. package/lib/math/trade.d.ts +4 -4
  56. package/lib/orderParams.d.ts +4 -4
  57. package/lib/orderParams.js +12 -4
  58. package/lib/serum/serumSubscriber.d.ts +23 -0
  59. package/lib/serum/serumSubscriber.js +41 -0
  60. package/lib/serum/types.d.ts +11 -0
  61. package/lib/serum/types.js +2 -0
  62. package/lib/tx/retryTxSender.d.ts +1 -1
  63. package/lib/tx/retryTxSender.js +4 -2
  64. package/lib/tx/types.d.ts +1 -1
  65. package/lib/types.d.ts +148 -39
  66. package/lib/types.js +37 -9
  67. package/my-script/.env +7 -0
  68. package/my-script/getUserStats.ts +106 -0
  69. package/my-script/multiConnections.ts +119 -0
  70. package/my-script/test-regex.ts +11 -0
  71. package/my-script/utils.ts +52 -0
  72. package/package.json +1 -1
  73. package/src/accounts/bulkAccountLoader.js +249 -0
  74. package/src/accounts/bulkUserStatsSubscription.js +75 -0
  75. package/src/accounts/bulkUserSubscription.js +75 -0
  76. package/src/accounts/fetch.js +92 -0
  77. package/src/accounts/pollingClearingHouseAccountSubscriber.js +465 -0
  78. package/src/accounts/pollingClearingHouseAccountSubscriber.ts +38 -38
  79. package/src/accounts/pollingOracleSubscriber.js +156 -0
  80. package/src/accounts/pollingTokenAccountSubscriber.js +141 -0
  81. package/src/accounts/pollingUserAccountSubscriber.js +208 -0
  82. package/src/accounts/pollingUserStatsAccountSubscriber.js +208 -0
  83. package/src/accounts/types.js +28 -0
  84. package/src/accounts/types.ts +11 -9
  85. package/src/accounts/utils.js +7 -0
  86. package/src/accounts/webSocketAccountSubscriber.js +138 -0
  87. package/src/accounts/webSocketClearingHouseAccountSubscriber.js +433 -0
  88. package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +59 -52
  89. package/src/accounts/webSocketUserAccountSubscriber.js +113 -0
  90. package/src/accounts/webSocketUserStatsAccountSubsriber.js +113 -0
  91. package/src/addresses/pda.js +186 -0
  92. package/src/addresses/pda.ts +56 -42
  93. package/src/admin.js +1284 -0
  94. package/src/admin.ts +149 -75
  95. package/src/assert/assert.js +1 -1
  96. package/src/clearingHouse.js +3433 -0
  97. package/src/clearingHouse.ts +1097 -380
  98. package/src/clearingHouseConfig.js +2 -0
  99. package/src/clearingHouseConfig.ts +2 -2
  100. package/src/clearingHouseUser.js +874 -0
  101. package/src/clearingHouseUser.ts +237 -172
  102. package/src/clearingHouseUserConfig.js +2 -0
  103. package/src/clearingHouseUserStats.js +115 -0
  104. package/src/clearingHouseUserStatsConfig.js +2 -0
  105. package/src/config.js +80 -0
  106. package/src/config.ts +30 -30
  107. package/src/constants/numericConstants.js +18 -11
  108. package/src/constants/numericConstants.ts +17 -15
  109. package/{lib/constants/markets.js → src/constants/perpMarkets.js} +11 -11
  110. package/src/constants/{markets.ts → perpMarkets.ts} +5 -5
  111. package/src/constants/spotMarkets.js +51 -0
  112. package/src/constants/{banks.ts → spotMarkets.ts} +19 -19
  113. package/src/events/eventList.js +66 -23
  114. package/src/events/eventSubscriber.js +202 -0
  115. package/src/events/eventSubscriber.ts +20 -12
  116. package/src/events/fetchLogs.js +117 -0
  117. package/src/events/fetchLogs.ts +35 -8
  118. package/src/events/pollingLogProvider.js +113 -0
  119. package/src/events/pollingLogProvider.ts +10 -2
  120. package/src/events/sort.js +41 -0
  121. package/src/events/txEventCache.js +22 -19
  122. package/src/events/types.js +25 -0
  123. package/src/events/types.ts +7 -1
  124. package/src/events/webSocketLogProvider.js +76 -0
  125. package/src/examples/makeTradeExample.ts +27 -6
  126. package/src/factory/bigNum.js +183 -180
  127. package/src/factory/oracleClient.js +9 -9
  128. package/src/idl/clearing_house.json +1128 -347
  129. package/src/index.js +75 -0
  130. package/src/index.ts +6 -3
  131. package/src/math/amm.js +422 -0
  132. package/src/math/amm.ts +73 -5
  133. package/src/math/auction.js +10 -10
  134. package/src/math/conversion.js +4 -3
  135. package/src/math/funding.js +223 -175
  136. package/src/math/funding.ts +7 -7
  137. package/src/math/insurance.js +27 -0
  138. package/src/math/margin.js +77 -0
  139. package/src/math/margin.ts +34 -23
  140. package/src/math/market.js +105 -0
  141. package/src/math/market.ts +71 -19
  142. package/src/math/oracles.js +40 -10
  143. package/src/math/oracles.ts +18 -1
  144. package/src/math/orders.js +153 -0
  145. package/src/math/orders.ts +5 -5
  146. package/src/math/position.js +172 -0
  147. package/src/math/position.ts +31 -31
  148. package/src/math/repeg.js +40 -40
  149. package/src/math/spotBalance.js +176 -0
  150. package/src/math/spotBalance.ts +290 -0
  151. package/src/math/spotMarket.js +8 -0
  152. package/src/math/spotMarket.ts +9 -0
  153. package/src/math/spotPosition.js +8 -0
  154. package/src/math/spotPosition.ts +6 -0
  155. package/src/math/state.ts +2 -2
  156. package/src/math/trade.js +81 -74
  157. package/src/math/trade.ts +4 -4
  158. package/src/math/utils.js +8 -7
  159. package/src/oracles/oracleClientCache.js +10 -9
  160. package/src/oracles/pythClient.js +52 -17
  161. package/src/oracles/quoteAssetOracleClient.js +44 -13
  162. package/src/oracles/switchboardClient.js +69 -37
  163. package/src/oracles/types.js +1 -1
  164. package/src/orderParams.js +14 -6
  165. package/src/orderParams.ts +16 -8
  166. package/src/serum/serumSubscriber.js +102 -0
  167. package/src/serum/serumSubscriber.ts +80 -0
  168. package/src/serum/types.js +2 -0
  169. package/src/serum/types.ts +13 -0
  170. package/src/slot/SlotSubscriber.js +67 -20
  171. package/src/token/index.js +4 -4
  172. package/src/tokenFaucet.js +288 -154
  173. package/src/tx/retryTxSender.js +280 -0
  174. package/src/tx/retryTxSender.ts +5 -2
  175. package/src/tx/types.js +1 -1
  176. package/src/tx/types.ts +2 -1
  177. package/src/tx/utils.js +7 -6
  178. package/src/types.js +216 -0
  179. package/src/types.ts +131 -39
  180. package/src/userName.js +5 -5
  181. package/src/util/computeUnits.js +46 -11
  182. package/src/util/promiseTimeout.js +5 -5
  183. package/src/util/tps.js +46 -12
  184. package/src/wallet.js +55 -18
  185. package/lib/math/bankBalance.d.ts +0 -15
  186. package/lib/math/bankBalance.js +0 -150
  187. package/src/addresses/marketAddresses.js +0 -26
  188. package/src/constants/banks.js +0 -42
  189. package/src/examples/makeTradeExample.js +0 -80
  190. package/src/math/bankBalance.ts +0 -258
  191. package/src/math/state.js +0 -15
  192. package/src/math/utils.js.map +0 -1
  193. package/src/util/getTokenAddress.js +0 -9
@@ -0,0 +1,874 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (_) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ exports.__esModule = true;
39
+ exports.ClearingHouseUser = void 0;
40
+ var types_1 = require("./types");
41
+ var position_1 = require("./math/position");
42
+ var numericConstants_1 = require("./constants/numericConstants");
43
+ var _1 = require(".");
44
+ var spotBalance_1 = require("./math/spotBalance");
45
+ var margin_1 = require("./math/margin");
46
+ var pollingUserAccountSubscriber_1 = require("./accounts/pollingUserAccountSubscriber");
47
+ var webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccountSubscriber");
48
+ var ClearingHouseUser = /** @class */ (function () {
49
+ function ClearingHouseUser(config) {
50
+ var _a;
51
+ this._isSubscribed = false;
52
+ this.clearingHouse = config.clearingHouse;
53
+ this.userAccountPublicKey = config.userAccountPublicKey;
54
+ if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
55
+ this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.clearingHouse.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
56
+ }
57
+ else {
58
+ this.accountSubscriber = new webSocketUserAccountSubscriber_1.WebSocketUserAccountSubscriber(config.clearingHouse.program, config.userAccountPublicKey);
59
+ }
60
+ this.eventEmitter = this.accountSubscriber.eventEmitter;
61
+ }
62
+ Object.defineProperty(ClearingHouseUser.prototype, "isSubscribed", {
63
+ get: function () {
64
+ return this._isSubscribed && this.accountSubscriber.isSubscribed;
65
+ },
66
+ set: function (val) {
67
+ this._isSubscribed = val;
68
+ },
69
+ enumerable: false,
70
+ configurable: true
71
+ });
72
+ /**
73
+ * Subscribe to ClearingHouseUser state accounts
74
+ * @returns SusbcriptionSuccess result
75
+ */
76
+ ClearingHouseUser.prototype.subscribe = function () {
77
+ return __awaiter(this, void 0, void 0, function () {
78
+ var _a;
79
+ return __generator(this, function (_b) {
80
+ switch (_b.label) {
81
+ case 0:
82
+ _a = this;
83
+ return [4 /*yield*/, this.accountSubscriber.subscribe()];
84
+ case 1:
85
+ _a.isSubscribed = _b.sent();
86
+ return [2 /*return*/, this.isSubscribed];
87
+ }
88
+ });
89
+ });
90
+ };
91
+ /**
92
+ * Forces the accountSubscriber to fetch account updates from rpc
93
+ */
94
+ ClearingHouseUser.prototype.fetchAccounts = function () {
95
+ return __awaiter(this, void 0, void 0, function () {
96
+ return __generator(this, function (_a) {
97
+ switch (_a.label) {
98
+ case 0: return [4 /*yield*/, this.accountSubscriber.fetch()];
99
+ case 1:
100
+ _a.sent();
101
+ return [2 /*return*/];
102
+ }
103
+ });
104
+ });
105
+ };
106
+ ClearingHouseUser.prototype.unsubscribe = function () {
107
+ return __awaiter(this, void 0, void 0, function () {
108
+ return __generator(this, function (_a) {
109
+ switch (_a.label) {
110
+ case 0: return [4 /*yield*/, this.accountSubscriber.unsubscribe()];
111
+ case 1:
112
+ _a.sent();
113
+ this.isSubscribed = false;
114
+ return [2 /*return*/];
115
+ }
116
+ });
117
+ });
118
+ };
119
+ ClearingHouseUser.prototype.getUserAccount = function () {
120
+ return this.accountSubscriber.getUserAccountAndSlot().data;
121
+ };
122
+ ClearingHouseUser.prototype.getUserAccountAndSlot = function () {
123
+ return this.accountSubscriber.getUserAccountAndSlot();
124
+ };
125
+ /**
126
+ * Gets the user's current position for a given market. If the user has no position returns undefined
127
+ * @param marketIndex
128
+ * @returns userPosition
129
+ */
130
+ ClearingHouseUser.prototype.getUserPosition = function (marketIndex) {
131
+ return this.getUserAccount().perpPositions.find(function (position) {
132
+ return position.marketIndex.eq(marketIndex);
133
+ });
134
+ };
135
+ ClearingHouseUser.prototype.getEmptyPosition = function (marketIndex) {
136
+ return {
137
+ baseAssetAmount: numericConstants_1.ZERO,
138
+ remainderBaseAssetAmount: numericConstants_1.ZERO,
139
+ lastCumulativeFundingRate: numericConstants_1.ZERO,
140
+ marketIndex: marketIndex,
141
+ quoteAssetAmount: numericConstants_1.ZERO,
142
+ quoteEntryAmount: numericConstants_1.ZERO,
143
+ openOrders: numericConstants_1.ZERO,
144
+ openBids: numericConstants_1.ZERO,
145
+ openAsks: numericConstants_1.ZERO,
146
+ realizedPnl: numericConstants_1.ZERO,
147
+ lpShares: numericConstants_1.ZERO,
148
+ lastFeePerLp: numericConstants_1.ZERO,
149
+ lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
150
+ lastNetQuoteAssetAmountPerLp: numericConstants_1.ZERO
151
+ };
152
+ };
153
+ ClearingHouseUser.prototype.getClonedPosition = function (position) {
154
+ var clonedPosition = Object.assign({}, position);
155
+ return clonedPosition;
156
+ };
157
+ /**
158
+ * @param orderId
159
+ * @returns Order
160
+ */
161
+ ClearingHouseUser.prototype.getOrder = function (orderId) {
162
+ return this.getUserAccount().orders.find(function (order) {
163
+ return order.orderId.eq(orderId);
164
+ });
165
+ };
166
+ /**
167
+ * @param userOrderId
168
+ * @returns Order
169
+ */
170
+ ClearingHouseUser.prototype.getOrderByUserOrderId = function (userOrderId) {
171
+ return this.getUserAccount().orders.find(function (order) { return order.userOrderId === userOrderId; });
172
+ };
173
+ ClearingHouseUser.prototype.getUserAccountPublicKey = function () {
174
+ return this.userAccountPublicKey;
175
+ };
176
+ ClearingHouseUser.prototype.exists = function () {
177
+ return __awaiter(this, void 0, void 0, function () {
178
+ var userAccountRPCResponse;
179
+ return __generator(this, function (_a) {
180
+ switch (_a.label) {
181
+ case 0: return [4 /*yield*/, this.clearingHouse.connection.getParsedAccountInfo(this.userAccountPublicKey)];
182
+ case 1:
183
+ userAccountRPCResponse = _a.sent();
184
+ return [2 /*return*/, userAccountRPCResponse.value !== null];
185
+ }
186
+ });
187
+ });
188
+ };
189
+ /**
190
+ * calculates the market position if the lp position was settled
191
+ * @returns : the settled userPosition
192
+ * @returns : the dust base asset amount (ie, < stepsize)
193
+ * @returns : pnl from settle
194
+ */
195
+ ClearingHouseUser.prototype.getSettledLPPosition = function (marketIndex) {
196
+ var _position = this.getUserPosition(marketIndex);
197
+ var position = this.getClonedPosition(_position);
198
+ var market = this.clearingHouse.getPerpMarketAccount(position.marketIndex);
199
+ var nShares = position.lpShares;
200
+ var deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
201
+ .sub(position.lastNetBaseAssetAmountPerLp)
202
+ .mul(nShares)
203
+ .div(numericConstants_1.AMM_RESERVE_PRECISION);
204
+ var deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
205
+ .sub(position.lastNetQuoteAssetAmountPerLp)
206
+ .mul(nShares)
207
+ .div(numericConstants_1.AMM_RESERVE_PRECISION);
208
+ function sign(v) {
209
+ var sign = { "true": new _1.BN(1), "false": new _1.BN(-1) }[v.gte(numericConstants_1.ZERO).toString()];
210
+ return sign;
211
+ }
212
+ function standardize(amount, stepsize) {
213
+ var remainder = amount.abs().mod(stepsize).mul(sign(amount));
214
+ var standardizedAmount = amount.sub(remainder);
215
+ return [standardizedAmount, remainder];
216
+ }
217
+ var _a = standardize(deltaBaa, market.amm.baseAssetAmountStepSize), standardizedBaa = _a[0], remainderBaa = _a[1];
218
+ position.remainderBaseAssetAmount =
219
+ position.remainderBaseAssetAmount.add(remainderBaa);
220
+ if (position.remainderBaseAssetAmount
221
+ .abs()
222
+ .gte(market.amm.baseAssetAmountStepSize)) {
223
+ var _b = standardize(position.remainderBaseAssetAmount, market.amm.baseAssetAmountStepSize), newStandardizedBaa = _b[0], newRemainderBaa = _b[1];
224
+ position.baseAssetAmount =
225
+ position.baseAssetAmount.add(newStandardizedBaa);
226
+ position.remainderBaseAssetAmount = newRemainderBaa;
227
+ }
228
+ var updateType;
229
+ if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
230
+ updateType = 'open';
231
+ }
232
+ else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
233
+ updateType = 'increase';
234
+ }
235
+ else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
236
+ updateType = 'reduce';
237
+ }
238
+ else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
239
+ updateType = 'close';
240
+ }
241
+ else {
242
+ updateType = 'flip';
243
+ }
244
+ var newQuoteEntry;
245
+ var pnl;
246
+ if (updateType == 'open' || updateType == 'increase') {
247
+ newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
248
+ pnl = 0;
249
+ }
250
+ else if (updateType == 'reduce' || updateType == 'close') {
251
+ newQuoteEntry = position.quoteEntryAmount.sub(position.quoteEntryAmount
252
+ .mul(deltaBaa.abs())
253
+ .div(position.baseAssetAmount.abs()));
254
+ pnl = position.quoteEntryAmount.sub(newQuoteEntry).add(deltaQaa);
255
+ }
256
+ else {
257
+ newQuoteEntry = deltaQaa.sub(deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs()));
258
+ pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
259
+ }
260
+ position.quoteEntryAmount = newQuoteEntry;
261
+ position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
262
+ position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
263
+ if (position.baseAssetAmount.gt(numericConstants_1.ZERO)) {
264
+ position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
265
+ }
266
+ else if (position.baseAssetAmount.lt(numericConstants_1.ZERO)) {
267
+ position.lastCumulativeFundingRate =
268
+ market.amm.cumulativeFundingRateShort;
269
+ }
270
+ else {
271
+ position.lastCumulativeFundingRate = numericConstants_1.ZERO;
272
+ }
273
+ return [position, remainderBaa, pnl];
274
+ };
275
+ /**
276
+ * calculates Buying Power = FC * MAX_LEVERAGE
277
+ * @returns : Precision QUOTE_PRECISION
278
+ */
279
+ ClearingHouseUser.prototype.getBuyingPower = function (marketIndex) {
280
+ return this.getFreeCollateral()
281
+ .mul(this.getMaxLeverage(marketIndex, 'Initial'))
282
+ .div(numericConstants_1.TEN_THOUSAND);
283
+ };
284
+ /**
285
+ * calculates Free Collateral = Total collateral - initial margin requirement
286
+ * @returns : Precision QUOTE_PRECISION
287
+ */
288
+ ClearingHouseUser.prototype.getFreeCollateral = function () {
289
+ var totalCollateral = this.getTotalCollateral();
290
+ var initialMarginRequirement = this.getInitialMarginRequirement();
291
+ var freeCollateral = totalCollateral.sub(initialMarginRequirement);
292
+ return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
293
+ };
294
+ /**
295
+ * @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
296
+ */
297
+ ClearingHouseUser.prototype.getMarginRequirement = function (type) {
298
+ var _this = this;
299
+ return this.getUserAccount()
300
+ .perpPositions.reduce(function (marginRequirement, perpPosition) {
301
+ var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
302
+ if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
303
+ // is an lp
304
+ // clone so we dont mutate the position
305
+ perpPosition = _this.getClonedPosition(perpPosition);
306
+ // settle position
307
+ var _a = _this.getSettledLPPosition(market.marketIndex), settledPosition = _a[0], dustBaa = _a[1], _2 = _a[2];
308
+ perpPosition.baseAssetAmount =
309
+ settledPosition.baseAssetAmount.add(dustBaa);
310
+ perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
311
+ // open orders
312
+ var openAsks = void 0;
313
+ if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
314
+ openAsks = market.amm.maxBaseAssetReserve
315
+ .sub(market.amm.baseAssetReserve)
316
+ .mul(perpPosition.lpShares)
317
+ .div(market.amm.sqrtK)
318
+ .mul(new _1.BN(-1));
319
+ }
320
+ else {
321
+ openAsks = numericConstants_1.ZERO;
322
+ }
323
+ var openBids = void 0;
324
+ if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
325
+ openBids = market.amm.baseAssetReserve
326
+ .sub(market.amm.minBaseAssetReserve)
327
+ .mul(perpPosition.lpShares)
328
+ .div(market.amm.sqrtK);
329
+ }
330
+ else {
331
+ openBids = numericConstants_1.ZERO;
332
+ }
333
+ perpPosition.openAsks = perpPosition.openAsks.add(openAsks);
334
+ perpPosition.openBids = perpPosition.openBids.add(openBids);
335
+ }
336
+ var valuationPrice = _this.getOracleDataForMarket(market.marketIndex).price;
337
+ if ((0, types_1.isVariant)(market.status, 'settlement')) {
338
+ valuationPrice = market.settlementPrice;
339
+ }
340
+ var worstCaseBaseAssetAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition);
341
+ var worstCaseAssetValue = worstCaseBaseAssetAmount
342
+ .abs()
343
+ .mul(valuationPrice)
344
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO.mul(numericConstants_1.MARK_PRICE_PRECISION));
345
+ return marginRequirement.add(worstCaseAssetValue
346
+ .mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, worstCaseBaseAssetAmount.abs(), type)))
347
+ .div(numericConstants_1.MARGIN_PRECISION));
348
+ }, numericConstants_1.ZERO)
349
+ .add(this.getSpotMarketLiabilityValue(undefined, type));
350
+ };
351
+ /**
352
+ * @returns The initial margin requirement in USDC. : QUOTE_PRECISION
353
+ */
354
+ ClearingHouseUser.prototype.getInitialMarginRequirement = function () {
355
+ return this.getMarginRequirement('Initial');
356
+ };
357
+ /**
358
+ * @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
359
+ */
360
+ ClearingHouseUser.prototype.getMaintenanceMarginRequirement = function () {
361
+ return this.getMarginRequirement('Maintenance');
362
+ };
363
+ /**
364
+ * calculates unrealized position price pnl
365
+ * @returns : Precision QUOTE_PRECISION
366
+ */
367
+ ClearingHouseUser.prototype.getUnrealizedPNL = function (withFunding, marketIndex, withWeightMarginCategory) {
368
+ var _this = this;
369
+ return this.getUserAccount()
370
+ .perpPositions.filter(function (pos) {
371
+ return marketIndex ? pos.marketIndex === marketIndex : true;
372
+ })
373
+ .reduce(function (unrealizedPnl, perpPosition) {
374
+ var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
375
+ var positionUnrealizedPnl = (0, _1.calculatePositionPNL)(market, perpPosition, withFunding, _this.getOracleDataForMarket(market.marketIndex));
376
+ if (withWeightMarginCategory !== undefined) {
377
+ if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
378
+ positionUnrealizedPnl = positionUnrealizedPnl
379
+ .mul((0, _1.calculateUnrealizedAssetWeight)(market, positionUnrealizedPnl, withWeightMarginCategory))
380
+ .div(new _1.BN(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION));
381
+ }
382
+ }
383
+ return unrealizedPnl.add(positionUnrealizedPnl);
384
+ }, numericConstants_1.ZERO);
385
+ };
386
+ /**
387
+ * calculates unrealized funding payment pnl
388
+ * @returns : Precision QUOTE_PRECISION
389
+ */
390
+ ClearingHouseUser.prototype.getUnrealizedFundingPNL = function (marketIndex) {
391
+ var _this = this;
392
+ return this.getUserAccount()
393
+ .perpPositions.filter(function (pos) {
394
+ return marketIndex ? pos.marketIndex === marketIndex : true;
395
+ })
396
+ .reduce(function (pnl, perpPosition) {
397
+ var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
398
+ return pnl.add((0, _1.calculatePositionFundingPNL)(market, perpPosition));
399
+ }, numericConstants_1.ZERO);
400
+ };
401
+ ClearingHouseUser.prototype.getSpotMarketLiabilityValue = function (marketIndex, withWeightMarginCategory) {
402
+ var _this = this;
403
+ return this.getUserAccount().spotPositions.reduce(function (totalLiabilityValue, spotPosition) {
404
+ if (spotPosition.balance.eq(numericConstants_1.ZERO) ||
405
+ (0, types_1.isVariant)(spotPosition.balanceType, 'deposit') ||
406
+ (marketIndex !== undefined &&
407
+ !spotPosition.marketIndex.eq(marketIndex))) {
408
+ return totalLiabilityValue;
409
+ }
410
+ // Todo this needs to account for whether it's based on initial or maintenance requirements
411
+ var spotMarketAccount = _this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
412
+ var tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.balance, spotMarketAccount, spotPosition.balanceType);
413
+ var liabilityValue = tokenAmount
414
+ .mul(_this.getOracleDataForSpotMarket(spotMarketAccount.marketIndex).price)
415
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
416
+ .div(new _1.BN(10).pow(new _1.BN(spotMarketAccount.decimals).sub(numericConstants_1.SPOT_MARKET_BALANCE_PRECISION_EXP)));
417
+ if (withWeightMarginCategory !== undefined) {
418
+ var weight = (0, spotBalance_1.calculateLiabilityWeight)(tokenAmount, spotMarketAccount, withWeightMarginCategory);
419
+ liabilityValue = liabilityValue
420
+ .mul(weight)
421
+ .div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
422
+ }
423
+ return totalLiabilityValue.add(liabilityValue);
424
+ }, numericConstants_1.ZERO);
425
+ };
426
+ ClearingHouseUser.prototype.getSpotMarketAssetValue = function (marketIndex, withWeightMarginCategory) {
427
+ var _this = this;
428
+ return this.getUserAccount().spotPositions.reduce(function (totalAssetValue, spotPosition) {
429
+ if (spotPosition.balance.eq(numericConstants_1.ZERO) ||
430
+ (0, types_1.isVariant)(spotPosition.balanceType, 'borrow') ||
431
+ (marketIndex !== undefined &&
432
+ !spotPosition.marketIndex.eq(marketIndex))) {
433
+ return totalAssetValue;
434
+ }
435
+ // Todo this needs to account for whether it's based on initial or maintenance requirements
436
+ var spotMarketAccount = _this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
437
+ var tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.balance, spotMarketAccount, spotPosition.balanceType);
438
+ var assetValue = tokenAmount
439
+ .mul(_this.getOracleDataForSpotMarket(spotMarketAccount.marketIndex).price)
440
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
441
+ .div(new _1.BN(10).pow(new _1.BN(spotMarketAccount.decimals).sub(numericConstants_1.SPOT_MARKET_BALANCE_PRECISION_EXP)));
442
+ if (withWeightMarginCategory !== undefined) {
443
+ var weight = (0, spotBalance_1.calculateAssetWeight)(tokenAmount, spotMarketAccount, withWeightMarginCategory);
444
+ assetValue = assetValue.mul(weight).div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
445
+ }
446
+ return totalAssetValue.add(assetValue);
447
+ }, numericConstants_1.ZERO);
448
+ };
449
+ ClearingHouseUser.prototype.getNetSpotMarketValue = function (withWeightMarginCategory) {
450
+ return this.getSpotMarketAssetValue(undefined, withWeightMarginCategory).sub(this.getSpotMarketLiabilityValue(undefined, withWeightMarginCategory));
451
+ };
452
+ /**
453
+ * calculates TotalCollateral: collateral + unrealized pnl
454
+ * @returns : Precision QUOTE_PRECISION
455
+ */
456
+ ClearingHouseUser.prototype.getTotalCollateral = function (marginCategory) {
457
+ if (marginCategory === void 0) { marginCategory = 'Initial'; }
458
+ return this.getSpotMarketAssetValue(undefined, marginCategory).add(this.getUnrealizedPNL(true, undefined, marginCategory));
459
+ };
460
+ /**
461
+ * calculates sum of position value across all positions in margin system
462
+ * @returns : Precision QUOTE_PRECISION
463
+ */
464
+ ClearingHouseUser.prototype.getTotalPositionValue = function () {
465
+ var _this = this;
466
+ return this.getUserAccount().perpPositions.reduce(function (positionValue, perpPosition) {
467
+ var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
468
+ var posVal = (0, margin_1.calculateBaseAssetValueWithOracle)(market, perpPosition, _this.getOracleDataForMarket(market.marketIndex));
469
+ return positionValue.add(posVal);
470
+ }, numericConstants_1.ZERO);
471
+ };
472
+ /**
473
+ * calculates position value in margin system
474
+ * @returns : Precision QUOTE_PRECISION
475
+ */
476
+ ClearingHouseUser.prototype.getPositionValue = function (marketIndex, oraclePriceData) {
477
+ var userPosition = this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
478
+ var market = this.clearingHouse.getPerpMarketAccount(userPosition.marketIndex);
479
+ return (0, margin_1.calculateBaseAssetValueWithOracle)(market, userPosition, oraclePriceData);
480
+ };
481
+ ClearingHouseUser.prototype.getPositionSide = function (currentPosition) {
482
+ if (currentPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
483
+ return _1.PositionDirection.LONG;
484
+ }
485
+ else if (currentPosition.baseAssetAmount.lt(numericConstants_1.ZERO)) {
486
+ return _1.PositionDirection.SHORT;
487
+ }
488
+ else {
489
+ return undefined;
490
+ }
491
+ };
492
+ /**
493
+ * calculates average exit price (optionally for closing up to 100% of position)
494
+ * @returns : Precision MARK_PRICE_PRECISION
495
+ */
496
+ ClearingHouseUser.prototype.getPositionEstimatedExitPriceAndPnl = function (position, amountToClose, useAMMClose) {
497
+ if (useAMMClose === void 0) { useAMMClose = false; }
498
+ var market = this.clearingHouse.getPerpMarketAccount(position.marketIndex);
499
+ var entryPrice = (0, position_1.calculateEntryPrice)(position);
500
+ var oraclePriceData = this.getOracleDataForMarket(position.marketIndex);
501
+ if (amountToClose) {
502
+ if (amountToClose.eq(numericConstants_1.ZERO)) {
503
+ return [(0, _1.calculateMarkPrice)(market, oraclePriceData), numericConstants_1.ZERO];
504
+ }
505
+ position = {
506
+ baseAssetAmount: amountToClose,
507
+ lastCumulativeFundingRate: position.lastCumulativeFundingRate,
508
+ marketIndex: position.marketIndex,
509
+ quoteAssetAmount: position.quoteAssetAmount
510
+ };
511
+ }
512
+ var baseAssetValue;
513
+ if (useAMMClose) {
514
+ baseAssetValue = (0, _1.calculateBaseAssetValue)(market, position, oraclePriceData);
515
+ }
516
+ else {
517
+ baseAssetValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market, position, oraclePriceData);
518
+ }
519
+ if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
520
+ return [numericConstants_1.ZERO, numericConstants_1.ZERO];
521
+ }
522
+ var exitPrice = baseAssetValue
523
+ .mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
524
+ .mul(numericConstants_1.MARK_PRICE_PRECISION)
525
+ .div(position.baseAssetAmount.abs());
526
+ var pnlPerBase = exitPrice.sub(entryPrice);
527
+ var pnl = pnlPerBase
528
+ .mul(position.baseAssetAmount)
529
+ .div(numericConstants_1.MARK_PRICE_PRECISION)
530
+ .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
531
+ return [exitPrice, pnl];
532
+ };
533
+ /**
534
+ * calculates current user leverage across all positions
535
+ * @returns : Precision TEN_THOUSAND
536
+ */
537
+ ClearingHouseUser.prototype.getLeverage = function () {
538
+ var totalCollateral = this.getTotalCollateral();
539
+ var totalPositionValue = this.getTotalPositionValue();
540
+ if (totalPositionValue.eq(numericConstants_1.ZERO) && totalCollateral.eq(numericConstants_1.ZERO)) {
541
+ return numericConstants_1.ZERO;
542
+ }
543
+ return totalPositionValue.mul(numericConstants_1.TEN_THOUSAND).div(totalCollateral);
544
+ };
545
+ /**
546
+ * calculates max allowable leverage exceeding hitting requirement category
547
+ * @params category {Initial, Partial, Maintenance}
548
+ * @returns : Precision TEN_THOUSAND
549
+ */
550
+ ClearingHouseUser.prototype.getMaxLeverage = function (marketIndex, category) {
551
+ if (category === void 0) { category = 'Initial'; }
552
+ var market = this.clearingHouse.getPerpMarketAccount(marketIndex);
553
+ var marginRatioCategory = (0, _1.calculateMarketMarginRatio)(market,
554
+ // worstCaseBaseAssetAmount.abs(),
555
+ numericConstants_1.ZERO, // todo
556
+ category);
557
+ var maxLeverage = numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).div(new _1.BN(marginRatioCategory));
558
+ return maxLeverage;
559
+ };
560
+ /**
561
+ * calculates margin ratio: total collateral / |total position value|
562
+ * @returns : Precision TEN_THOUSAND
563
+ */
564
+ ClearingHouseUser.prototype.getMarginRatio = function () {
565
+ var totalPositionValue = this.getTotalPositionValue();
566
+ if (totalPositionValue.eq(numericConstants_1.ZERO)) {
567
+ return numericConstants_1.BN_MAX;
568
+ }
569
+ return this.getTotalCollateral().mul(numericConstants_1.TEN_THOUSAND).div(totalPositionValue);
570
+ };
571
+ ClearingHouseUser.prototype.canBeLiquidated = function () {
572
+ var totalCollateral = this.getTotalCollateral();
573
+ var partialMaintenanceRequirement = this.getMaintenanceMarginRequirement();
574
+ var marginRatio = this.getMarginRatio();
575
+ var canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
576
+ return [canLiquidate, marginRatio];
577
+ };
578
+ /**
579
+ * Checks if any user position cumulative funding differs from respective market cumulative funding
580
+ * @returns
581
+ */
582
+ ClearingHouseUser.prototype.needsToSettleFundingPayment = function () {
583
+ for (var _i = 0, _a = this.getUserAccount().perpPositions; _i < _a.length; _i++) {
584
+ var userPosition = _a[_i];
585
+ if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
586
+ continue;
587
+ }
588
+ var market = this.clearingHouse.getPerpMarketAccount(userPosition.marketIndex);
589
+ if (market.amm.cumulativeFundingRateLong.eq(userPosition.lastCumulativeFundingRate) ||
590
+ market.amm.cumulativeFundingRateShort.eq(userPosition.lastCumulativeFundingRate)) {
591
+ continue;
592
+ }
593
+ return true;
594
+ }
595
+ return false;
596
+ };
597
+ /**
598
+ * Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
599
+ * @param PerpPosition
600
+ * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
601
+ * @param partial
602
+ * @returns Precision : MARK_PRICE_PRECISION
603
+ */
604
+ ClearingHouseUser.prototype.liquidationPrice = function (perpPosition, positionBaseSizeChange) {
605
+ // solves formula for example canBeLiquidated below
606
+ var _this = this;
607
+ if (positionBaseSizeChange === void 0) { positionBaseSizeChange = numericConstants_1.ZERO; }
608
+ /* example: assume BTC price is $40k (examine 10% up/down)
609
+
610
+ if 10k deposit and levered 10x short BTC => BTC up $400 means:
611
+ 1. higher base_asset_value (+$4k)
612
+ 2. lower collateral (-$4k)
613
+ 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
614
+
615
+ for 10x long, BTC down $400:
616
+ 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
617
+ var totalCollateral = this.getTotalCollateral();
618
+ // calculate the total position value ignoring any value from the target market of the trade
619
+ var totalPositionValueExcludingTargetMarket = this.getTotalPositionValueExcludingMarket(perpPosition.marketIndex);
620
+ var currentPerpPosition = this.getUserPosition(perpPosition.marketIndex) ||
621
+ this.getEmptyPosition(perpPosition.marketIndex);
622
+ var currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
623
+ var proposedBaseAssetAmount = currentPerpPositionBaseSize.add(positionBaseSizeChange);
624
+ // calculate position for current market after trade
625
+ var proposedPerpPosition = {
626
+ marketIndex: perpPosition.marketIndex,
627
+ baseAssetAmount: proposedBaseAssetAmount,
628
+ remainderBaseAssetAmount: numericConstants_1.ZERO,
629
+ quoteAssetAmount: new _1.BN(0),
630
+ lastCumulativeFundingRate: numericConstants_1.ZERO,
631
+ quoteEntryAmount: new _1.BN(0),
632
+ openOrders: new _1.BN(0),
633
+ openBids: new _1.BN(0),
634
+ openAsks: new _1.BN(0),
635
+ realizedPnl: numericConstants_1.ZERO,
636
+ lpShares: numericConstants_1.ZERO,
637
+ lastFeePerLp: numericConstants_1.ZERO,
638
+ lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
639
+ lastNetQuoteAssetAmountPerLp: numericConstants_1.ZERO
640
+ };
641
+ if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
642
+ return new _1.BN(-1);
643
+ var market = this.clearingHouse.getPerpMarketAccount(proposedPerpPosition.marketIndex);
644
+ var proposedPerpPositionValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market, proposedPerpPosition, this.getOracleDataForMarket(market.marketIndex));
645
+ // total position value after trade
646
+ var totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
647
+ var marginRequirementExcludingTargetMarket = this.getUserAccount().perpPositions.reduce(function (totalMarginRequirement, position) {
648
+ if (!position.marketIndex.eq(perpPosition.marketIndex)) {
649
+ var market_1 = _this.clearingHouse.getPerpMarketAccount(position.marketIndex);
650
+ var positionValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market_1, position, _this.getOracleDataForMarket(market_1.marketIndex));
651
+ var marketMarginRequirement = positionValue
652
+ .mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market_1, position.baseAssetAmount.abs(), 'Maintenance')))
653
+ .div(numericConstants_1.MARGIN_PRECISION);
654
+ totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
655
+ }
656
+ return totalMarginRequirement;
657
+ }, numericConstants_1.ZERO);
658
+ var freeCollateralExcludingTargetMarket = totalCollateral.sub(marginRequirementExcludingTargetMarket);
659
+ // if the position value after the trade is less than free collateral, there is no liq price
660
+ if (totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
661
+ proposedPerpPosition.baseAssetAmount.abs().gt(numericConstants_1.ZERO)) {
662
+ return new _1.BN(-1);
663
+ }
664
+ var marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(proposedPerpPositionValue
665
+ .mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, proposedPerpPosition.baseAssetAmount.abs(), 'Maintenance')))
666
+ .div(numericConstants_1.MARGIN_PRECISION));
667
+ var freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
668
+ var marketMaxLeverage = this.getMaxLeverage(proposedPerpPosition.marketIndex, 'Maintenance');
669
+ var priceDelta;
670
+ if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
671
+ priceDelta = freeCollateralAfterTrade
672
+ .mul(marketMaxLeverage) // precision is TEN_THOUSAND
673
+ .div(marketMaxLeverage.add(numericConstants_1.TEN_THOUSAND))
674
+ .mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
675
+ .mul(numericConstants_1.AMM_RESERVE_PRECISION)
676
+ .div(proposedBaseAssetAmount);
677
+ }
678
+ else {
679
+ priceDelta = freeCollateralAfterTrade
680
+ .mul(marketMaxLeverage) // precision is TEN_THOUSAND
681
+ .div(marketMaxLeverage.sub(numericConstants_1.TEN_THOUSAND))
682
+ .mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
683
+ .mul(numericConstants_1.AMM_RESERVE_PRECISION)
684
+ .div(proposedBaseAssetAmount);
685
+ }
686
+ var markPriceAfterTrade;
687
+ if (positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
688
+ markPriceAfterTrade = (0, _1.calculateMarkPrice)(this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex), this.getOracleDataForMarket(perpPosition.marketIndex));
689
+ }
690
+ else {
691
+ var direction = positionBaseSizeChange.gt(numericConstants_1.ZERO)
692
+ ? _1.PositionDirection.LONG
693
+ : _1.PositionDirection.SHORT;
694
+ markPriceAfterTrade = (0, _1.calculateTradeSlippage)(direction, positionBaseSizeChange.abs(), this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex), 'base', this.getOracleDataForMarket(perpPosition.marketIndex))[3]; // newPrice after swap
695
+ }
696
+ if (priceDelta.gt(markPriceAfterTrade)) {
697
+ return new _1.BN(-1);
698
+ }
699
+ return markPriceAfterTrade.sub(priceDelta);
700
+ };
701
+ /**
702
+ * Calculates the estimated liquidation price for a position after closing a quote amount of the position.
703
+ * @param positionMarketIndex
704
+ * @param closeQuoteAmount
705
+ * @returns : Precision MARK_PRICE_PRECISION
706
+ */
707
+ ClearingHouseUser.prototype.liquidationPriceAfterClose = function (positionMarketIndex, closeQuoteAmount) {
708
+ var currentPosition = this.getUserPosition(positionMarketIndex) ||
709
+ this.getEmptyPosition(positionMarketIndex);
710
+ var closeBaseAmount = currentPosition.baseAssetAmount
711
+ .mul(closeQuoteAmount)
712
+ .div(currentPosition.quoteAssetAmount.abs())
713
+ .add(currentPosition.baseAssetAmount
714
+ .mul(closeQuoteAmount)
715
+ .mod(currentPosition.quoteAssetAmount.abs()))
716
+ .neg();
717
+ return this.liquidationPrice({
718
+ marketIndex: positionMarketIndex
719
+ }, closeBaseAmount);
720
+ };
721
+ /**
722
+ * Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
723
+ *
724
+ * To Calculate Max Quote Available:
725
+ *
726
+ * Case 1: SameSide
727
+ * => Remaining quote to get to maxLeverage
728
+ *
729
+ * Case 2: NOT SameSide && currentLeverage <= maxLeverage
730
+ * => Current opposite position x2 + remaining to get to maxLeverage
731
+ *
732
+ * Case 3: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition > maxLeverage
733
+ * => strictly reduce current position size
734
+ *
735
+ * Case 4: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition < maxLeverage
736
+ * => current position + remaining to get to maxLeverage
737
+ *
738
+ * @param targetMarketIndex
739
+ * @param tradeSide
740
+ * @returns tradeSizeAllowed : Precision QUOTE_PRECISION
741
+ */
742
+ ClearingHouseUser.prototype.getMaxTradeSizeUSDC = function (targetMarketIndex, tradeSide) {
743
+ var currentPosition = this.getUserPosition(targetMarketIndex) ||
744
+ this.getEmptyPosition(targetMarketIndex);
745
+ var targetSide = (0, types_1.isVariant)(tradeSide, 'short') ? 'short' : 'long';
746
+ var currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
747
+ ? 'short'
748
+ : 'long';
749
+ var targetingSameSide = !currentPosition
750
+ ? true
751
+ : targetSide === currentPositionSide;
752
+ var oracleData = this.getOracleDataForMarket(targetMarketIndex);
753
+ // 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.
754
+ var oppositeSizeValueUSDC = targetingSameSide
755
+ ? numericConstants_1.ZERO
756
+ : this.getPositionValue(targetMarketIndex, oracleData);
757
+ var maxPositionSize = this.getBuyingPower(targetMarketIndex);
758
+ if (maxPositionSize.gte(numericConstants_1.ZERO)) {
759
+ if (oppositeSizeValueUSDC.eq(numericConstants_1.ZERO)) {
760
+ // case 1 : Regular trade where current total position less than max, and no opposite position to account for
761
+ // do nothing
762
+ }
763
+ else {
764
+ // case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
765
+ maxPositionSize = maxPositionSize.add(oppositeSizeValueUSDC.mul(new _1.BN(2)));
766
+ }
767
+ }
768
+ else {
769
+ // current leverage is greater than max leverage - can only reduce position size
770
+ if (!targetingSameSide) {
771
+ var market = this.clearingHouse.getPerpMarketAccount(targetMarketIndex);
772
+ var perpPositionValue = this.getPositionValue(targetMarketIndex, oracleData);
773
+ var totalCollateral = this.getTotalCollateral();
774
+ var marginRequirement = this.getInitialMarginRequirement();
775
+ var marginFreedByClosing = perpPositionValue
776
+ .mul(new _1.BN(market.marginRatioInitial))
777
+ .div(numericConstants_1.MARGIN_PRECISION);
778
+ var marginRequirementAfterClosing = marginRequirement.sub(marginFreedByClosing);
779
+ if (marginRequirementAfterClosing.gt(totalCollateral)) {
780
+ maxPositionSize = perpPositionValue;
781
+ }
782
+ else {
783
+ var freeCollateralAfterClose = totalCollateral.sub(marginRequirementAfterClosing);
784
+ var buyingPowerAfterClose = freeCollateralAfterClose
785
+ .mul(this.getMaxLeverage(targetMarketIndex))
786
+ .div(numericConstants_1.TEN_THOUSAND);
787
+ maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
788
+ }
789
+ }
790
+ else {
791
+ // do nothing if targetting same side
792
+ }
793
+ }
794
+ // subtract oneMillionth of maxPositionSize
795
+ // => to avoid rounding errors when taking max leverage
796
+ var oneMilli = maxPositionSize.div(numericConstants_1.QUOTE_PRECISION);
797
+ return maxPositionSize.sub(oneMilli);
798
+ };
799
+ // TODO - should this take the price impact of the trade into account for strict accuracy?
800
+ /**
801
+ * Returns the leverage ratio for the account after adding (or subtracting) the given quote size to the given position
802
+ * @param targetMarketIndex
803
+ * @param positionMarketIndex
804
+ * @param tradeQuoteAmount
805
+ * @returns leverageRatio : Precision TEN_THOUSAND
806
+ */
807
+ ClearingHouseUser.prototype.accountLeverageRatioAfterTrade = function (targetMarketIndex, tradeQuoteAmount, tradeSide) {
808
+ var currentPosition = this.getUserPosition(targetMarketIndex) ||
809
+ this.getEmptyPosition(targetMarketIndex);
810
+ var oracleData = this.getOracleDataForMarket(targetMarketIndex);
811
+ var currentPositionQuoteAmount = this.getPositionValue(targetMarketIndex, oracleData);
812
+ var currentSide = currentPosition && currentPosition.baseAssetAmount.isNeg()
813
+ ? _1.PositionDirection.SHORT
814
+ : _1.PositionDirection.LONG;
815
+ if (currentSide === _1.PositionDirection.SHORT)
816
+ currentPositionQuoteAmount = currentPositionQuoteAmount.neg();
817
+ if (tradeSide === _1.PositionDirection.SHORT)
818
+ tradeQuoteAmount = tradeQuoteAmount.neg();
819
+ var currentPerpPositionAfterTrade = currentPositionQuoteAmount
820
+ .add(tradeQuoteAmount)
821
+ .abs();
822
+ var totalPositionAfterTradeExcludingTargetMarket = this.getTotalPositionValueExcludingMarket(targetMarketIndex);
823
+ var totalCollateral = this.getTotalCollateral();
824
+ if (totalCollateral.gt(numericConstants_1.ZERO)) {
825
+ var newLeverage = currentPerpPositionAfterTrade
826
+ .add(totalPositionAfterTradeExcludingTargetMarket)
827
+ .abs()
828
+ .mul(numericConstants_1.TEN_THOUSAND)
829
+ .div(totalCollateral);
830
+ return newLeverage;
831
+ }
832
+ else {
833
+ return new _1.BN(0);
834
+ }
835
+ };
836
+ /**
837
+ * Calculates how much fee will be taken for a given sized trade
838
+ * @param quoteAmount
839
+ * @returns feeForQuote : Precision QUOTE_PRECISION
840
+ */
841
+ ClearingHouseUser.prototype.calculateFeeForQuoteAmount = function (quoteAmount) {
842
+ var feeStructure = this.clearingHouse.getStateAccount().perpFeeStructure;
843
+ return quoteAmount
844
+ .mul(feeStructure.feeNumerator)
845
+ .div(feeStructure.feeDenominator);
846
+ };
847
+ /**
848
+ * Get the total position value, excluding any position coming from the given target market
849
+ * @param marketToIgnore
850
+ * @returns positionValue : Precision QUOTE_PRECISION
851
+ */
852
+ ClearingHouseUser.prototype.getTotalPositionValueExcludingMarket = function (marketToIgnore) {
853
+ var currentPerpPosition = this.getUserPosition(marketToIgnore) ||
854
+ this.getEmptyPosition(marketToIgnore);
855
+ var oracleData = this.getOracleDataForMarket(marketToIgnore);
856
+ var currentPerpPositionValueUSDC = numericConstants_1.ZERO;
857
+ if (currentPerpPosition) {
858
+ currentPerpPositionValueUSDC = this.getPositionValue(marketToIgnore, oracleData);
859
+ }
860
+ return this.getTotalPositionValue().sub(currentPerpPositionValueUSDC);
861
+ };
862
+ ClearingHouseUser.prototype.getOracleDataForMarket = function (marketIndex) {
863
+ var oracleKey = this.clearingHouse.getPerpMarketAccount(marketIndex).amm.oracle;
864
+ var oracleData = this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
865
+ return oracleData;
866
+ };
867
+ ClearingHouseUser.prototype.getOracleDataForSpotMarket = function (marketIndex) {
868
+ var oracleKey = this.clearingHouse.getSpotMarketAccount(marketIndex).oracle;
869
+ var oracleData = this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
870
+ return oracleData;
871
+ };
872
+ return ClearingHouseUser;
873
+ }());
874
+ exports.ClearingHouseUser = ClearingHouseUser;