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