@drift-labs/sdk 0.2.0-master.26 → 0.2.0-master.28
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 +1 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +3 -0
- package/lib/accounts/types.d.ts +2 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +1 -0
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +3 -0
- package/lib/admin.d.ts +5 -2
- package/lib/admin.js +30 -4
- package/lib/clearingHouse.d.ts +3 -0
- package/lib/clearingHouse.js +19 -1
- package/lib/clearingHouseUser.d.ts +11 -9
- package/lib/clearingHouseUser.js +184 -108
- package/lib/config.js +1 -1
- package/lib/dlob/DLOB.d.ts +73 -0
- package/lib/dlob/DLOB.js +557 -0
- package/lib/dlob/DLOBNode.d.ts +52 -0
- package/lib/dlob/DLOBNode.js +82 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +138 -0
- package/lib/idl/clearing_house.json +123 -203
- package/lib/index.d.ts +5 -0
- package/lib/index.js +5 -0
- package/lib/math/market.d.ts +3 -2
- package/lib/math/market.js +17 -12
- package/lib/math/orders.d.ts +3 -3
- package/lib/math/orders.js +31 -16
- package/lib/math/position.d.ts +3 -3
- package/lib/math/position.js +23 -16
- package/lib/math/repeg.js +8 -0
- package/lib/math/spotBalance.d.ts +3 -0
- package/lib/math/spotBalance.js +18 -1
- package/lib/math/spotPosition.d.ts +5 -1
- package/lib/math/spotPosition.js +16 -1
- package/lib/types.d.ts +25 -24
- package/lib/types.js +9 -3
- package/lib/userMap/userMap.d.ts +25 -0
- package/lib/userMap/userMap.js +73 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/package.json +6 -3
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +4 -0
- package/src/accounts/types.ts +1 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +6 -0
- package/src/admin.ts +50 -8
- package/src/clearingHouse.ts +30 -1
- package/src/clearingHouseUser.ts +366 -167
- package/src/config.ts +1 -1
- package/src/dlob/DLOB.ts +884 -0
- package/src/dlob/DLOBNode.ts +163 -0
- package/src/dlob/NodeList.ts +185 -0
- package/src/idl/clearing_house.json +123 -203
- package/src/index.ts +5 -0
- package/src/math/market.ts +22 -13
- package/src/math/orders.ts +29 -21
- package/src/math/position.ts +36 -22
- package/src/math/repeg.ts +9 -0
- package/src/math/spotBalance.ts +26 -0
- package/src/math/spotPosition.ts +42 -1
- package/src/types.ts +26 -24
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -0
- package/tests/bn/test.ts +2 -3
- package/tests/dlob/helpers.ts +322 -0
- package/tests/dlob/test.ts +2865 -0
- package/my-script/.env +0 -7
- package/my-script/getUserStats.ts +0 -106
- package/my-script/multiConnections.ts +0 -119
- package/my-script/test-regex.ts +0 -11
- package/my-script/utils.ts +0 -52
- package/src/accounts/bulkAccountLoader.js +0 -249
- package/src/accounts/bulkUserStatsSubscription.js +0 -75
- package/src/accounts/bulkUserSubscription.js +0 -75
- package/src/accounts/fetch.js +0 -92
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -465
- package/src/accounts/pollingOracleSubscriber.js +0 -156
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -141
- package/src/accounts/pollingUserAccountSubscriber.js +0 -208
- package/src/accounts/pollingUserStatsAccountSubscriber.js +0 -208
- package/src/accounts/types.js +0 -28
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -138
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -433
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -113
- package/src/accounts/webSocketUserStatsAccountSubsriber.js +0 -113
- package/src/addresses/pda.js +0 -186
- package/src/admin.js +0 -1284
- package/src/assert/assert.js +0 -9
- package/src/clearingHouse.js +0 -3433
- package/src/clearingHouseConfig.js +0 -2
- package/src/clearingHouseUser.js +0 -874
- package/src/clearingHouseUserConfig.js +0 -2
- package/src/clearingHouseUserStats.js +0 -115
- package/src/clearingHouseUserStatsConfig.js +0 -2
- package/src/config.js +0 -80
- package/src/constants/numericConstants.js +0 -48
- package/src/constants/perpMarkets.js +0 -42
- package/src/constants/spotMarkets.js +0 -51
- package/src/events/eventList.js +0 -120
- package/src/events/eventSubscriber.js +0 -202
- package/src/events/fetchLogs.js +0 -117
- package/src/events/pollingLogProvider.js +0 -113
- package/src/events/sort.js +0 -41
- package/src/events/txEventCache.js +0 -74
- package/src/events/types.js +0 -25
- package/src/events/webSocketLogProvider.js +0 -76
- package/src/factory/bigNum.js +0 -393
- package/src/factory/oracleClient.js +0 -20
- package/src/index.js +0 -75
- package/src/math/amm.js +0 -422
- package/src/math/auction.js +0 -42
- package/src/math/conversion.js +0 -12
- package/src/math/funding.js +0 -296
- package/src/math/insurance.js +0 -27
- package/src/math/margin.js +0 -77
- package/src/math/market.js +0 -105
- package/src/math/oracles.js +0 -56
- package/src/math/orders.js +0 -153
- package/src/math/position.js +0 -172
- package/src/math/repeg.js +0 -128
- package/src/math/spotBalance.js +0 -176
- package/src/math/spotMarket.js +0 -8
- package/src/math/spotPosition.js +0 -8
- package/src/math/trade.js +0 -260
- package/src/math/utils.js +0 -27
- package/src/oracles/oracleClientCache.js +0 -20
- package/src/oracles/pythClient.js +0 -81
- package/src/oracles/quoteAssetOracleClient.js +0 -63
- package/src/oracles/switchboardClient.js +0 -101
- package/src/oracles/types.js +0 -2
- package/src/orderParams.js +0 -28
- package/src/serum/serumSubscriber.js +0 -102
- package/src/serum/types.js +0 -2
- package/src/slot/SlotSubscriber.js +0 -86
- package/src/token/index.js +0 -38
- package/src/tokenFaucet.js +0 -323
- package/src/tx/retryTxSender.js +0 -280
- package/src/tx/types.js +0 -2
- package/src/tx/utils.js +0 -18
- package/src/types.js +0 -216
- package/src/userName.js +0 -20
- package/src/util/computeUnits.js +0 -62
- package/src/util/promiseTimeout.js +0 -14
- package/src/util/tps.js +0 -61
- package/src/wallet.js +0 -72
package/src/clearingHouseUser.ts
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
PRICE_TO_QUOTE_PRECISION,
|
|
22
22
|
MARGIN_PRECISION,
|
|
23
23
|
SPOT_MARKET_WEIGHT_PRECISION,
|
|
24
|
-
|
|
24
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
25
25
|
} from './constants/numericConstants';
|
|
26
26
|
import {
|
|
27
27
|
UserAccountSubscriber,
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
calculateTradeSlippage,
|
|
40
40
|
BN,
|
|
41
41
|
SpotMarketAccount,
|
|
42
|
+
getTokenValue,
|
|
42
43
|
} from '.';
|
|
43
44
|
import {
|
|
44
45
|
getTokenAmount,
|
|
@@ -53,6 +54,10 @@ import { OraclePriceData } from './oracles/types';
|
|
|
53
54
|
import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
|
|
54
55
|
import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
|
|
55
56
|
import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
|
|
57
|
+
import {
|
|
58
|
+
getWorstCaseTokenAmounts,
|
|
59
|
+
isSpotPositionAvailable,
|
|
60
|
+
} from './math/spotPosition';
|
|
56
61
|
export class ClearingHouseUser {
|
|
57
62
|
clearingHouse: ClearingHouse;
|
|
58
63
|
userAccountPublicKey: PublicKey;
|
|
@@ -137,7 +142,7 @@ export class ClearingHouseUser {
|
|
|
137
142
|
openOrders: ZERO,
|
|
138
143
|
openBids: ZERO,
|
|
139
144
|
openAsks: ZERO,
|
|
140
|
-
|
|
145
|
+
settledPnl: ZERO,
|
|
141
146
|
lpShares: ZERO,
|
|
142
147
|
lastFeePerLp: ZERO,
|
|
143
148
|
lastNetBaseAssetAmountPerLp: ZERO,
|
|
@@ -313,93 +318,21 @@ export class ClearingHouseUser {
|
|
|
313
318
|
* @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
|
|
314
319
|
*/
|
|
315
320
|
public getMarginRequirement(
|
|
316
|
-
|
|
321
|
+
marginCategory: MarginCategory,
|
|
317
322
|
liquidationBuffer?: BN
|
|
318
323
|
): BN {
|
|
319
|
-
return this.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const [settledPosition, dustBaa, _] = this.getSettledLPPosition(
|
|
332
|
-
market.marketIndex
|
|
333
|
-
);
|
|
334
|
-
perpPosition.baseAssetAmount =
|
|
335
|
-
settledPosition.baseAssetAmount.add(dustBaa);
|
|
336
|
-
perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
|
337
|
-
|
|
338
|
-
// open orders
|
|
339
|
-
let openAsks;
|
|
340
|
-
if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
|
|
341
|
-
openAsks = market.amm.maxBaseAssetReserve
|
|
342
|
-
.sub(market.amm.baseAssetReserve)
|
|
343
|
-
.mul(perpPosition.lpShares)
|
|
344
|
-
.div(market.amm.sqrtK)
|
|
345
|
-
.mul(new BN(-1));
|
|
346
|
-
} else {
|
|
347
|
-
openAsks = ZERO;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
let openBids;
|
|
351
|
-
if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
|
|
352
|
-
openBids = market.amm.baseAssetReserve
|
|
353
|
-
.sub(market.amm.minBaseAssetReserve)
|
|
354
|
-
.mul(perpPosition.lpShares)
|
|
355
|
-
.div(market.amm.sqrtK);
|
|
356
|
-
} else {
|
|
357
|
-
openBids = ZERO;
|
|
358
|
-
}
|
|
359
|
-
|
|
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;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
const worstCaseBaseAssetAmount =
|
|
373
|
-
calculateWorstCaseBaseAssetAmount(perpPosition);
|
|
374
|
-
|
|
375
|
-
const worstCaseAssetValue = worstCaseBaseAssetAmount
|
|
376
|
-
.abs()
|
|
377
|
-
.mul(valuationPrice)
|
|
378
|
-
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
379
|
-
|
|
380
|
-
const positionMarginRequirement = worstCaseAssetValue
|
|
381
|
-
.mul(
|
|
382
|
-
new BN(
|
|
383
|
-
calculateMarketMarginRatio(
|
|
384
|
-
market,
|
|
385
|
-
worstCaseBaseAssetAmount.abs(),
|
|
386
|
-
type
|
|
387
|
-
)
|
|
388
|
-
)
|
|
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);
|
|
399
|
-
}, ZERO)
|
|
400
|
-
.add(
|
|
401
|
-
this.getSpotMarketLiabilityValue(undefined, type, liquidationBuffer)
|
|
402
|
-
);
|
|
324
|
+
return this.getTotalPerpPositionValue(
|
|
325
|
+
marginCategory,
|
|
326
|
+
liquidationBuffer,
|
|
327
|
+
true
|
|
328
|
+
).add(
|
|
329
|
+
this.getSpotMarketLiabilityValue(
|
|
330
|
+
undefined,
|
|
331
|
+
marginCategory,
|
|
332
|
+
liquidationBuffer,
|
|
333
|
+
true
|
|
334
|
+
)
|
|
335
|
+
);
|
|
403
336
|
}
|
|
404
337
|
|
|
405
338
|
/**
|
|
@@ -482,74 +415,165 @@ export class ClearingHouseUser {
|
|
|
482
415
|
|
|
483
416
|
public getSpotMarketLiabilityValue(
|
|
484
417
|
marketIndex?: BN,
|
|
485
|
-
|
|
486
|
-
liquidationBuffer?: BN
|
|
418
|
+
marginCategory?: MarginCategory,
|
|
419
|
+
liquidationBuffer?: BN,
|
|
420
|
+
includeOpenOrders?: boolean
|
|
487
421
|
): BN {
|
|
488
422
|
return this.getUserAccount().spotPositions.reduce(
|
|
489
423
|
(totalLiabilityValue, spotPosition) => {
|
|
490
424
|
if (
|
|
491
|
-
spotPosition
|
|
492
|
-
isVariant(spotPosition.balanceType, 'deposit') ||
|
|
425
|
+
isSpotPositionAvailable(spotPosition) ||
|
|
493
426
|
(marketIndex !== undefined &&
|
|
494
427
|
!spotPosition.marketIndex.eq(marketIndex))
|
|
495
428
|
) {
|
|
496
429
|
return totalLiabilityValue;
|
|
497
430
|
}
|
|
498
431
|
|
|
499
|
-
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
500
432
|
const spotMarketAccount: SpotMarketAccount =
|
|
501
433
|
this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
|
|
502
434
|
|
|
503
|
-
|
|
504
|
-
spotPosition.
|
|
505
|
-
|
|
506
|
-
|
|
435
|
+
if (spotPosition.marketIndex.eq(QUOTE_SPOT_MARKET_INDEX)) {
|
|
436
|
+
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
437
|
+
const tokenAmount = getTokenAmount(
|
|
438
|
+
spotPosition.balance,
|
|
439
|
+
spotMarketAccount,
|
|
440
|
+
spotPosition.balanceType
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
let weight = SPOT_MARKET_WEIGHT_PRECISION;
|
|
444
|
+
if (marginCategory === 'Initial') {
|
|
445
|
+
weight = BN.max(
|
|
446
|
+
weight,
|
|
447
|
+
new BN(this.getUserAccount().customMarginRatio)
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const weightedTokenValue = tokenAmount
|
|
452
|
+
.mul(weight)
|
|
453
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
454
|
+
|
|
455
|
+
return totalLiabilityValue.add(weightedTokenValue);
|
|
456
|
+
} else {
|
|
457
|
+
return totalLiabilityValue;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
462
|
+
spotPosition.marketIndex
|
|
507
463
|
);
|
|
508
464
|
|
|
509
|
-
|
|
510
|
-
.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
465
|
+
if (!includeOpenOrders) {
|
|
466
|
+
if (isVariant(spotPosition.balanceType, 'borrow')) {
|
|
467
|
+
const tokenAmount = getTokenAmount(
|
|
468
|
+
spotPosition.balance,
|
|
469
|
+
spotMarketAccount,
|
|
470
|
+
spotPosition.balanceType
|
|
471
|
+
);
|
|
472
|
+
const liabilityValue = this.getSpotLiabilityValue(
|
|
473
|
+
tokenAmount,
|
|
474
|
+
oraclePriceData,
|
|
475
|
+
spotMarketAccount,
|
|
476
|
+
marginCategory,
|
|
477
|
+
liquidationBuffer
|
|
478
|
+
);
|
|
479
|
+
return totalLiabilityValue.add(liabilityValue);
|
|
480
|
+
} else {
|
|
481
|
+
return totalLiabilityValue;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
|
|
486
|
+
getWorstCaseTokenAmounts(
|
|
487
|
+
spotPosition,
|
|
488
|
+
spotMarketAccount,
|
|
489
|
+
this.getOracleDataForSpotMarket(spotPosition.marketIndex)
|
|
520
490
|
);
|
|
521
491
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
492
|
+
let newTotalLiabilityValue = totalLiabilityValue;
|
|
493
|
+
if (worstCaseTokenAmount.lt(ZERO)) {
|
|
494
|
+
const baseLiabilityValue = this.getSpotLiabilityValue(
|
|
495
|
+
worstCaseTokenAmount,
|
|
496
|
+
oraclePriceData,
|
|
525
497
|
spotMarketAccount,
|
|
526
|
-
|
|
498
|
+
marginCategory,
|
|
499
|
+
liquidationBuffer
|
|
527
500
|
);
|
|
528
501
|
|
|
529
|
-
|
|
530
|
-
|
|
502
|
+
newTotalLiabilityValue =
|
|
503
|
+
newTotalLiabilityValue.add(baseLiabilityValue);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (worstCaseQuoteTokenAmount.lt(ZERO)) {
|
|
507
|
+
let weight = SPOT_MARKET_WEIGHT_PRECISION;
|
|
508
|
+
if (marginCategory === 'Initial') {
|
|
509
|
+
weight = BN.max(
|
|
510
|
+
weight,
|
|
511
|
+
new BN(this.getUserAccount().customMarginRatio)
|
|
512
|
+
);
|
|
531
513
|
}
|
|
532
514
|
|
|
533
|
-
|
|
515
|
+
const weightedTokenValue = worstCaseQuoteTokenAmount
|
|
534
516
|
.mul(weight)
|
|
535
517
|
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
518
|
+
|
|
519
|
+
newTotalLiabilityValue =
|
|
520
|
+
newTotalLiabilityValue.add(weightedTokenValue);
|
|
536
521
|
}
|
|
537
522
|
|
|
538
|
-
return
|
|
523
|
+
return newTotalLiabilityValue;
|
|
539
524
|
},
|
|
540
525
|
ZERO
|
|
541
526
|
);
|
|
542
527
|
}
|
|
543
528
|
|
|
529
|
+
getSpotLiabilityValue(
|
|
530
|
+
tokenAmount: BN,
|
|
531
|
+
oraclePriceData: OraclePriceData,
|
|
532
|
+
spotMarketAccount: SpotMarketAccount,
|
|
533
|
+
marginCategory?: MarginCategory,
|
|
534
|
+
liquidationBuffer?: BN
|
|
535
|
+
): BN {
|
|
536
|
+
let liabilityValue = getTokenValue(
|
|
537
|
+
tokenAmount,
|
|
538
|
+
spotMarketAccount.decimals,
|
|
539
|
+
oraclePriceData
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
if (marginCategory !== undefined) {
|
|
543
|
+
let weight = calculateLiabilityWeight(
|
|
544
|
+
tokenAmount,
|
|
545
|
+
spotMarketAccount,
|
|
546
|
+
marginCategory
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
if (marginCategory === 'Initial') {
|
|
550
|
+
weight = BN.max(
|
|
551
|
+
weight,
|
|
552
|
+
new BN(this.getUserAccount().customMarginRatio)
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (liquidationBuffer !== undefined) {
|
|
557
|
+
weight = weight.add(liquidationBuffer);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
liabilityValue = liabilityValue
|
|
561
|
+
.mul(weight)
|
|
562
|
+
.div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return liabilityValue;
|
|
566
|
+
}
|
|
567
|
+
|
|
544
568
|
public getSpotMarketAssetValue(
|
|
545
569
|
marketIndex?: BN,
|
|
546
|
-
|
|
570
|
+
marginCategory?: MarginCategory,
|
|
571
|
+
includeOpenOrders?: boolean
|
|
547
572
|
): BN {
|
|
548
573
|
return this.getUserAccount().spotPositions.reduce(
|
|
549
574
|
(totalAssetValue, spotPosition) => {
|
|
550
575
|
if (
|
|
551
|
-
spotPosition
|
|
552
|
-
isVariant(spotPosition.balanceType, 'borrow') ||
|
|
576
|
+
isSpotPositionAvailable(spotPosition) ||
|
|
553
577
|
(marketIndex !== undefined &&
|
|
554
578
|
!spotPosition.marketIndex.eq(marketIndex))
|
|
555
579
|
) {
|
|
@@ -560,39 +584,99 @@ export class ClearingHouseUser {
|
|
|
560
584
|
const spotMarketAccount: SpotMarketAccount =
|
|
561
585
|
this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
|
|
562
586
|
|
|
563
|
-
|
|
564
|
-
spotPosition.
|
|
565
|
-
|
|
566
|
-
|
|
587
|
+
if (spotPosition.marketIndex.eq(QUOTE_SPOT_MARKET_INDEX)) {
|
|
588
|
+
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
589
|
+
const tokenAmount = getTokenAmount(
|
|
590
|
+
spotPosition.balance,
|
|
591
|
+
spotMarketAccount,
|
|
592
|
+
spotPosition.balanceType
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
return totalAssetValue.add(tokenAmount);
|
|
596
|
+
} else {
|
|
597
|
+
return totalAssetValue;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(
|
|
602
|
+
spotPosition.marketIndex
|
|
567
603
|
);
|
|
568
604
|
|
|
569
|
-
|
|
570
|
-
.
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
605
|
+
if (!includeOpenOrders) {
|
|
606
|
+
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
607
|
+
const tokenAmount = getTokenAmount(
|
|
608
|
+
spotPosition.balance,
|
|
609
|
+
spotMarketAccount,
|
|
610
|
+
spotPosition.balanceType
|
|
611
|
+
);
|
|
612
|
+
const assetValue = this.getSpotAssetValue(
|
|
613
|
+
tokenAmount,
|
|
614
|
+
oraclePriceData,
|
|
615
|
+
spotMarketAccount,
|
|
616
|
+
marginCategory
|
|
617
|
+
);
|
|
618
|
+
return totalAssetValue.add(assetValue);
|
|
619
|
+
} else {
|
|
620
|
+
return totalAssetValue;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const [worstCaseTokenAmount, worstCaseQuoteTokenAmount] =
|
|
625
|
+
getWorstCaseTokenAmounts(
|
|
626
|
+
spotPosition,
|
|
627
|
+
spotMarketAccount,
|
|
628
|
+
this.getOracleDataForSpotMarket(spotPosition.marketIndex)
|
|
580
629
|
);
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
630
|
+
|
|
631
|
+
let newTotalAssetValue = totalAssetValue;
|
|
632
|
+
if (worstCaseTokenAmount.gt(ZERO)) {
|
|
633
|
+
const baseAssetValue = this.getSpotAssetValue(
|
|
634
|
+
worstCaseTokenAmount,
|
|
635
|
+
oraclePriceData,
|
|
584
636
|
spotMarketAccount,
|
|
585
|
-
|
|
637
|
+
marginCategory
|
|
638
|
+
);
|
|
639
|
+
|
|
640
|
+
newTotalAssetValue = newTotalAssetValue.add(baseAssetValue);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if (worstCaseQuoteTokenAmount.gt(ZERO)) {
|
|
644
|
+
newTotalAssetValue = newTotalAssetValue.add(
|
|
645
|
+
worstCaseQuoteTokenAmount
|
|
586
646
|
);
|
|
587
|
-
assetValue = assetValue.mul(weight).div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
588
647
|
}
|
|
589
648
|
|
|
590
|
-
return
|
|
649
|
+
return newTotalAssetValue;
|
|
591
650
|
},
|
|
592
651
|
ZERO
|
|
593
652
|
);
|
|
594
653
|
}
|
|
595
654
|
|
|
655
|
+
getSpotAssetValue(
|
|
656
|
+
tokenAmount: BN,
|
|
657
|
+
oraclePriceData: OraclePriceData,
|
|
658
|
+
spotMarketAccount: SpotMarketAccount,
|
|
659
|
+
marginCategory?: MarginCategory
|
|
660
|
+
): BN {
|
|
661
|
+
let assetValue = getTokenValue(
|
|
662
|
+
tokenAmount,
|
|
663
|
+
spotMarketAccount.decimals,
|
|
664
|
+
oraclePriceData
|
|
665
|
+
);
|
|
666
|
+
|
|
667
|
+
if (marginCategory !== undefined) {
|
|
668
|
+
const weight = calculateAssetWeight(
|
|
669
|
+
tokenAmount,
|
|
670
|
+
spotMarketAccount,
|
|
671
|
+
marginCategory
|
|
672
|
+
);
|
|
673
|
+
|
|
674
|
+
assetValue = assetValue.mul(weight).div(SPOT_MARKET_WEIGHT_PRECISION);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return assetValue;
|
|
678
|
+
}
|
|
679
|
+
|
|
596
680
|
public getNetSpotMarketValue(withWeightMarginCategory?: MarginCategory): BN {
|
|
597
681
|
return this.getSpotMarketAssetValue(
|
|
598
682
|
undefined,
|
|
@@ -607,7 +691,7 @@ export class ClearingHouseUser {
|
|
|
607
691
|
* @returns : Precision QUOTE_PRECISION
|
|
608
692
|
*/
|
|
609
693
|
public getTotalCollateral(marginCategory: MarginCategory = 'Initial'): BN {
|
|
610
|
-
return this.getSpotMarketAssetValue(undefined, marginCategory).add(
|
|
694
|
+
return this.getSpotMarketAssetValue(undefined, marginCategory, true).add(
|
|
611
695
|
this.getUnrealizedPNL(true, undefined, marginCategory)
|
|
612
696
|
);
|
|
613
697
|
}
|
|
@@ -616,19 +700,99 @@ export class ClearingHouseUser {
|
|
|
616
700
|
* calculates sum of position value across all positions in margin system
|
|
617
701
|
* @returns : Precision QUOTE_PRECISION
|
|
618
702
|
*/
|
|
619
|
-
|
|
703
|
+
getTotalPerpPositionValue(
|
|
704
|
+
marginCategory?: MarginCategory,
|
|
705
|
+
liquidationBuffer?: BN,
|
|
706
|
+
includeOpenOrders?: boolean
|
|
707
|
+
): BN {
|
|
620
708
|
return this.getUserAccount().perpPositions.reduce(
|
|
621
|
-
(
|
|
709
|
+
(totalPerpValue, perpPosition) => {
|
|
622
710
|
const market = this.clearingHouse.getPerpMarketAccount(
|
|
623
711
|
perpPosition.marketIndex
|
|
624
712
|
);
|
|
625
|
-
const posVal = calculateBaseAssetValueWithOracle(
|
|
626
|
-
market,
|
|
627
|
-
perpPosition,
|
|
628
|
-
this.getOracleDataForMarket(market.marketIndex)
|
|
629
|
-
);
|
|
630
713
|
|
|
631
|
-
|
|
714
|
+
if (perpPosition.lpShares.gt(ZERO)) {
|
|
715
|
+
// is an lp
|
|
716
|
+
// clone so we dont mutate the position
|
|
717
|
+
perpPosition = this.getClonedPosition(perpPosition);
|
|
718
|
+
|
|
719
|
+
// settle position
|
|
720
|
+
const [settledPosition, dustBaa, _] = this.getSettledLPPosition(
|
|
721
|
+
market.marketIndex
|
|
722
|
+
);
|
|
723
|
+
perpPosition.baseAssetAmount =
|
|
724
|
+
settledPosition.baseAssetAmount.add(dustBaa);
|
|
725
|
+
perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
|
726
|
+
|
|
727
|
+
// open orders
|
|
728
|
+
let openAsks;
|
|
729
|
+
if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
|
|
730
|
+
openAsks = market.amm.maxBaseAssetReserve
|
|
731
|
+
.sub(market.amm.baseAssetReserve)
|
|
732
|
+
.mul(perpPosition.lpShares)
|
|
733
|
+
.div(market.amm.sqrtK)
|
|
734
|
+
.mul(new BN(-1));
|
|
735
|
+
} else {
|
|
736
|
+
openAsks = ZERO;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
let openBids;
|
|
740
|
+
if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
|
|
741
|
+
openBids = market.amm.baseAssetReserve
|
|
742
|
+
.sub(market.amm.minBaseAssetReserve)
|
|
743
|
+
.mul(perpPosition.lpShares)
|
|
744
|
+
.div(market.amm.sqrtK);
|
|
745
|
+
} else {
|
|
746
|
+
openBids = ZERO;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
perpPosition.openAsks = perpPosition.openAsks.add(openAsks);
|
|
750
|
+
perpPosition.openBids = perpPosition.openBids.add(openBids);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
let valuationPrice = this.getOracleDataForMarket(
|
|
754
|
+
market.marketIndex
|
|
755
|
+
).price;
|
|
756
|
+
|
|
757
|
+
if (isVariant(market.status, 'settlement')) {
|
|
758
|
+
valuationPrice = market.settlementPrice;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
const baseAssetAmount = includeOpenOrders
|
|
762
|
+
? calculateWorstCaseBaseAssetAmount(perpPosition)
|
|
763
|
+
: perpPosition.baseAssetAmount;
|
|
764
|
+
|
|
765
|
+
let baseAssetValue = baseAssetAmount
|
|
766
|
+
.abs()
|
|
767
|
+
.mul(valuationPrice)
|
|
768
|
+
.div(AMM_TO_QUOTE_PRECISION_RATIO.mul(MARK_PRICE_PRECISION));
|
|
769
|
+
|
|
770
|
+
if (marginCategory) {
|
|
771
|
+
let marginRatio = new BN(
|
|
772
|
+
calculateMarketMarginRatio(
|
|
773
|
+
market,
|
|
774
|
+
baseAssetAmount.abs(),
|
|
775
|
+
marginCategory
|
|
776
|
+
)
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
if (marginCategory === 'Initial') {
|
|
780
|
+
marginRatio = BN.max(
|
|
781
|
+
marginRatio,
|
|
782
|
+
new BN(this.getUserAccount().customMarginRatio)
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
if (liquidationBuffer !== undefined) {
|
|
787
|
+
marginRatio = marginRatio.add(liquidationBuffer);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
baseAssetValue = baseAssetValue
|
|
791
|
+
.mul(marginRatio)
|
|
792
|
+
.div(MARGIN_PRECISION);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
return totalPerpValue.add(baseAssetValue);
|
|
632
796
|
},
|
|
633
797
|
ZERO
|
|
634
798
|
);
|
|
@@ -638,7 +802,7 @@ export class ClearingHouseUser {
|
|
|
638
802
|
* calculates position value in margin system
|
|
639
803
|
* @returns : Precision QUOTE_PRECISION
|
|
640
804
|
*/
|
|
641
|
-
public
|
|
805
|
+
public getPerpPositionValue(
|
|
642
806
|
marketIndex: BN,
|
|
643
807
|
oraclePriceData: OraclePriceData
|
|
644
808
|
): BN {
|
|
@@ -732,13 +896,31 @@ export class ClearingHouseUser {
|
|
|
732
896
|
* calculates current user leverage across all positions
|
|
733
897
|
* @returns : Precision TEN_THOUSAND
|
|
734
898
|
*/
|
|
735
|
-
public getLeverage(): BN {
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
|
|
899
|
+
public getLeverage(marginCategory?: MarginCategory): BN {
|
|
900
|
+
const totalLiabilityValue = this.getTotalPerpPositionValue(
|
|
901
|
+
marginCategory,
|
|
902
|
+
undefined,
|
|
903
|
+
true
|
|
904
|
+
).add(
|
|
905
|
+
this.getSpotMarketLiabilityValue(
|
|
906
|
+
undefined,
|
|
907
|
+
marginCategory,
|
|
908
|
+
undefined,
|
|
909
|
+
true
|
|
910
|
+
)
|
|
911
|
+
);
|
|
912
|
+
|
|
913
|
+
const totalAssetValue = this.getSpotMarketAssetValue(
|
|
914
|
+
undefined,
|
|
915
|
+
marginCategory,
|
|
916
|
+
true
|
|
917
|
+
).add(this.getUnrealizedPNL(true, undefined, marginCategory));
|
|
918
|
+
|
|
919
|
+
if (totalAssetValue.eq(ZERO) && totalLiabilityValue.eq(ZERO)) {
|
|
739
920
|
return ZERO;
|
|
740
921
|
}
|
|
741
|
-
|
|
922
|
+
|
|
923
|
+
return totalLiabilityValue.mul(TEN_THOUSAND).div(totalAssetValue);
|
|
742
924
|
}
|
|
743
925
|
|
|
744
926
|
/**
|
|
@@ -768,14 +950,31 @@ export class ClearingHouseUser {
|
|
|
768
950
|
* calculates margin ratio: total collateral / |total position value|
|
|
769
951
|
* @returns : Precision TEN_THOUSAND
|
|
770
952
|
*/
|
|
771
|
-
public getMarginRatio(): BN {
|
|
772
|
-
const
|
|
953
|
+
public getMarginRatio(marginCategory?: MarginCategory): BN {
|
|
954
|
+
const totalLiabilityValue = this.getTotalPerpPositionValue(
|
|
955
|
+
marginCategory,
|
|
956
|
+
undefined,
|
|
957
|
+
true
|
|
958
|
+
).add(
|
|
959
|
+
this.getSpotMarketLiabilityValue(
|
|
960
|
+
undefined,
|
|
961
|
+
marginCategory,
|
|
962
|
+
undefined,
|
|
963
|
+
true
|
|
964
|
+
)
|
|
965
|
+
);
|
|
773
966
|
|
|
774
|
-
if (
|
|
967
|
+
if (totalLiabilityValue.eq(ZERO)) {
|
|
775
968
|
return BN_MAX;
|
|
776
969
|
}
|
|
777
970
|
|
|
778
|
-
|
|
971
|
+
const totalAssetValue = this.getSpotMarketAssetValue(
|
|
972
|
+
undefined,
|
|
973
|
+
marginCategory,
|
|
974
|
+
true
|
|
975
|
+
).add(this.getUnrealizedPNL(true, undefined, marginCategory));
|
|
976
|
+
|
|
977
|
+
return totalAssetValue.mul(TEN_THOUSAND).div(totalLiabilityValue);
|
|
779
978
|
}
|
|
780
979
|
|
|
781
980
|
public canBeLiquidated(): boolean {
|
|
@@ -849,7 +1048,7 @@ export class ClearingHouseUser {
|
|
|
849
1048
|
|
|
850
1049
|
// calculate the total position value ignoring any value from the target market of the trade
|
|
851
1050
|
const totalPositionValueExcludingTargetMarket =
|
|
852
|
-
this.
|
|
1051
|
+
this.getTotalPerpPositionValueExcludingMarket(perpPosition.marketIndex);
|
|
853
1052
|
|
|
854
1053
|
const currentPerpPosition =
|
|
855
1054
|
this.getUserPosition(perpPosition.marketIndex) ||
|
|
@@ -872,7 +1071,7 @@ export class ClearingHouseUser {
|
|
|
872
1071
|
openOrders: new BN(0),
|
|
873
1072
|
openBids: new BN(0),
|
|
874
1073
|
openAsks: new BN(0),
|
|
875
|
-
|
|
1074
|
+
settledPnl: ZERO,
|
|
876
1075
|
lpShares: ZERO,
|
|
877
1076
|
lastFeePerLp: ZERO,
|
|
878
1077
|
lastNetBaseAssetAmountPerLp: ZERO,
|
|
@@ -1081,7 +1280,7 @@ export class ClearingHouseUser {
|
|
|
1081
1280
|
// 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.
|
|
1082
1281
|
const oppositeSizeValueUSDC = targetingSameSide
|
|
1083
1282
|
? ZERO
|
|
1084
|
-
: this.
|
|
1283
|
+
: this.getPerpPositionValue(targetMarketIndex, oracleData);
|
|
1085
1284
|
|
|
1086
1285
|
let maxPositionSize = this.getBuyingPower(targetMarketIndex);
|
|
1087
1286
|
if (maxPositionSize.gte(ZERO)) {
|
|
@@ -1100,7 +1299,7 @@ export class ClearingHouseUser {
|
|
|
1100
1299
|
if (!targetingSameSide) {
|
|
1101
1300
|
const market =
|
|
1102
1301
|
this.clearingHouse.getPerpMarketAccount(targetMarketIndex);
|
|
1103
|
-
const perpPositionValue = this.
|
|
1302
|
+
const perpPositionValue = this.getPerpPositionValue(
|
|
1104
1303
|
targetMarketIndex,
|
|
1105
1304
|
oracleData
|
|
1106
1305
|
);
|
|
@@ -1154,7 +1353,7 @@ export class ClearingHouseUser {
|
|
|
1154
1353
|
|
|
1155
1354
|
const oracleData = this.getOracleDataForMarket(targetMarketIndex);
|
|
1156
1355
|
|
|
1157
|
-
let currentPositionQuoteAmount = this.
|
|
1356
|
+
let currentPositionQuoteAmount = this.getPerpPositionValue(
|
|
1158
1357
|
targetMarketIndex,
|
|
1159
1358
|
oracleData
|
|
1160
1359
|
);
|
|
@@ -1175,7 +1374,7 @@ export class ClearingHouseUser {
|
|
|
1175
1374
|
.abs();
|
|
1176
1375
|
|
|
1177
1376
|
const totalPositionAfterTradeExcludingTargetMarket =
|
|
1178
|
-
this.
|
|
1377
|
+
this.getTotalPerpPositionValueExcludingMarket(targetMarketIndex);
|
|
1179
1378
|
|
|
1180
1379
|
const totalCollateral = this.getTotalCollateral();
|
|
1181
1380
|
if (totalCollateral.gt(ZERO)) {
|
|
@@ -1208,7 +1407,7 @@ export class ClearingHouseUser {
|
|
|
1208
1407
|
* @param marketToIgnore
|
|
1209
1408
|
* @returns positionValue : Precision QUOTE_PRECISION
|
|
1210
1409
|
*/
|
|
1211
|
-
private
|
|
1410
|
+
private getTotalPerpPositionValueExcludingMarket(marketToIgnore: BN): BN {
|
|
1212
1411
|
const currentPerpPosition =
|
|
1213
1412
|
this.getUserPosition(marketToIgnore) ||
|
|
1214
1413
|
this.getEmptyPosition(marketToIgnore);
|
|
@@ -1217,13 +1416,13 @@ export class ClearingHouseUser {
|
|
|
1217
1416
|
|
|
1218
1417
|
let currentPerpPositionValueUSDC = ZERO;
|
|
1219
1418
|
if (currentPerpPosition) {
|
|
1220
|
-
currentPerpPositionValueUSDC = this.
|
|
1419
|
+
currentPerpPositionValueUSDC = this.getPerpPositionValue(
|
|
1221
1420
|
marketToIgnore,
|
|
1222
1421
|
oracleData
|
|
1223
1422
|
);
|
|
1224
1423
|
}
|
|
1225
1424
|
|
|
1226
|
-
return this.
|
|
1425
|
+
return this.getTotalPerpPositionValue().sub(currentPerpPositionValueUSDC);
|
|
1227
1426
|
}
|
|
1228
1427
|
|
|
1229
1428
|
private getOracleDataForMarket(marketIndex: BN): OraclePriceData {
|