@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.
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +13 -13
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +27 -27
- package/lib/accounts/types.d.ts +8 -9
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +14 -14
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +35 -34
- package/lib/addresses/pda.d.ts +8 -6
- package/lib/addresses/pda.js +35 -27
- package/lib/admin.d.ts +9 -6
- package/lib/admin.js +90 -54
- package/lib/clearingHouse.d.ts +71 -42
- package/lib/clearingHouse.js +765 -282
- package/lib/clearingHouseConfig.d.ts +2 -2
- package/lib/clearingHouseUser.d.ts +19 -17
- package/lib/clearingHouseUser.js +145 -123
- package/lib/config.d.ts +7 -7
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +12 -12
- package/lib/constants/numericConstants.js +13 -13
- package/lib/constants/{markets.d.ts → perpMarkets.d.ts} +5 -5
- package/{src/constants/markets.js → lib/constants/perpMarkets.js} +4 -4
- package/lib/constants/{banks.d.ts → spotMarkets.d.ts} +6 -6
- package/lib/constants/{banks.js → spotMarkets.js} +16 -16
- package/lib/events/eventSubscriber.d.ts +4 -2
- package/lib/events/eventSubscriber.js +16 -9
- package/lib/events/fetchLogs.d.ts +10 -1
- package/lib/events/fetchLogs.js +27 -7
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +6 -2
- package/lib/events/types.d.ts +4 -2
- package/lib/events/types.js +2 -0
- package/lib/examples/makeTradeExample.js +18 -6
- package/lib/idl/clearing_house.json +1128 -347
- package/lib/index.d.ts +6 -3
- package/lib/index.js +6 -3
- package/lib/math/amm.d.ts +5 -3
- package/lib/math/amm.js +42 -4
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +2 -1
- package/lib/math/margin.d.ts +4 -4
- package/lib/math/margin.js +18 -11
- package/lib/math/market.d.ts +10 -9
- package/lib/math/market.js +29 -6
- package/lib/math/oracles.d.ts +2 -1
- package/lib/math/oracles.js +11 -1
- package/lib/math/orders.d.ts +5 -5
- package/lib/math/position.d.ts +13 -13
- package/lib/math/position.js +19 -19
- package/lib/math/spotBalance.d.ts +19 -0
- package/lib/math/spotBalance.js +176 -0
- package/lib/math/spotMarket.d.ts +4 -0
- package/lib/math/spotMarket.js +8 -0
- package/lib/math/spotPosition.d.ts +2 -0
- package/lib/math/spotPosition.js +8 -0
- package/lib/math/state.js +2 -2
- package/lib/math/trade.d.ts +4 -4
- package/lib/orderParams.d.ts +4 -4
- package/lib/orderParams.js +12 -4
- package/lib/serum/serumSubscriber.d.ts +23 -0
- package/lib/serum/serumSubscriber.js +41 -0
- package/lib/serum/types.d.ts +11 -0
- package/lib/serum/types.js +2 -0
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +4 -2
- package/lib/tx/types.d.ts +1 -1
- package/lib/types.d.ts +148 -39
- package/lib/types.js +37 -9
- package/my-script/.env +7 -0
- package/my-script/getUserStats.ts +106 -0
- package/my-script/multiConnections.ts +119 -0
- package/my-script/test-regex.ts +11 -0
- package/my-script/utils.ts +52 -0
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.js +249 -0
- package/src/accounts/bulkUserStatsSubscription.js +75 -0
- package/src/accounts/bulkUserSubscription.js +75 -0
- package/src/accounts/fetch.js +92 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +465 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +38 -38
- package/src/accounts/pollingOracleSubscriber.js +156 -0
- package/src/accounts/pollingTokenAccountSubscriber.js +141 -0
- package/src/accounts/pollingUserAccountSubscriber.js +208 -0
- package/src/accounts/pollingUserStatsAccountSubscriber.js +208 -0
- package/src/accounts/types.js +28 -0
- package/src/accounts/types.ts +11 -9
- package/src/accounts/utils.js +7 -0
- package/src/accounts/webSocketAccountSubscriber.js +138 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +433 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +59 -52
- package/src/accounts/webSocketUserAccountSubscriber.js +113 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.js +113 -0
- package/src/addresses/pda.js +186 -0
- package/src/addresses/pda.ts +56 -42
- package/src/admin.js +1284 -0
- package/src/admin.ts +149 -75
- package/src/assert/assert.js +1 -1
- package/src/clearingHouse.js +3433 -0
- package/src/clearingHouse.ts +1097 -380
- package/src/clearingHouseConfig.js +2 -0
- package/src/clearingHouseConfig.ts +2 -2
- package/src/clearingHouseUser.js +874 -0
- package/src/clearingHouseUser.ts +237 -172
- package/src/clearingHouseUserConfig.js +2 -0
- package/src/clearingHouseUserStats.js +115 -0
- package/src/clearingHouseUserStatsConfig.js +2 -0
- package/src/config.js +80 -0
- package/src/config.ts +30 -30
- package/src/constants/numericConstants.js +18 -11
- package/src/constants/numericConstants.ts +17 -15
- package/{lib/constants/markets.js → src/constants/perpMarkets.js} +11 -11
- package/src/constants/{markets.ts → perpMarkets.ts} +5 -5
- package/src/constants/spotMarkets.js +51 -0
- package/src/constants/{banks.ts → spotMarkets.ts} +19 -19
- package/src/events/eventList.js +66 -23
- package/src/events/eventSubscriber.js +202 -0
- package/src/events/eventSubscriber.ts +20 -12
- package/src/events/fetchLogs.js +117 -0
- package/src/events/fetchLogs.ts +35 -8
- package/src/events/pollingLogProvider.js +113 -0
- package/src/events/pollingLogProvider.ts +10 -2
- package/src/events/sort.js +41 -0
- package/src/events/txEventCache.js +22 -19
- package/src/events/types.js +25 -0
- package/src/events/types.ts +7 -1
- package/src/events/webSocketLogProvider.js +76 -0
- package/src/examples/makeTradeExample.ts +27 -6
- package/src/factory/bigNum.js +183 -180
- package/src/factory/oracleClient.js +9 -9
- package/src/idl/clearing_house.json +1128 -347
- package/src/index.js +75 -0
- package/src/index.ts +6 -3
- package/src/math/amm.js +422 -0
- package/src/math/amm.ts +73 -5
- package/src/math/auction.js +10 -10
- package/src/math/conversion.js +4 -3
- package/src/math/funding.js +223 -175
- package/src/math/funding.ts +7 -7
- package/src/math/insurance.js +27 -0
- package/src/math/margin.js +77 -0
- package/src/math/margin.ts +34 -23
- package/src/math/market.js +105 -0
- package/src/math/market.ts +71 -19
- package/src/math/oracles.js +40 -10
- package/src/math/oracles.ts +18 -1
- package/src/math/orders.js +153 -0
- package/src/math/orders.ts +5 -5
- package/src/math/position.js +172 -0
- package/src/math/position.ts +31 -31
- package/src/math/repeg.js +40 -40
- package/src/math/spotBalance.js +176 -0
- package/src/math/spotBalance.ts +290 -0
- package/src/math/spotMarket.js +8 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.js +8 -0
- package/src/math/spotPosition.ts +6 -0
- package/src/math/state.ts +2 -2
- package/src/math/trade.js +81 -74
- package/src/math/trade.ts +4 -4
- package/src/math/utils.js +8 -7
- package/src/oracles/oracleClientCache.js +10 -9
- package/src/oracles/pythClient.js +52 -17
- package/src/oracles/quoteAssetOracleClient.js +44 -13
- package/src/oracles/switchboardClient.js +69 -37
- package/src/oracles/types.js +1 -1
- package/src/orderParams.js +14 -6
- package/src/orderParams.ts +16 -8
- package/src/serum/serumSubscriber.js +102 -0
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.js +2 -0
- package/src/serum/types.ts +13 -0
- package/src/slot/SlotSubscriber.js +67 -20
- package/src/token/index.js +4 -4
- package/src/tokenFaucet.js +288 -154
- package/src/tx/retryTxSender.js +280 -0
- package/src/tx/retryTxSender.ts +5 -2
- package/src/tx/types.js +1 -1
- package/src/tx/types.ts +2 -1
- package/src/tx/utils.js +7 -6
- package/src/types.js +216 -0
- package/src/types.ts +131 -39
- package/src/userName.js +5 -5
- package/src/util/computeUnits.js +46 -11
- package/src/util/promiseTimeout.js +5 -5
- package/src/util/tps.js +46 -12
- package/src/wallet.js +55 -18
- package/lib/math/bankBalance.d.ts +0 -15
- package/lib/math/bankBalance.js +0 -150
- package/src/addresses/marketAddresses.js +0 -26
- package/src/constants/banks.js +0 -42
- package/src/examples/makeTradeExample.js +0 -80
- package/src/math/bankBalance.ts +0 -258
- package/src/math/state.js +0 -15
- package/src/math/utils.js.map +0 -1
- package/src/util/getTokenAddress.js +0 -9
package/src/clearingHouseUser.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
MarginCategory,
|
|
8
8
|
Order,
|
|
9
9
|
UserAccount,
|
|
10
|
-
|
|
10
|
+
PerpPosition,
|
|
11
11
|
} from './types';
|
|
12
12
|
import { calculateEntryPrice } from './math/position';
|
|
13
13
|
import {
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
AMM_RESERVE_PRECISION,
|
|
21
21
|
PRICE_TO_QUOTE_PRECISION,
|
|
22
22
|
MARGIN_PRECISION,
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
SPOT_MARKET_WEIGHT_PRECISION,
|
|
24
|
+
SPOT_MARKET_BALANCE_PRECISION_EXP,
|
|
25
25
|
} from './constants/numericConstants';
|
|
26
26
|
import {
|
|
27
27
|
UserAccountSubscriber,
|
|
@@ -38,13 +38,13 @@ import {
|
|
|
38
38
|
PositionDirection,
|
|
39
39
|
calculateTradeSlippage,
|
|
40
40
|
BN,
|
|
41
|
-
|
|
41
|
+
SpotMarketAccount,
|
|
42
42
|
} from '.';
|
|
43
43
|
import {
|
|
44
44
|
getTokenAmount,
|
|
45
45
|
calculateAssetWeight,
|
|
46
46
|
calculateLiabilityWeight,
|
|
47
|
-
} from './math/
|
|
47
|
+
} from './math/spotBalance';
|
|
48
48
|
import {
|
|
49
49
|
calculateBaseAssetValueWithOracle,
|
|
50
50
|
calculateWorstCaseBaseAssetAmount,
|
|
@@ -120,15 +120,16 @@ export class ClearingHouseUser {
|
|
|
120
120
|
* @param marketIndex
|
|
121
121
|
* @returns userPosition
|
|
122
122
|
*/
|
|
123
|
-
public getUserPosition(marketIndex: BN):
|
|
124
|
-
return this.getUserAccount().
|
|
123
|
+
public getUserPosition(marketIndex: BN): PerpPosition | undefined {
|
|
124
|
+
return this.getUserAccount().perpPositions.find((position) =>
|
|
125
125
|
position.marketIndex.eq(marketIndex)
|
|
126
126
|
);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
public getEmptyPosition(marketIndex: BN):
|
|
129
|
+
public getEmptyPosition(marketIndex: BN): PerpPosition {
|
|
130
130
|
return {
|
|
131
131
|
baseAssetAmount: ZERO,
|
|
132
|
+
remainderBaseAssetAmount: ZERO,
|
|
132
133
|
lastCumulativeFundingRate: ZERO,
|
|
133
134
|
marketIndex,
|
|
134
135
|
quoteAssetAmount: ZERO,
|
|
@@ -144,7 +145,7 @@ export class ClearingHouseUser {
|
|
|
144
145
|
};
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
public getClonedPosition(position:
|
|
148
|
+
public getClonedPosition(position: PerpPosition): PerpPosition {
|
|
148
149
|
const clonedPosition = Object.assign({}, position);
|
|
149
150
|
return clonedPosition;
|
|
150
151
|
}
|
|
@@ -183,13 +184,17 @@ export class ClearingHouseUser {
|
|
|
183
184
|
|
|
184
185
|
/**
|
|
185
186
|
* calculates the market position if the lp position was settled
|
|
186
|
-
* @returns : userPosition
|
|
187
|
+
* @returns : the settled userPosition
|
|
188
|
+
* @returns : the dust base asset amount (ie, < stepsize)
|
|
189
|
+
* @returns : pnl from settle
|
|
187
190
|
*/
|
|
188
|
-
public getSettledLPPosition(marketIndex: BN): [
|
|
191
|
+
public getSettledLPPosition(marketIndex: BN): [PerpPosition, BN, BN] {
|
|
189
192
|
const _position = this.getUserPosition(marketIndex);
|
|
190
193
|
const position = this.getClonedPosition(_position);
|
|
191
194
|
|
|
192
|
-
const market = this.clearingHouse.
|
|
195
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
196
|
+
position.marketIndex
|
|
197
|
+
);
|
|
193
198
|
const nShares = position.lpShares;
|
|
194
199
|
|
|
195
200
|
const deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
|
|
@@ -208,27 +213,33 @@ export class ClearingHouseUser {
|
|
|
208
213
|
return sign;
|
|
209
214
|
}
|
|
210
215
|
|
|
211
|
-
|
|
212
|
-
.abs()
|
|
213
|
-
.
|
|
214
|
-
|
|
215
|
-
const _standardizedBaa = deltaBaa.sub(remainder);
|
|
216
|
-
|
|
217
|
-
let remainderBaa;
|
|
218
|
-
if (_standardizedBaa.abs().gte(market.amm.baseAssetAmountStepSize)) {
|
|
219
|
-
remainderBaa = remainder;
|
|
220
|
-
} else {
|
|
221
|
-
remainderBaa = deltaBaa;
|
|
216
|
+
function standardize(amount, stepsize) {
|
|
217
|
+
const remainder = amount.abs().mod(stepsize).mul(sign(amount));
|
|
218
|
+
const standardizedAmount = amount.sub(remainder);
|
|
219
|
+
return [standardizedAmount, remainder];
|
|
222
220
|
}
|
|
223
|
-
const standardizedBaa = deltaBaa.sub(remainderBaa);
|
|
224
221
|
|
|
225
|
-
const
|
|
222
|
+
const [standardizedBaa, remainderBaa] = standardize(
|
|
223
|
+
deltaBaa,
|
|
224
|
+
market.amm.baseAssetAmountStepSize
|
|
225
|
+
);
|
|
226
226
|
|
|
227
|
-
position.
|
|
228
|
-
|
|
227
|
+
position.remainderBaseAssetAmount =
|
|
228
|
+
position.remainderBaseAssetAmount.add(remainderBaa);
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
|
|
230
|
+
if (
|
|
231
|
+
position.remainderBaseAssetAmount
|
|
232
|
+
.abs()
|
|
233
|
+
.gte(market.amm.baseAssetAmountStepSize)
|
|
234
|
+
) {
|
|
235
|
+
const [newStandardizedBaa, newRemainderBaa] = standardize(
|
|
236
|
+
position.remainderBaseAssetAmount,
|
|
237
|
+
market.amm.baseAssetAmountStepSize
|
|
238
|
+
);
|
|
239
|
+
position.baseAssetAmount =
|
|
240
|
+
position.baseAssetAmount.add(newStandardizedBaa);
|
|
241
|
+
position.remainderBaseAssetAmount = newRemainderBaa;
|
|
242
|
+
}
|
|
232
243
|
|
|
233
244
|
let updateType;
|
|
234
245
|
if (position.baseAssetAmount.eq(ZERO)) {
|
|
@@ -254,7 +265,7 @@ export class ClearingHouseUser {
|
|
|
254
265
|
.mul(deltaBaa.abs())
|
|
255
266
|
.div(position.baseAssetAmount.abs())
|
|
256
267
|
);
|
|
257
|
-
pnl = position.quoteEntryAmount.sub(newQuoteEntry);
|
|
268
|
+
pnl = position.quoteEntryAmount.sub(newQuoteEntry).add(deltaQaa);
|
|
258
269
|
} else {
|
|
259
270
|
newQuoteEntry = deltaQaa.sub(
|
|
260
271
|
deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
|
|
@@ -262,6 +273,8 @@ export class ClearingHouseUser {
|
|
|
262
273
|
pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
|
|
263
274
|
}
|
|
264
275
|
position.quoteEntryAmount = newQuoteEntry;
|
|
276
|
+
position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
|
|
277
|
+
position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
|
|
265
278
|
|
|
266
279
|
if (position.baseAssetAmount.gt(ZERO)) {
|
|
267
280
|
position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
@@ -299,32 +312,35 @@ export class ClearingHouseUser {
|
|
|
299
312
|
/**
|
|
300
313
|
* @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
|
|
301
314
|
*/
|
|
302
|
-
public getMarginRequirement(
|
|
315
|
+
public getMarginRequirement(
|
|
316
|
+
type: MarginCategory,
|
|
317
|
+
liquidationBuffer?: BN
|
|
318
|
+
): BN {
|
|
303
319
|
return this.getUserAccount()
|
|
304
|
-
.
|
|
305
|
-
const market = this.clearingHouse.
|
|
306
|
-
|
|
320
|
+
.perpPositions.reduce((marginRequirement, perpPosition) => {
|
|
321
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
322
|
+
perpPosition.marketIndex
|
|
307
323
|
);
|
|
308
324
|
|
|
309
|
-
if (
|
|
325
|
+
if (perpPosition.lpShares.gt(ZERO)) {
|
|
310
326
|
// is an lp
|
|
311
327
|
// clone so we dont mutate the position
|
|
312
|
-
|
|
328
|
+
perpPosition = this.getClonedPosition(perpPosition);
|
|
313
329
|
|
|
314
330
|
// settle position
|
|
315
331
|
const [settledPosition, dustBaa, _] = this.getSettledLPPosition(
|
|
316
332
|
market.marketIndex
|
|
317
333
|
);
|
|
318
|
-
|
|
334
|
+
perpPosition.baseAssetAmount =
|
|
319
335
|
settledPosition.baseAssetAmount.add(dustBaa);
|
|
320
|
-
|
|
336
|
+
perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
|
321
337
|
|
|
322
338
|
// open orders
|
|
323
339
|
let openAsks;
|
|
324
340
|
if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
|
|
325
341
|
openAsks = market.amm.maxBaseAssetReserve
|
|
326
342
|
.sub(market.amm.baseAssetReserve)
|
|
327
|
-
.mul(
|
|
343
|
+
.mul(perpPosition.lpShares)
|
|
328
344
|
.div(market.amm.sqrtK)
|
|
329
345
|
.mul(new BN(-1));
|
|
330
346
|
} else {
|
|
@@ -335,39 +351,55 @@ export class ClearingHouseUser {
|
|
|
335
351
|
if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
|
|
336
352
|
openBids = market.amm.baseAssetReserve
|
|
337
353
|
.sub(market.amm.minBaseAssetReserve)
|
|
338
|
-
.mul(
|
|
354
|
+
.mul(perpPosition.lpShares)
|
|
339
355
|
.div(market.amm.sqrtK);
|
|
340
356
|
} else {
|
|
341
357
|
openBids = ZERO;
|
|
342
358
|
}
|
|
343
359
|
|
|
344
|
-
|
|
345
|
-
|
|
360
|
+
perpPosition.openAsks = perpPosition.openAsks.add(openAsks);
|
|
361
|
+
perpPosition.openBids = perpPosition.openBids.add(openBids);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
let valuationPrice = this.getOracleDataForMarket(
|
|
365
|
+
market.marketIndex
|
|
366
|
+
).price;
|
|
367
|
+
|
|
368
|
+
if (isVariant(market.status, 'settlement')) {
|
|
369
|
+
valuationPrice = market.settlementPrice;
|
|
346
370
|
}
|
|
347
371
|
|
|
348
372
|
const worstCaseBaseAssetAmount =
|
|
349
|
-
calculateWorstCaseBaseAssetAmount(
|
|
373
|
+
calculateWorstCaseBaseAssetAmount(perpPosition);
|
|
350
374
|
|
|
351
375
|
const worstCaseAssetValue = worstCaseBaseAssetAmount
|
|
352
376
|
.abs()
|
|
353
|
-
.mul(
|
|
377
|
+
.mul(valuationPrice)
|
|
354
378
|
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
355
379
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
type
|
|
364
|
-
)
|
|
380
|
+
const positionMarginRequirement = worstCaseAssetValue
|
|
381
|
+
.mul(
|
|
382
|
+
new BN(
|
|
383
|
+
calculateMarketMarginRatio(
|
|
384
|
+
market,
|
|
385
|
+
worstCaseBaseAssetAmount.abs(),
|
|
386
|
+
type
|
|
365
387
|
)
|
|
366
388
|
)
|
|
367
|
-
|
|
368
|
-
|
|
389
|
+
)
|
|
390
|
+
.div(MARGIN_PRECISION);
|
|
391
|
+
|
|
392
|
+
if (liquidationBuffer !== undefined) {
|
|
393
|
+
positionMarginRequirement.add(
|
|
394
|
+
worstCaseAssetValue.mul(liquidationBuffer).div(MARGIN_PRECISION)
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return marginRequirement.add(positionMarginRequirement);
|
|
369
399
|
}, ZERO)
|
|
370
|
-
.add(
|
|
400
|
+
.add(
|
|
401
|
+
this.getSpotMarketLiabilityValue(undefined, type, liquidationBuffer)
|
|
402
|
+
);
|
|
371
403
|
}
|
|
372
404
|
|
|
373
405
|
/**
|
|
@@ -380,8 +412,8 @@ export class ClearingHouseUser {
|
|
|
380
412
|
/**
|
|
381
413
|
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
|
|
382
414
|
*/
|
|
383
|
-
public getMaintenanceMarginRequirement(): BN {
|
|
384
|
-
return this.getMarginRequirement('Maintenance');
|
|
415
|
+
public getMaintenanceMarginRequirement(liquidationBuffer?: BN): BN {
|
|
416
|
+
return this.getMarginRequirement('Maintenance', liquidationBuffer);
|
|
385
417
|
}
|
|
386
418
|
|
|
387
419
|
/**
|
|
@@ -393,19 +425,22 @@ export class ClearingHouseUser {
|
|
|
393
425
|
marketIndex?: BN,
|
|
394
426
|
withWeightMarginCategory?: MarginCategory
|
|
395
427
|
): BN {
|
|
428
|
+
const quoteSpotMarket = this.clearingHouse.getQuoteSpotMarketAccount();
|
|
396
429
|
return this.getUserAccount()
|
|
397
|
-
.
|
|
430
|
+
.perpPositions.filter((pos) =>
|
|
398
431
|
marketIndex ? pos.marketIndex === marketIndex : true
|
|
399
432
|
)
|
|
400
|
-
.reduce((unrealizedPnl,
|
|
401
|
-
const market = this.clearingHouse.
|
|
402
|
-
|
|
433
|
+
.reduce((unrealizedPnl, perpPosition) => {
|
|
434
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
435
|
+
perpPosition.marketIndex
|
|
403
436
|
);
|
|
437
|
+
const oraclePriceData = this.getOracleDataForMarket(market.marketIndex);
|
|
438
|
+
|
|
404
439
|
let positionUnrealizedPnl = calculatePositionPNL(
|
|
405
440
|
market,
|
|
406
|
-
|
|
441
|
+
perpPosition,
|
|
407
442
|
withFunding,
|
|
408
|
-
|
|
443
|
+
oraclePriceData
|
|
409
444
|
);
|
|
410
445
|
|
|
411
446
|
if (withWeightMarginCategory !== undefined) {
|
|
@@ -414,11 +449,13 @@ export class ClearingHouseUser {
|
|
|
414
449
|
.mul(
|
|
415
450
|
calculateUnrealizedAssetWeight(
|
|
416
451
|
market,
|
|
452
|
+
quoteSpotMarket,
|
|
417
453
|
positionUnrealizedPnl,
|
|
418
|
-
withWeightMarginCategory
|
|
454
|
+
withWeightMarginCategory,
|
|
455
|
+
oraclePriceData
|
|
419
456
|
)
|
|
420
457
|
)
|
|
421
|
-
.div(new BN(
|
|
458
|
+
.div(new BN(SPOT_MARKET_WEIGHT_PRECISION));
|
|
422
459
|
}
|
|
423
460
|
}
|
|
424
461
|
|
|
@@ -432,60 +469,70 @@ export class ClearingHouseUser {
|
|
|
432
469
|
*/
|
|
433
470
|
public getUnrealizedFundingPNL(marketIndex?: BN): BN {
|
|
434
471
|
return this.getUserAccount()
|
|
435
|
-
.
|
|
472
|
+
.perpPositions.filter((pos) =>
|
|
436
473
|
marketIndex ? pos.marketIndex === marketIndex : true
|
|
437
474
|
)
|
|
438
|
-
.reduce((pnl,
|
|
439
|
-
const market = this.clearingHouse.
|
|
440
|
-
|
|
475
|
+
.reduce((pnl, perpPosition) => {
|
|
476
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
477
|
+
perpPosition.marketIndex
|
|
441
478
|
);
|
|
442
|
-
return pnl.add(calculatePositionFundingPNL(market,
|
|
479
|
+
return pnl.add(calculatePositionFundingPNL(market, perpPosition));
|
|
443
480
|
}, ZERO);
|
|
444
481
|
}
|
|
445
482
|
|
|
446
|
-
public
|
|
447
|
-
|
|
448
|
-
withWeightMarginCategory?: MarginCategory
|
|
483
|
+
public getSpotMarketLiabilityValue(
|
|
484
|
+
marketIndex?: BN,
|
|
485
|
+
withWeightMarginCategory?: MarginCategory,
|
|
486
|
+
liquidationBuffer?: BN
|
|
449
487
|
): BN {
|
|
450
|
-
return this.getUserAccount().
|
|
451
|
-
(totalLiabilityValue,
|
|
488
|
+
return this.getUserAccount().spotPositions.reduce(
|
|
489
|
+
(totalLiabilityValue, spotPosition) => {
|
|
452
490
|
if (
|
|
453
|
-
|
|
454
|
-
isVariant(
|
|
455
|
-
(
|
|
491
|
+
spotPosition.balance.eq(ZERO) ||
|
|
492
|
+
isVariant(spotPosition.balanceType, 'deposit') ||
|
|
493
|
+
(marketIndex !== undefined &&
|
|
494
|
+
!spotPosition.marketIndex.eq(marketIndex))
|
|
456
495
|
) {
|
|
457
496
|
return totalLiabilityValue;
|
|
458
497
|
}
|
|
459
498
|
|
|
460
499
|
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
);
|
|
500
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
501
|
+
this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
|
|
464
502
|
|
|
465
503
|
const tokenAmount = getTokenAmount(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
504
|
+
spotPosition.balance,
|
|
505
|
+
spotMarketAccount,
|
|
506
|
+
spotPosition.balanceType
|
|
469
507
|
);
|
|
470
508
|
|
|
471
509
|
let liabilityValue = tokenAmount
|
|
472
|
-
.mul(
|
|
510
|
+
.mul(
|
|
511
|
+
this.getOracleDataForSpotMarket(spotMarketAccount.marketIndex).price
|
|
512
|
+
)
|
|
473
513
|
.div(MARK_PRICE_PRECISION)
|
|
474
514
|
.div(
|
|
475
515
|
new BN(10).pow(
|
|
476
|
-
new BN(
|
|
516
|
+
new BN(spotMarketAccount.decimals).sub(
|
|
517
|
+
SPOT_MARKET_BALANCE_PRECISION_EXP
|
|
518
|
+
)
|
|
477
519
|
)
|
|
478
520
|
);
|
|
479
521
|
|
|
480
522
|
if (withWeightMarginCategory !== undefined) {
|
|
481
|
-
|
|
523
|
+
let weight = calculateLiabilityWeight(
|
|
482
524
|
tokenAmount,
|
|
483
|
-
|
|
525
|
+
spotMarketAccount,
|
|
484
526
|
withWeightMarginCategory
|
|
485
527
|
);
|
|
528
|
+
|
|
529
|
+
if (liquidationBuffer !== undefined) {
|
|
530
|
+
weight = weight.add(liquidationBuffer);
|
|
531
|
+
}
|
|
532
|
+
|
|
486
533
|
liabilityValue = liabilityValue
|
|
487
534
|
.mul(weight)
|
|
488
|
-
.div(
|
|
535
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
489
536
|
}
|
|
490
537
|
|
|
491
538
|
return totalLiabilityValue.add(liabilityValue);
|
|
@@ -494,46 +541,50 @@ export class ClearingHouseUser {
|
|
|
494
541
|
);
|
|
495
542
|
}
|
|
496
543
|
|
|
497
|
-
public
|
|
498
|
-
|
|
544
|
+
public getSpotMarketAssetValue(
|
|
545
|
+
marketIndex?: BN,
|
|
499
546
|
withWeightMarginCategory?: MarginCategory
|
|
500
547
|
): BN {
|
|
501
|
-
return this.getUserAccount().
|
|
502
|
-
(totalAssetValue,
|
|
548
|
+
return this.getUserAccount().spotPositions.reduce(
|
|
549
|
+
(totalAssetValue, spotPosition) => {
|
|
503
550
|
if (
|
|
504
|
-
|
|
505
|
-
isVariant(
|
|
506
|
-
(
|
|
551
|
+
spotPosition.balance.eq(ZERO) ||
|
|
552
|
+
isVariant(spotPosition.balanceType, 'borrow') ||
|
|
553
|
+
(marketIndex !== undefined &&
|
|
554
|
+
!spotPosition.marketIndex.eq(marketIndex))
|
|
507
555
|
) {
|
|
508
556
|
return totalAssetValue;
|
|
509
557
|
}
|
|
510
558
|
|
|
511
559
|
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
);
|
|
560
|
+
const spotMarketAccount: SpotMarketAccount =
|
|
561
|
+
this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
|
|
515
562
|
|
|
516
563
|
const tokenAmount = getTokenAmount(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
564
|
+
spotPosition.balance,
|
|
565
|
+
spotMarketAccount,
|
|
566
|
+
spotPosition.balanceType
|
|
520
567
|
);
|
|
521
568
|
|
|
522
569
|
let assetValue = tokenAmount
|
|
523
|
-
.mul(
|
|
570
|
+
.mul(
|
|
571
|
+
this.getOracleDataForSpotMarket(spotMarketAccount.marketIndex).price
|
|
572
|
+
)
|
|
524
573
|
.div(MARK_PRICE_PRECISION)
|
|
525
574
|
.div(
|
|
526
575
|
new BN(10).pow(
|
|
527
|
-
new BN(
|
|
576
|
+
new BN(spotMarketAccount.decimals).sub(
|
|
577
|
+
SPOT_MARKET_BALANCE_PRECISION_EXP
|
|
578
|
+
)
|
|
528
579
|
)
|
|
529
580
|
);
|
|
530
581
|
if (withWeightMarginCategory !== undefined) {
|
|
531
582
|
const weight = calculateAssetWeight(
|
|
532
583
|
tokenAmount,
|
|
533
|
-
|
|
584
|
+
spotMarketAccount,
|
|
534
585
|
withWeightMarginCategory
|
|
535
586
|
);
|
|
536
|
-
assetValue = assetValue.mul(weight).div(
|
|
587
|
+
assetValue = assetValue.mul(weight).div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
537
588
|
}
|
|
538
589
|
|
|
539
590
|
return totalAssetValue.add(assetValue);
|
|
@@ -542,9 +593,12 @@ export class ClearingHouseUser {
|
|
|
542
593
|
);
|
|
543
594
|
}
|
|
544
595
|
|
|
545
|
-
public
|
|
546
|
-
return this.
|
|
547
|
-
|
|
596
|
+
public getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN {
|
|
597
|
+
return this.getSpotMarketAssetValue(
|
|
598
|
+
undefined,
|
|
599
|
+
withWeightMarginCategory
|
|
600
|
+
).sub(
|
|
601
|
+
this.getSpotMarketLiabilityValue(undefined, withWeightMarginCategory)
|
|
548
602
|
);
|
|
549
603
|
}
|
|
550
604
|
|
|
@@ -553,7 +607,7 @@ export class ClearingHouseUser {
|
|
|
553
607
|
* @returns : Precision QUOTE_PRECISION
|
|
554
608
|
*/
|
|
555
609
|
public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
|
|
556
|
-
return this.
|
|
610
|
+
return this.getSpotMarketAssetValue(undefined, marginCategory).add(
|
|
557
611
|
this.getUnrealizedPNL(true, undefined, marginCategory)
|
|
558
612
|
);
|
|
559
613
|
}
|
|
@@ -563,14 +617,14 @@ export class ClearingHouseUser {
|
|
|
563
617
|
* @returns : Precision QUOTE_PRECISION
|
|
564
618
|
*/
|
|
565
619
|
getTotalPositionValue(): BN {
|
|
566
|
-
return this.getUserAccount().
|
|
567
|
-
(positionValue,
|
|
568
|
-
const market = this.clearingHouse.
|
|
569
|
-
|
|
620
|
+
return this.getUserAccount().perpPositions.reduce(
|
|
621
|
+
(positionValue, perpPosition) => {
|
|
622
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
623
|
+
perpPosition.marketIndex
|
|
570
624
|
);
|
|
571
625
|
const posVal = calculateBaseAssetValueWithOracle(
|
|
572
626
|
market,
|
|
573
|
-
|
|
627
|
+
perpPosition,
|
|
574
628
|
this.getOracleDataForMarket(market.marketIndex)
|
|
575
629
|
);
|
|
576
630
|
|
|
@@ -590,7 +644,7 @@ export class ClearingHouseUser {
|
|
|
590
644
|
): BN {
|
|
591
645
|
const userPosition =
|
|
592
646
|
this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
593
|
-
const market = this.clearingHouse.
|
|
647
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
594
648
|
userPosition.marketIndex
|
|
595
649
|
);
|
|
596
650
|
return calculateBaseAssetValueWithOracle(
|
|
@@ -601,7 +655,7 @@ export class ClearingHouseUser {
|
|
|
601
655
|
}
|
|
602
656
|
|
|
603
657
|
public getPositionSide(
|
|
604
|
-
currentPosition: Pick<
|
|
658
|
+
currentPosition: Pick<PerpPosition, 'baseAssetAmount'>
|
|
605
659
|
): PositionDirection | undefined {
|
|
606
660
|
if (currentPosition.baseAssetAmount.gt(ZERO)) {
|
|
607
661
|
return PositionDirection.LONG;
|
|
@@ -617,11 +671,13 @@ export class ClearingHouseUser {
|
|
|
617
671
|
* @returns : Precision MARK_PRICE_PRECISION
|
|
618
672
|
*/
|
|
619
673
|
public getPositionEstimatedExitPriceAndPnl(
|
|
620
|
-
position:
|
|
674
|
+
position: PerpPosition,
|
|
621
675
|
amountToClose?: BN,
|
|
622
676
|
useAMMClose = false
|
|
623
677
|
): [BN, BN] {
|
|
624
|
-
const market = this.clearingHouse.
|
|
678
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
679
|
+
position.marketIndex
|
|
680
|
+
);
|
|
625
681
|
|
|
626
682
|
const entryPrice = calculateEntryPrice(position);
|
|
627
683
|
|
|
@@ -636,7 +692,7 @@ export class ClearingHouseUser {
|
|
|
636
692
|
lastCumulativeFundingRate: position.lastCumulativeFundingRate,
|
|
637
693
|
marketIndex: position.marketIndex,
|
|
638
694
|
quoteAssetAmount: position.quoteAssetAmount,
|
|
639
|
-
} as
|
|
695
|
+
} as PerpPosition;
|
|
640
696
|
}
|
|
641
697
|
|
|
642
698
|
let baseAssetValue: BN;
|
|
@@ -694,7 +750,7 @@ export class ClearingHouseUser {
|
|
|
694
750
|
marketIndex: BN | number,
|
|
695
751
|
category: MarginCategory = 'Initial'
|
|
696
752
|
): BN {
|
|
697
|
-
const market = this.clearingHouse.
|
|
753
|
+
const market = this.clearingHouse.getPerpMarketAccount(marketIndex);
|
|
698
754
|
|
|
699
755
|
const marginRatioCategory = calculateMarketMarginRatio(
|
|
700
756
|
market,
|
|
@@ -722,13 +778,19 @@ export class ClearingHouseUser {
|
|
|
722
778
|
return this.getTotalCollateral().mul(TEN_THOUSAND).div(totalPositionValue);
|
|
723
779
|
}
|
|
724
780
|
|
|
725
|
-
public canBeLiquidated():
|
|
781
|
+
public canBeLiquidated(): boolean {
|
|
726
782
|
const totalCollateral = this.getTotalCollateral();
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
783
|
+
|
|
784
|
+
// if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
|
|
785
|
+
let liquidationBuffer = undefined;
|
|
786
|
+
if (this.getUserAccount().beingLiquidated) {
|
|
787
|
+
liquidationBuffer = new BN(
|
|
788
|
+
this.clearingHouse.getStateAccount().liquidationMarginBufferRatio
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
const maintenanceRequirement =
|
|
792
|
+
this.getMaintenanceMarginRequirement(liquidationBuffer);
|
|
793
|
+
return totalCollateral.lt(maintenanceRequirement);
|
|
732
794
|
}
|
|
733
795
|
|
|
734
796
|
/**
|
|
@@ -736,12 +798,12 @@ export class ClearingHouseUser {
|
|
|
736
798
|
* @returns
|
|
737
799
|
*/
|
|
738
800
|
public needsToSettleFundingPayment(): boolean {
|
|
739
|
-
for (const userPosition of this.getUserAccount().
|
|
801
|
+
for (const userPosition of this.getUserAccount().perpPositions) {
|
|
740
802
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
741
803
|
continue;
|
|
742
804
|
}
|
|
743
805
|
|
|
744
|
-
const market = this.clearingHouse.
|
|
806
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
745
807
|
userPosition.marketIndex
|
|
746
808
|
);
|
|
747
809
|
if (
|
|
@@ -762,13 +824,13 @@ export class ClearingHouseUser {
|
|
|
762
824
|
|
|
763
825
|
/**
|
|
764
826
|
* Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
|
|
765
|
-
* @param
|
|
827
|
+
* @param PerpPosition
|
|
766
828
|
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
767
829
|
* @param partial
|
|
768
830
|
* @returns Precision : MARK_PRICE_PRECISION
|
|
769
831
|
*/
|
|
770
832
|
public liquidationPrice(
|
|
771
|
-
|
|
833
|
+
perpPosition: Pick<PerpPosition, 'marketIndex'>,
|
|
772
834
|
positionBaseSizeChange: BN = ZERO
|
|
773
835
|
): BN {
|
|
774
836
|
// solves formula for example canBeLiquidated below
|
|
@@ -787,22 +849,23 @@ export class ClearingHouseUser {
|
|
|
787
849
|
|
|
788
850
|
// calculate the total position value ignoring any value from the target market of the trade
|
|
789
851
|
const totalPositionValueExcludingTargetMarket =
|
|
790
|
-
this.getTotalPositionValueExcludingMarket(
|
|
852
|
+
this.getTotalPositionValueExcludingMarket(perpPosition.marketIndex);
|
|
791
853
|
|
|
792
|
-
const
|
|
793
|
-
this.getUserPosition(
|
|
794
|
-
this.getEmptyPosition(
|
|
854
|
+
const currentPerpPosition =
|
|
855
|
+
this.getUserPosition(perpPosition.marketIndex) ||
|
|
856
|
+
this.getEmptyPosition(perpPosition.marketIndex);
|
|
795
857
|
|
|
796
|
-
const
|
|
858
|
+
const currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
|
|
797
859
|
|
|
798
|
-
const proposedBaseAssetAmount =
|
|
860
|
+
const proposedBaseAssetAmount = currentPerpPositionBaseSize.add(
|
|
799
861
|
positionBaseSizeChange
|
|
800
862
|
);
|
|
801
863
|
|
|
802
864
|
// calculate position for current market after trade
|
|
803
|
-
const
|
|
804
|
-
marketIndex:
|
|
865
|
+
const proposedPerpPosition: PerpPosition = {
|
|
866
|
+
marketIndex: perpPosition.marketIndex,
|
|
805
867
|
baseAssetAmount: proposedBaseAssetAmount,
|
|
868
|
+
remainderBaseAssetAmount: ZERO,
|
|
806
869
|
quoteAssetAmount: new BN(0),
|
|
807
870
|
lastCumulativeFundingRate: ZERO,
|
|
808
871
|
quoteEntryAmount: new BN(0),
|
|
@@ -818,25 +881,25 @@ export class ClearingHouseUser {
|
|
|
818
881
|
|
|
819
882
|
if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
|
|
820
883
|
|
|
821
|
-
const market = this.clearingHouse.
|
|
822
|
-
|
|
884
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
885
|
+
proposedPerpPosition.marketIndex
|
|
823
886
|
);
|
|
824
887
|
|
|
825
|
-
const
|
|
888
|
+
const proposedPerpPositionValue = calculateBaseAssetValueWithOracle(
|
|
826
889
|
market,
|
|
827
|
-
|
|
890
|
+
proposedPerpPosition,
|
|
828
891
|
this.getOracleDataForMarket(market.marketIndex)
|
|
829
892
|
);
|
|
830
893
|
|
|
831
894
|
// total position value after trade
|
|
832
895
|
const totalPositionValueAfterTrade =
|
|
833
|
-
totalPositionValueExcludingTargetMarket.add(
|
|
896
|
+
totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
|
|
834
897
|
|
|
835
898
|
const marginRequirementExcludingTargetMarket =
|
|
836
|
-
this.getUserAccount().
|
|
899
|
+
this.getUserAccount().perpPositions.reduce(
|
|
837
900
|
(totalMarginRequirement, position) => {
|
|
838
|
-
if (!position.marketIndex.eq(
|
|
839
|
-
const market = this.clearingHouse.
|
|
901
|
+
if (!position.marketIndex.eq(perpPosition.marketIndex)) {
|
|
902
|
+
const market = this.clearingHouse.getPerpMarketAccount(
|
|
840
903
|
position.marketIndex
|
|
841
904
|
);
|
|
842
905
|
const positionValue = calculateBaseAssetValueWithOracle(
|
|
@@ -871,19 +934,19 @@ export class ClearingHouseUser {
|
|
|
871
934
|
// if the position value after the trade is less than free collateral, there is no liq price
|
|
872
935
|
if (
|
|
873
936
|
totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
|
|
874
|
-
|
|
937
|
+
proposedPerpPosition.baseAssetAmount.abs().gt(ZERO)
|
|
875
938
|
) {
|
|
876
939
|
return new BN(-1);
|
|
877
940
|
}
|
|
878
941
|
|
|
879
942
|
const marginRequirementAfterTrade =
|
|
880
943
|
marginRequirementExcludingTargetMarket.add(
|
|
881
|
-
|
|
944
|
+
proposedPerpPositionValue
|
|
882
945
|
.mul(
|
|
883
946
|
new BN(
|
|
884
947
|
calculateMarketMarginRatio(
|
|
885
948
|
market,
|
|
886
|
-
|
|
949
|
+
proposedPerpPosition.baseAssetAmount.abs(),
|
|
887
950
|
'Maintenance'
|
|
888
951
|
)
|
|
889
952
|
)
|
|
@@ -895,7 +958,7 @@ export class ClearingHouseUser {
|
|
|
895
958
|
);
|
|
896
959
|
|
|
897
960
|
const marketMaxLeverage = this.getMaxLeverage(
|
|
898
|
-
|
|
961
|
+
proposedPerpPosition.marketIndex,
|
|
899
962
|
'Maintenance'
|
|
900
963
|
);
|
|
901
964
|
|
|
@@ -919,8 +982,8 @@ export class ClearingHouseUser {
|
|
|
919
982
|
let markPriceAfterTrade;
|
|
920
983
|
if (positionBaseSizeChange.eq(ZERO)) {
|
|
921
984
|
markPriceAfterTrade = calculateMarkPrice(
|
|
922
|
-
this.clearingHouse.
|
|
923
|
-
this.getOracleDataForMarket(
|
|
985
|
+
this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex),
|
|
986
|
+
this.getOracleDataForMarket(perpPosition.marketIndex)
|
|
924
987
|
);
|
|
925
988
|
} else {
|
|
926
989
|
const direction = positionBaseSizeChange.gt(ZERO)
|
|
@@ -929,9 +992,9 @@ export class ClearingHouseUser {
|
|
|
929
992
|
markPriceAfterTrade = calculateTradeSlippage(
|
|
930
993
|
direction,
|
|
931
994
|
positionBaseSizeChange.abs(),
|
|
932
|
-
this.clearingHouse.
|
|
995
|
+
this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex),
|
|
933
996
|
'base',
|
|
934
|
-
this.getOracleDataForMarket(
|
|
997
|
+
this.getOracleDataForMarket(perpPosition.marketIndex)
|
|
935
998
|
)[3]; // newPrice after swap
|
|
936
999
|
}
|
|
937
1000
|
|
|
@@ -1035,21 +1098,22 @@ export class ClearingHouseUser {
|
|
|
1035
1098
|
// current leverage is greater than max leverage - can only reduce position size
|
|
1036
1099
|
|
|
1037
1100
|
if (!targetingSameSide) {
|
|
1038
|
-
const market =
|
|
1039
|
-
|
|
1101
|
+
const market =
|
|
1102
|
+
this.clearingHouse.getPerpMarketAccount(targetMarketIndex);
|
|
1103
|
+
const perpPositionValue = this.getPositionValue(
|
|
1040
1104
|
targetMarketIndex,
|
|
1041
1105
|
oracleData
|
|
1042
1106
|
);
|
|
1043
1107
|
const totalCollateral = this.getTotalCollateral();
|
|
1044
1108
|
const marginRequirement = this.getInitialMarginRequirement();
|
|
1045
|
-
const marginFreedByClosing =
|
|
1109
|
+
const marginFreedByClosing = perpPositionValue
|
|
1046
1110
|
.mul(new BN(market.marginRatioInitial))
|
|
1047
1111
|
.div(MARGIN_PRECISION);
|
|
1048
1112
|
const marginRequirementAfterClosing =
|
|
1049
1113
|
marginRequirement.sub(marginFreedByClosing);
|
|
1050
1114
|
|
|
1051
1115
|
if (marginRequirementAfterClosing.gt(totalCollateral)) {
|
|
1052
|
-
maxPositionSize =
|
|
1116
|
+
maxPositionSize = perpPositionValue;
|
|
1053
1117
|
} else {
|
|
1054
1118
|
const freeCollateralAfterClose = totalCollateral.sub(
|
|
1055
1119
|
marginRequirementAfterClosing
|
|
@@ -1057,7 +1121,7 @@ export class ClearingHouseUser {
|
|
|
1057
1121
|
const buyingPowerAfterClose = freeCollateralAfterClose
|
|
1058
1122
|
.mul(this.getMaxLeverage(targetMarketIndex))
|
|
1059
1123
|
.div(TEN_THOUSAND);
|
|
1060
|
-
maxPositionSize =
|
|
1124
|
+
maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
|
|
1061
1125
|
}
|
|
1062
1126
|
} else {
|
|
1063
1127
|
// do nothing if targetting same side
|
|
@@ -1106,7 +1170,7 @@ export class ClearingHouseUser {
|
|
|
1106
1170
|
if (tradeSide === PositionDirection.SHORT)
|
|
1107
1171
|
tradeQuoteAmount = tradeQuoteAmount.neg();
|
|
1108
1172
|
|
|
1109
|
-
const
|
|
1173
|
+
const currentPerpPositionAfterTrade = currentPositionQuoteAmount
|
|
1110
1174
|
.add(tradeQuoteAmount)
|
|
1111
1175
|
.abs();
|
|
1112
1176
|
|
|
@@ -1115,7 +1179,7 @@ export class ClearingHouseUser {
|
|
|
1115
1179
|
|
|
1116
1180
|
const totalCollateral = this.getTotalCollateral();
|
|
1117
1181
|
if (totalCollateral.gt(ZERO)) {
|
|
1118
|
-
const newLeverage =
|
|
1182
|
+
const newLeverage = currentPerpPositionAfterTrade
|
|
1119
1183
|
.add(totalPositionAfterTradeExcludingTargetMarket)
|
|
1120
1184
|
.abs()
|
|
1121
1185
|
.mul(TEN_THOUSAND)
|
|
@@ -1132,7 +1196,7 @@ export class ClearingHouseUser {
|
|
|
1132
1196
|
* @returns feeForQuote : Precision QUOTE_PRECISION
|
|
1133
1197
|
*/
|
|
1134
1198
|
public calculateFeeForQuoteAmount(quoteAmount: BN): BN {
|
|
1135
|
-
const feeStructure = this.clearingHouse.getStateAccount().
|
|
1199
|
+
const feeStructure = this.clearingHouse.getStateAccount().perpFeeStructure;
|
|
1136
1200
|
|
|
1137
1201
|
return quoteAmount
|
|
1138
1202
|
.mul(feeStructure.feeNumerator)
|
|
@@ -1145,33 +1209,34 @@ export class ClearingHouseUser {
|
|
|
1145
1209
|
* @returns positionValue : Precision QUOTE_PRECISION
|
|
1146
1210
|
*/
|
|
1147
1211
|
private getTotalPositionValueExcludingMarket(marketToIgnore: BN): BN {
|
|
1148
|
-
const
|
|
1212
|
+
const currentPerpPosition =
|
|
1149
1213
|
this.getUserPosition(marketToIgnore) ||
|
|
1150
1214
|
this.getEmptyPosition(marketToIgnore);
|
|
1151
1215
|
|
|
1152
1216
|
const oracleData = this.getOracleDataForMarket(marketToIgnore);
|
|
1153
1217
|
|
|
1154
|
-
let
|
|
1155
|
-
if (
|
|
1156
|
-
|
|
1218
|
+
let currentPerpPositionValueUSDC = ZERO;
|
|
1219
|
+
if (currentPerpPosition) {
|
|
1220
|
+
currentPerpPositionValueUSDC = this.getPositionValue(
|
|
1157
1221
|
marketToIgnore,
|
|
1158
1222
|
oracleData
|
|
1159
1223
|
);
|
|
1160
1224
|
}
|
|
1161
1225
|
|
|
1162
|
-
return this.getTotalPositionValue().sub(
|
|
1226
|
+
return this.getTotalPositionValue().sub(currentPerpPositionValueUSDC);
|
|
1163
1227
|
}
|
|
1164
1228
|
|
|
1165
1229
|
private getOracleDataForMarket(marketIndex: BN): OraclePriceData {
|
|
1166
1230
|
const oracleKey =
|
|
1167
|
-
this.clearingHouse.
|
|
1231
|
+
this.clearingHouse.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1168
1232
|
const oracleData =
|
|
1169
1233
|
this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
|
|
1170
1234
|
|
|
1171
1235
|
return oracleData;
|
|
1172
1236
|
}
|
|
1173
|
-
private
|
|
1174
|
-
const oracleKey =
|
|
1237
|
+
private getOracleDataForSpotMarket(marketIndex: BN): OraclePriceData {
|
|
1238
|
+
const oracleKey =
|
|
1239
|
+
this.clearingHouse.getSpotMarketAccount(marketIndex).oracle;
|
|
1175
1240
|
|
|
1176
1241
|
const oracleData =
|
|
1177
1242
|
this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
|