@drift-labs/sdk 2.149.0-beta.0 → 2.149.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION +1 -1
- package/lib/browser/marginCalculation.d.ts +79 -0
- package/lib/browser/marginCalculation.js +196 -0
- package/lib/browser/math/margin.d.ts +1 -1
- package/lib/browser/math/margin.js +8 -2
- package/lib/browser/math/spotPosition.d.ts +1 -1
- package/lib/browser/math/spotPosition.js +3 -2
- package/lib/browser/types.d.ts +10 -0
- package/lib/browser/types.js +7 -1
- package/lib/browser/user.d.ts +56 -16
- package/lib/browser/user.js +414 -46
- package/lib/node/marginCalculation.d.ts +80 -0
- package/lib/node/marginCalculation.d.ts.map +1 -0
- package/lib/node/marginCalculation.js +196 -0
- package/lib/node/math/margin.d.ts +1 -1
- package/lib/node/math/margin.d.ts.map +1 -1
- package/lib/node/math/margin.js +8 -2
- package/lib/node/math/spotPosition.d.ts +1 -1
- package/lib/node/math/spotPosition.d.ts.map +1 -1
- package/lib/node/math/spotPosition.js +3 -2
- package/lib/node/types.d.ts +10 -0
- package/lib/node/types.d.ts.map +1 -1
- package/lib/node/types.js +7 -1
- package/lib/node/user.d.ts +56 -16
- package/lib/node/user.d.ts.map +1 -1
- package/lib/node/user.js +414 -46
- package/package.json +2 -1
- package/src/marginCalculation.ts +287 -0
- package/src/math/margin.ts +15 -2
- package/src/math/spotPosition.ts +6 -2
- package/src/types.ts +12 -0
- package/src/user.ts +737 -87
- package/tests/dlob/helpers.ts +19 -0
- package/tests/user/getMarginCalculation.ts +361 -0
- package/tests/user/helpers.ts +96 -2
- package/tests/user/liquidations.ts +129 -0
package/lib/browser/user.js
CHANGED
|
@@ -26,6 +26,7 @@ const tiers_1 = require("./math/tiers");
|
|
|
26
26
|
const strictOraclePrice_1 = require("./oracles/strictOraclePrice");
|
|
27
27
|
const fuel_1 = require("./math/fuel");
|
|
28
28
|
const grpcUserAccountSubscriber_1 = require("./accounts/grpcUserAccountSubscriber");
|
|
29
|
+
const marginCalculation_1 = require("./marginCalculation");
|
|
29
30
|
class User {
|
|
30
31
|
get isSubscribed() {
|
|
31
32
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -190,6 +191,19 @@ class User {
|
|
|
190
191
|
positionFlag: 0,
|
|
191
192
|
};
|
|
192
193
|
}
|
|
194
|
+
getIsolatePerpPositionTokenAmount(perpMarketIndex) {
|
|
195
|
+
var _a;
|
|
196
|
+
const perpPosition = this.getPerpPosition(perpMarketIndex);
|
|
197
|
+
if (!perpPosition)
|
|
198
|
+
return numericConstants_1.ZERO;
|
|
199
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(perpMarketIndex);
|
|
200
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(perpMarket.quoteSpotMarketIndex);
|
|
201
|
+
if (perpPosition === undefined) {
|
|
202
|
+
return numericConstants_1.ZERO;
|
|
203
|
+
}
|
|
204
|
+
return (0, spotBalance_2.getTokenAmount)((_a = perpPosition.isolatedPositionScaledBalance) !== null && _a !== void 0 ? _a : numericConstants_1.ZERO, //TODO remove ? later
|
|
205
|
+
spotMarket, types_2.SpotBalanceType.DEPOSIT);
|
|
206
|
+
}
|
|
193
207
|
getClonedPosition(position) {
|
|
194
208
|
const clonedPosition = Object.assign({}, position);
|
|
195
209
|
return clonedPosition;
|
|
@@ -288,36 +302,73 @@ class User {
|
|
|
288
302
|
* calculates Free Collateral = Total collateral - margin requirement
|
|
289
303
|
* @returns : Precision QUOTE_PRECISION
|
|
290
304
|
*/
|
|
291
|
-
getFreeCollateral(marginCategory = 'Initial', enterHighLeverageMode =
|
|
292
|
-
const totalCollateral = this.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
305
|
+
getFreeCollateral(marginCategory = 'Initial', enterHighLeverageMode = false, perpMarketIndex) {
|
|
306
|
+
const { totalCollateral, marginRequirement, getIsolatedFreeCollateral } = this.getMarginCalculation(marginCategory, {
|
|
307
|
+
enteringHighLeverage: enterHighLeverageMode,
|
|
308
|
+
strict: marginCategory === 'Initial',
|
|
309
|
+
});
|
|
310
|
+
if (perpMarketIndex !== undefined) {
|
|
311
|
+
return getIsolatedFreeCollateral(perpMarketIndex);
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
const freeCollateral = totalCollateral.sub(marginRequirement);
|
|
315
|
+
return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
|
|
316
|
+
}
|
|
298
317
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
318
|
+
getMarginRequirement(marginCategory, liquidationBuffer, strict, includeOpenOrders, enteringHighLeverage, perpMarketIndex) {
|
|
319
|
+
const liquidationBufferMap = new Map();
|
|
320
|
+
if (liquidationBuffer && perpMarketIndex !== undefined) {
|
|
321
|
+
liquidationBufferMap.set(perpMarketIndex, liquidationBuffer);
|
|
322
|
+
}
|
|
323
|
+
else if (liquidationBuffer) {
|
|
324
|
+
liquidationBufferMap.set('cross', liquidationBuffer);
|
|
325
|
+
}
|
|
326
|
+
const marginCalc = this.getMarginCalculation(marginCategory, {
|
|
327
|
+
strict,
|
|
328
|
+
includeOpenOrders,
|
|
329
|
+
enteringHighLeverage,
|
|
330
|
+
liquidationBufferMap,
|
|
331
|
+
});
|
|
332
|
+
// If perpMarketIndex is provided, compute only for that market index
|
|
333
|
+
if (perpMarketIndex !== undefined) {
|
|
334
|
+
const isolatedMarginCalculation = marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
|
|
335
|
+
if (!isolatedMarginCalculation)
|
|
336
|
+
return numericConstants_1.ZERO;
|
|
337
|
+
const { marginRequirement, marginRequirementPlusBuffer } = isolatedMarginCalculation;
|
|
338
|
+
if (liquidationBuffer === null || liquidationBuffer === void 0 ? void 0 : liquidationBuffer.gt(numericConstants_1.ZERO)) {
|
|
339
|
+
return marginRequirementPlusBuffer;
|
|
340
|
+
}
|
|
341
|
+
return marginRequirement;
|
|
342
|
+
}
|
|
343
|
+
// Default: Cross margin requirement
|
|
344
|
+
if (liquidationBuffer === null || liquidationBuffer === void 0 ? void 0 : liquidationBuffer.gt(numericConstants_1.ZERO)) {
|
|
345
|
+
return marginCalc.marginRequirementPlusBuffer;
|
|
346
|
+
}
|
|
347
|
+
return marginCalc.marginRequirement;
|
|
304
348
|
}
|
|
305
349
|
/**
|
|
306
350
|
* @returns The initial margin requirement in USDC. : QUOTE_PRECISION
|
|
307
351
|
*/
|
|
308
|
-
getInitialMarginRequirement(enterHighLeverageMode =
|
|
309
|
-
return this.getMarginRequirement('Initial', undefined, true, undefined, enterHighLeverageMode);
|
|
352
|
+
getInitialMarginRequirement(enterHighLeverageMode = false, perpMarketIndex) {
|
|
353
|
+
return this.getMarginRequirement('Initial', undefined, true, undefined, enterHighLeverageMode, perpMarketIndex);
|
|
310
354
|
}
|
|
311
355
|
/**
|
|
312
356
|
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
|
|
313
357
|
*/
|
|
314
|
-
getMaintenanceMarginRequirement(liquidationBuffer) {
|
|
315
|
-
return this.getMarginRequirement('Maintenance', liquidationBuffer
|
|
358
|
+
getMaintenanceMarginRequirement(liquidationBuffer, perpMarketIndex) {
|
|
359
|
+
return this.getMarginRequirement('Maintenance', liquidationBuffer, false, // strict default
|
|
360
|
+
true, // includeOpenOrders default
|
|
361
|
+
false, // enteringHighLeverage default
|
|
362
|
+
perpMarketIndex);
|
|
316
363
|
}
|
|
317
364
|
getActivePerpPositionsForUserAccount(userAccount) {
|
|
318
|
-
return userAccount.perpPositions.filter((pos) =>
|
|
319
|
-
|
|
320
|
-
!
|
|
365
|
+
return userAccount.perpPositions.filter((pos) => {
|
|
366
|
+
var _a;
|
|
367
|
+
return !pos.baseAssetAmount.eq(numericConstants_1.ZERO) ||
|
|
368
|
+
!pos.quoteAssetAmount.eq(numericConstants_1.ZERO) ||
|
|
369
|
+
!(pos.openOrders == 0) ||
|
|
370
|
+
((_a = pos.isolatedPositionScaledBalance) === null || _a === void 0 ? void 0 : _a.gt(numericConstants_1.ZERO));
|
|
371
|
+
});
|
|
321
372
|
}
|
|
322
373
|
getActivePerpPositions() {
|
|
323
374
|
const userAccount = this.getUserAccount();
|
|
@@ -555,27 +606,72 @@ class User {
|
|
|
555
606
|
* calculates TotalCollateral: collateral + unrealized pnl
|
|
556
607
|
* @returns : Precision QUOTE_PRECISION
|
|
557
608
|
*/
|
|
558
|
-
getTotalCollateral(marginCategory = 'Initial', strict = false, includeOpenOrders = true, liquidationBuffer) {
|
|
559
|
-
|
|
609
|
+
getTotalCollateral(marginCategory = 'Initial', strict = false, includeOpenOrders = true, liquidationBuffer, perpMarketIndex) {
|
|
610
|
+
const liquidationBufferMap = (() => {
|
|
611
|
+
if (liquidationBuffer && perpMarketIndex !== undefined) {
|
|
612
|
+
return new Map([[perpMarketIndex, liquidationBuffer]]);
|
|
613
|
+
}
|
|
614
|
+
else if (liquidationBuffer) {
|
|
615
|
+
return new Map([['cross', liquidationBuffer]]);
|
|
616
|
+
}
|
|
617
|
+
return new Map();
|
|
618
|
+
})();
|
|
619
|
+
const marginCalc = this.getMarginCalculation(marginCategory, {
|
|
620
|
+
strict,
|
|
621
|
+
includeOpenOrders,
|
|
622
|
+
liquidationBufferMap,
|
|
623
|
+
});
|
|
624
|
+
if (perpMarketIndex !== undefined) {
|
|
625
|
+
const { totalCollateral, totalCollateralBuffer } = marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
|
|
626
|
+
if (liquidationBuffer === null || liquidationBuffer === void 0 ? void 0 : liquidationBuffer.gt(numericConstants_1.ZERO)) {
|
|
627
|
+
return totalCollateralBuffer;
|
|
628
|
+
}
|
|
629
|
+
return totalCollateral;
|
|
630
|
+
}
|
|
631
|
+
if (liquidationBuffer === null || liquidationBuffer === void 0 ? void 0 : liquidationBuffer.gt(numericConstants_1.ZERO)) {
|
|
632
|
+
return marginCalc.totalCollateralBuffer;
|
|
633
|
+
}
|
|
634
|
+
return marginCalc.totalCollateral;
|
|
560
635
|
}
|
|
561
636
|
getLiquidationBuffer() {
|
|
562
|
-
|
|
563
|
-
let liquidationBuffer = undefined;
|
|
637
|
+
const liquidationBufferMap = new Map();
|
|
564
638
|
if (this.isBeingLiquidated()) {
|
|
565
|
-
|
|
639
|
+
liquidationBufferMap.set('cross', new anchor_1.BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio));
|
|
566
640
|
}
|
|
567
|
-
|
|
641
|
+
for (const position of this.getActivePerpPositions()) {
|
|
642
|
+
if (position.positionFlag &
|
|
643
|
+
(types_2.PositionFlag.BeingLiquidated | types_2.PositionFlag.Bankruptcy)) {
|
|
644
|
+
liquidationBufferMap.set(position.marketIndex, new anchor_1.BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio));
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return liquidationBufferMap;
|
|
568
648
|
}
|
|
569
649
|
/**
|
|
570
650
|
* calculates User Health by comparing total collateral and maint. margin requirement
|
|
571
651
|
* @returns : number (value from [0, 100])
|
|
572
652
|
*/
|
|
573
|
-
getHealth() {
|
|
574
|
-
if (this.
|
|
653
|
+
getHealth(perpMarketIndex) {
|
|
654
|
+
if (this.isCrossMarginBeingLiquidated() && !perpMarketIndex) {
|
|
575
655
|
return 0;
|
|
576
656
|
}
|
|
577
|
-
|
|
578
|
-
|
|
657
|
+
if (perpMarketIndex &&
|
|
658
|
+
this.isIsolatedPositionBeingLiquidated(perpMarketIndex)) {
|
|
659
|
+
return 0;
|
|
660
|
+
}
|
|
661
|
+
const marginCalc = this.getMarginCalculation('Maintenance');
|
|
662
|
+
let totalCollateral;
|
|
663
|
+
let maintenanceMarginReq;
|
|
664
|
+
if (perpMarketIndex) {
|
|
665
|
+
const isolatedMarginCalc = marginCalc.isolatedMarginCalculations.get(perpMarketIndex);
|
|
666
|
+
if (isolatedMarginCalc) {
|
|
667
|
+
totalCollateral = isolatedMarginCalc.totalCollateral;
|
|
668
|
+
maintenanceMarginReq = isolatedMarginCalc.marginRequirement;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
totalCollateral = marginCalc.totalCollateral;
|
|
673
|
+
maintenanceMarginReq = marginCalc.marginRequirement;
|
|
674
|
+
}
|
|
579
675
|
let health;
|
|
580
676
|
if (maintenanceMarginReq.eq(numericConstants_1.ZERO) && totalCollateral.gte(numericConstants_1.ZERO)) {
|
|
581
677
|
health = 100;
|
|
@@ -734,8 +830,8 @@ class User {
|
|
|
734
830
|
* calculates current user leverage which is (total liability size) / (net asset value)
|
|
735
831
|
* @returns : Precision TEN_THOUSAND
|
|
736
832
|
*/
|
|
737
|
-
getLeverage(includeOpenOrders = true) {
|
|
738
|
-
return this.calculateLeverageFromComponents(this.getLeverageComponents(includeOpenOrders));
|
|
833
|
+
getLeverage(includeOpenOrders = true, perpMarketIndex) {
|
|
834
|
+
return this.calculateLeverageFromComponents(this.getLeverageComponents(includeOpenOrders, undefined, perpMarketIndex));
|
|
739
835
|
}
|
|
740
836
|
calculateLeverageFromComponents({ perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue, }) {
|
|
741
837
|
const totalLiabilityValue = perpLiabilityValue.add(spotLiabilityValue);
|
|
@@ -746,7 +842,26 @@ class User {
|
|
|
746
842
|
}
|
|
747
843
|
return totalLiabilityValue.mul(numericConstants_1.TEN_THOUSAND).div(netAssetValue);
|
|
748
844
|
}
|
|
749
|
-
getLeverageComponents(includeOpenOrders = true, marginCategory = undefined) {
|
|
845
|
+
getLeverageComponents(includeOpenOrders = true, marginCategory = undefined, perpMarketIndex) {
|
|
846
|
+
var _a;
|
|
847
|
+
if (perpMarketIndex) {
|
|
848
|
+
const perpPosition = this.getPerpPositionOrEmpty(perpMarketIndex);
|
|
849
|
+
const perpLiability = this.calculateWeightedPerpPositionLiability(perpPosition, marginCategory, undefined, includeOpenOrders);
|
|
850
|
+
const perpMarket = this.driftClient.getPerpMarketAccount(perpPosition.marketIndex);
|
|
851
|
+
const oraclePriceData = this.getOracleDataForPerpMarket(perpPosition.marketIndex);
|
|
852
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(perpMarket.quoteSpotMarketIndex);
|
|
853
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(perpMarket.quoteSpotMarketIndex);
|
|
854
|
+
const strictOracle = new strictOraclePrice_1.StrictOraclePrice(quoteOraclePriceData.price, quoteOraclePriceData.twap);
|
|
855
|
+
const positionUnrealizedPnl = (0, position_2.calculatePositionPNL)(perpMarket, perpPosition, true, oraclePriceData);
|
|
856
|
+
const tokenAmount = (0, spotBalance_2.getTokenAmount)((_a = perpPosition.isolatedPositionScaledBalance) !== null && _a !== void 0 ? _a : numericConstants_1.ZERO, quoteSpotMarket, types_2.SpotBalanceType.DEPOSIT);
|
|
857
|
+
const spotAssetValue = (0, spotBalance_1.getStrictTokenValue)(tokenAmount, quoteSpotMarket.decimals, strictOracle);
|
|
858
|
+
return {
|
|
859
|
+
perpLiabilityValue: perpLiability,
|
|
860
|
+
perpPnl: positionUnrealizedPnl,
|
|
861
|
+
spotAssetValue,
|
|
862
|
+
spotLiabilityValue: numericConstants_1.ZERO,
|
|
863
|
+
};
|
|
864
|
+
}
|
|
750
865
|
const perpLiability = this.getTotalPerpPositionLiability(marginCategory, undefined, includeOpenOrders);
|
|
751
866
|
const perpPnl = this.getUnrealizedPNL(true, undefined, marginCategory);
|
|
752
867
|
const { totalAssetValue: spotAssetValue, totalLiabilityValue: spotLiabilityValue, } = this.getSpotMarketAssetAndLiabilityValue(undefined, marginCategory, undefined, includeOpenOrders);
|
|
@@ -895,21 +1010,96 @@ class User {
|
|
|
895
1010
|
return netAssetValue.mul(numericConstants_1.TEN_THOUSAND).div(totalLiabilityValue);
|
|
896
1011
|
}
|
|
897
1012
|
canBeLiquidated() {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1013
|
+
// Deprecated signature retained for backward compatibility in type only
|
|
1014
|
+
// but implementation now delegates to the new Map-based API and returns cross margin status.
|
|
1015
|
+
const map = this.getLiquidationStatuses();
|
|
1016
|
+
const cross = map.get('cross');
|
|
1017
|
+
const isolatedPositions = new Map(Array.from(map.entries())
|
|
1018
|
+
.filter((e) => e[0] !== 'cross')
|
|
1019
|
+
.map(([key, value]) => [key, value]));
|
|
1020
|
+
return cross
|
|
1021
|
+
? { ...cross, isolatedPositions }
|
|
1022
|
+
: {
|
|
1023
|
+
canBeLiquidated: false,
|
|
1024
|
+
marginRequirement: numericConstants_1.ZERO,
|
|
1025
|
+
totalCollateral: numericConstants_1.ZERO,
|
|
1026
|
+
isolatedPositions,
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* New API: Returns liquidation status for cross and each isolated perp position.
|
|
1031
|
+
* Map keys:
|
|
1032
|
+
* - 'cross' for cross margin
|
|
1033
|
+
* - marketIndex (number) for each isolated perp position
|
|
1034
|
+
*/
|
|
1035
|
+
getLiquidationStatuses(marginCalc) {
|
|
1036
|
+
// If not provided, use buffer-aware calc for canBeLiquidated checks
|
|
1037
|
+
if (!marginCalc) {
|
|
1038
|
+
const liquidationBufferMap = this.getLiquidationBuffer();
|
|
1039
|
+
marginCalc = this.getMarginCalculation('Maintenance', {
|
|
1040
|
+
liquidationBufferMap,
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
const result = new Map();
|
|
1044
|
+
// Cross margin status
|
|
1045
|
+
const crossTotalCollateral = marginCalc.totalCollateral;
|
|
1046
|
+
const crossMarginRequirement = marginCalc.marginRequirement;
|
|
1047
|
+
result.set('cross', {
|
|
1048
|
+
canBeLiquidated: crossTotalCollateral.lt(crossMarginRequirement),
|
|
1049
|
+
marginRequirement: crossMarginRequirement,
|
|
1050
|
+
totalCollateral: crossTotalCollateral,
|
|
1051
|
+
});
|
|
1052
|
+
// Isolated positions status
|
|
1053
|
+
for (const [marketIndex, isoCalc,] of marginCalc.isolatedMarginCalculations) {
|
|
1054
|
+
const isoTotalCollateral = isoCalc.totalCollateral;
|
|
1055
|
+
const isoMarginRequirement = isoCalc.marginRequirement;
|
|
1056
|
+
result.set(marketIndex, {
|
|
1057
|
+
canBeLiquidated: isoTotalCollateral.lt(isoMarginRequirement),
|
|
1058
|
+
marginRequirement: isoMarginRequirement,
|
|
1059
|
+
totalCollateral: isoTotalCollateral,
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
return result;
|
|
907
1063
|
}
|
|
908
1064
|
isBeingLiquidated() {
|
|
1065
|
+
return (this.isCrossMarginBeingLiquidated() ||
|
|
1066
|
+
this.hasIsolatedPositionBeingLiquidated());
|
|
1067
|
+
}
|
|
1068
|
+
isCrossMarginBeingLiquidated() {
|
|
909
1069
|
return ((this.getUserAccount().status &
|
|
910
1070
|
(types_1.UserStatus.BEING_LIQUIDATED | types_1.UserStatus.BANKRUPT)) >
|
|
911
1071
|
0);
|
|
912
1072
|
}
|
|
1073
|
+
/** Returns true if cross margin is currently below maintenance requirement (no buffer). */
|
|
1074
|
+
canCrossMarginBeLiquidated(marginCalc) {
|
|
1075
|
+
const calc = marginCalc !== null && marginCalc !== void 0 ? marginCalc : this.getMarginCalculation('Maintenance');
|
|
1076
|
+
return calc.totalCollateral.lt(calc.marginRequirement);
|
|
1077
|
+
}
|
|
1078
|
+
hasIsolatedPositionBeingLiquidated() {
|
|
1079
|
+
return this.getActivePerpPositions().some((position) => (position.positionFlag &
|
|
1080
|
+
(types_2.PositionFlag.BeingLiquidated | types_2.PositionFlag.Bankruptcy)) >
|
|
1081
|
+
0);
|
|
1082
|
+
}
|
|
1083
|
+
isIsolatedPositionBeingLiquidated(perpMarketIndex) {
|
|
1084
|
+
const position = this.getActivePerpPositions().find((position) => position.marketIndex === perpMarketIndex);
|
|
1085
|
+
return (((position === null || position === void 0 ? void 0 : position.positionFlag) &
|
|
1086
|
+
(types_2.PositionFlag.BeingLiquidated | types_2.PositionFlag.Bankruptcy)) >
|
|
1087
|
+
0);
|
|
1088
|
+
}
|
|
1089
|
+
/** Returns true if any isolated perp position is currently below its maintenance requirement (no buffer). */
|
|
1090
|
+
getLiquidatableIsolatedPositions(marginCalc) {
|
|
1091
|
+
const liquidatableIsolatedPositions = [];
|
|
1092
|
+
const calc = marginCalc !== null && marginCalc !== void 0 ? marginCalc : this.getMarginCalculation('Maintenance');
|
|
1093
|
+
for (const [marketIndex, isoCalc] of calc.isolatedMarginCalculations) {
|
|
1094
|
+
if (this.canIsolatedPositionMarginBeLiquidated(isoCalc)) {
|
|
1095
|
+
liquidatableIsolatedPositions.push(marketIndex);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
return liquidatableIsolatedPositions;
|
|
1099
|
+
}
|
|
1100
|
+
canIsolatedPositionMarginBeLiquidated(isolatedMarginCalculation) {
|
|
1101
|
+
return isolatedMarginCalculation.totalCollateral.lt(isolatedMarginCalculation.marginRequirement);
|
|
1102
|
+
}
|
|
913
1103
|
hasStatus(status) {
|
|
914
1104
|
return (this.getUserAccount().status & status) > 0;
|
|
915
1105
|
}
|
|
@@ -999,14 +1189,38 @@ class User {
|
|
|
999
1189
|
* @param offsetCollateral // allows calculating the liquidation price after this offset collateral is added to the user's account (e.g. : what will the liquidation price be for this position AFTER I deposit $x worth of collateral)
|
|
1000
1190
|
* @returns Precision : PRICE_PRECISION
|
|
1001
1191
|
*/
|
|
1002
|
-
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO, marginCategory = 'Maintenance', includeOpenOrders = false, offsetCollateral = numericConstants_1.ZERO, enteringHighLeverage =
|
|
1003
|
-
const
|
|
1004
|
-
const marginRequirement = this.getMarginRequirement(marginCategory, undefined, false, includeOpenOrders, enteringHighLeverage);
|
|
1005
|
-
let freeCollateral = anchor_1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(marginRequirement)).add(offsetCollateral);
|
|
1192
|
+
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO, marginCategory = 'Maintenance', includeOpenOrders = false, offsetCollateral = numericConstants_1.ZERO, enteringHighLeverage = false, marginType) {
|
|
1193
|
+
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1006
1194
|
const oracle = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1007
1195
|
const oraclePrice = this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1008
|
-
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1009
1196
|
const currentPerpPosition = this.getPerpPositionOrEmpty(marketIndex);
|
|
1197
|
+
if (marginType === 'Isolated') {
|
|
1198
|
+
const marginCalculation = this.getMarginCalculation(marginCategory, {
|
|
1199
|
+
strict: false,
|
|
1200
|
+
includeOpenOrders,
|
|
1201
|
+
enteringHighLeverage,
|
|
1202
|
+
});
|
|
1203
|
+
const isolatedMarginCalculation = marginCalculation.isolatedMarginCalculations.get(marketIndex);
|
|
1204
|
+
if (!isolatedMarginCalculation)
|
|
1205
|
+
return new anchor_1.BN(-1);
|
|
1206
|
+
const { totalCollateral, marginRequirement } = isolatedMarginCalculation;
|
|
1207
|
+
const freeCollateral = anchor_1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(marginRequirement)).add(offsetCollateral);
|
|
1208
|
+
const freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(market, currentPerpPosition, positionBaseSizeChange, oraclePrice, marginCategory, includeOpenOrders, enteringHighLeverage);
|
|
1209
|
+
if (freeCollateralDelta.eq(numericConstants_1.ZERO)) {
|
|
1210
|
+
return new anchor_1.BN(-1);
|
|
1211
|
+
}
|
|
1212
|
+
const liqPriceDelta = freeCollateral
|
|
1213
|
+
.mul(numericConstants_1.QUOTE_PRECISION)
|
|
1214
|
+
.div(freeCollateralDelta);
|
|
1215
|
+
const liqPrice = oraclePrice.sub(liqPriceDelta);
|
|
1216
|
+
if (liqPrice.lt(numericConstants_1.ZERO)) {
|
|
1217
|
+
return new anchor_1.BN(-1);
|
|
1218
|
+
}
|
|
1219
|
+
return liqPrice;
|
|
1220
|
+
}
|
|
1221
|
+
const totalCollateral = this.getTotalCollateral(marginCategory, false, includeOpenOrders);
|
|
1222
|
+
const marginRequirement = this.getMarginRequirement(marginCategory, undefined, false, includeOpenOrders, enteringHighLeverage);
|
|
1223
|
+
let freeCollateral = anchor_1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(marginRequirement)).add(offsetCollateral);
|
|
1010
1224
|
positionBaseSizeChange = (0, orders_1.standardizeBaseAssetAmount)(positionBaseSizeChange, market.amm.orderStepSize);
|
|
1011
1225
|
const freeCollateralChangeFromNewPosition = this.calculateEntriesEffectOnFreeCollateral(market, oraclePrice, currentPerpPosition, positionBaseSizeChange, estimatedEntryPrice, includeOpenOrders, enteringHighLeverage);
|
|
1012
1226
|
freeCollateral = freeCollateral.add(freeCollateralChangeFromNewPosition);
|
|
@@ -2004,5 +2218,159 @@ class User {
|
|
|
2004
2218
|
activeSpotPositions: activeSpotMarkets,
|
|
2005
2219
|
};
|
|
2006
2220
|
}
|
|
2221
|
+
/**
|
|
2222
|
+
* Compute a consolidated margin snapshot once, without caching.
|
|
2223
|
+
* Consumers can use this to avoid duplicating work across separate calls.
|
|
2224
|
+
*/
|
|
2225
|
+
getMarginCalculation(marginCategory = 'Initial', opts) {
|
|
2226
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2227
|
+
const strict = (_a = opts === null || opts === void 0 ? void 0 : opts.strict) !== null && _a !== void 0 ? _a : false;
|
|
2228
|
+
const enteringHighLeverage = (_b = opts === null || opts === void 0 ? void 0 : opts.enteringHighLeverage) !== null && _b !== void 0 ? _b : false;
|
|
2229
|
+
const liquidationBufferMap = (_c = opts === null || opts === void 0 ? void 0 : opts.liquidationBufferMap) !== null && _c !== void 0 ? _c : new Map();
|
|
2230
|
+
const includeOpenOrders = (_d = opts === null || opts === void 0 ? void 0 : opts.includeOpenOrders) !== null && _d !== void 0 ? _d : true;
|
|
2231
|
+
// Equivalent to on-chain user_custom_margin_ratio
|
|
2232
|
+
const userCustomMarginRatio = marginCategory === 'Initial' ? this.getUserAccount().maxMarginRatio : 0;
|
|
2233
|
+
// Initialize calc via JS mirror of Rust/on-chain MarginCalculation
|
|
2234
|
+
const isolatedMarginBuffers = new Map();
|
|
2235
|
+
for (const [marketIndex, isolatedMarginBuffer,] of (_e = opts === null || opts === void 0 ? void 0 : opts.liquidationBufferMap) !== null && _e !== void 0 ? _e : new Map()) {
|
|
2236
|
+
if (marketIndex !== 'cross') {
|
|
2237
|
+
isolatedMarginBuffers.set(marketIndex, isolatedMarginBuffer);
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
const ctx = marginCalculation_1.MarginContext.standard(marginCategory)
|
|
2241
|
+
.strictMode(strict)
|
|
2242
|
+
.setCrossMarginBuffer((_g = (_f = opts === null || opts === void 0 ? void 0 : opts.liquidationBufferMap) === null || _f === void 0 ? void 0 : _f.get('cross')) !== null && _g !== void 0 ? _g : numericConstants_1.ZERO)
|
|
2243
|
+
.setIsolatedMarginBuffers(isolatedMarginBuffers);
|
|
2244
|
+
const calc = new marginCalculation_1.MarginCalculation(ctx);
|
|
2245
|
+
// SPOT POSITIONS
|
|
2246
|
+
for (const spotPosition of this.getUserAccount().spotPositions) {
|
|
2247
|
+
if ((0, spotPosition_1.isSpotPositionAvailable)(spotPosition))
|
|
2248
|
+
continue;
|
|
2249
|
+
const isQuote = spotPosition.marketIndex === numericConstants_1.QUOTE_SPOT_MARKET_INDEX;
|
|
2250
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(spotPosition.marketIndex);
|
|
2251
|
+
const oraclePriceData = this.getOracleDataForSpotMarket(spotPosition.marketIndex);
|
|
2252
|
+
const twap5 = strict
|
|
2253
|
+
? (0, oracles_1.calculateLiveOracleTwap)(spotMarket.historicalOracleData, oraclePriceData, new anchor_1.BN(Math.floor(Date.now() / 1000)), numericConstants_1.FIVE_MINUTE)
|
|
2254
|
+
: undefined;
|
|
2255
|
+
const strictOracle = new strictOraclePrice_1.StrictOraclePrice(oraclePriceData.price, twap5);
|
|
2256
|
+
if (isQuote) {
|
|
2257
|
+
const tokenAmount = (0, spotBalance_1.getSignedTokenAmount)((0, spotBalance_2.getTokenAmount)(spotPosition.scaledBalance, spotMarket, spotPosition.balanceType), spotPosition.balanceType);
|
|
2258
|
+
if ((0, types_1.isVariant)(spotPosition.balanceType, 'deposit')) {
|
|
2259
|
+
// add deposit value to total collateral
|
|
2260
|
+
const weightedTokenValue = this.getSpotAssetValue(tokenAmount, strictOracle, spotMarket, marginCategory);
|
|
2261
|
+
calc.addCrossMarginTotalCollateral(weightedTokenValue);
|
|
2262
|
+
}
|
|
2263
|
+
else {
|
|
2264
|
+
// borrow on quote contributes to margin requirement
|
|
2265
|
+
const tokenValueAbs = this.getSpotLiabilityValue(tokenAmount, strictOracle, spotMarket, marginCategory, (_h = liquidationBufferMap.get('cross')) !== null && _h !== void 0 ? _h : new anchor_1.BN(0)).abs();
|
|
2266
|
+
calc.addCrossMarginRequirement(tokenValueAbs, tokenValueAbs);
|
|
2267
|
+
}
|
|
2268
|
+
continue;
|
|
2269
|
+
}
|
|
2270
|
+
// Non-quote spot: worst-case simulation
|
|
2271
|
+
const { tokenAmount: worstCaseTokenAmount, ordersValue: worstCaseOrdersValue, } = (0, spotPosition_1.getWorstCaseTokenAmounts)(spotPosition, spotMarket, strictOracle, marginCategory, userCustomMarginRatio, includeOpenOrders
|
|
2272
|
+
// false
|
|
2273
|
+
);
|
|
2274
|
+
if (includeOpenOrders) {
|
|
2275
|
+
// open order IM
|
|
2276
|
+
calc.addCrossMarginRequirement(new anchor_1.BN(spotPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT), numericConstants_1.ZERO);
|
|
2277
|
+
}
|
|
2278
|
+
if (worstCaseTokenAmount.gt(numericConstants_1.ZERO)) {
|
|
2279
|
+
const baseAssetValue = this.getSpotAssetValue(worstCaseTokenAmount, strictOracle, spotMarket, marginCategory);
|
|
2280
|
+
// asset side increases total collateral (weighted)
|
|
2281
|
+
calc.addCrossMarginTotalCollateral(baseAssetValue);
|
|
2282
|
+
}
|
|
2283
|
+
else if (worstCaseTokenAmount.lt(numericConstants_1.ZERO)) {
|
|
2284
|
+
// liability side increases margin requirement (weighted >= abs(token_value))
|
|
2285
|
+
const getSpotLiabilityValue = this.getSpotLiabilityValue(worstCaseTokenAmount, strictOracle, spotMarket, marginCategory, liquidationBufferMap.get('cross'));
|
|
2286
|
+
calc.addCrossMarginRequirement(getSpotLiabilityValue.abs(), getSpotLiabilityValue.abs());
|
|
2287
|
+
}
|
|
2288
|
+
// orders value contributes to collateral or requirement
|
|
2289
|
+
if (worstCaseOrdersValue.gt(numericConstants_1.ZERO)) {
|
|
2290
|
+
calc.addCrossMarginTotalCollateral(worstCaseOrdersValue);
|
|
2291
|
+
}
|
|
2292
|
+
else if (worstCaseOrdersValue.lt(numericConstants_1.ZERO)) {
|
|
2293
|
+
const absVal = worstCaseOrdersValue.abs();
|
|
2294
|
+
calc.addCrossMarginRequirement(absVal, absVal);
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
// PERP POSITIONS
|
|
2298
|
+
for (const marketPosition of this.getActivePerpPositions()) {
|
|
2299
|
+
const market = this.driftClient.getPerpMarketAccount(marketPosition.marketIndex);
|
|
2300
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
|
|
2301
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(market.quoteSpotMarketIndex);
|
|
2302
|
+
const oraclePriceData = this.getMMOracleDataForPerpMarket(market.marketIndex);
|
|
2303
|
+
const nonMmmOraclePriceData = this.getOracleDataForPerpMarket(market.marketIndex);
|
|
2304
|
+
// Worst-case perp liability and weighted pnl
|
|
2305
|
+
const { worstCaseBaseAssetAmount, worstCaseLiabilityValue } = (0, margin_1.calculateWorstCasePerpLiabilityValue)(marketPosition, market, nonMmmOraclePriceData.price, includeOpenOrders);
|
|
2306
|
+
// margin ratio for this perp
|
|
2307
|
+
const customMarginRatio = Math.max(userCustomMarginRatio, marketPosition.maxMarginRatio);
|
|
2308
|
+
let marginRatio = new anchor_1.BN((0, market_1.calculateMarketMarginRatio)(market, worstCaseBaseAssetAmount.abs(), marginCategory, customMarginRatio, this.isHighLeverageMode(marginCategory) || enteringHighLeverage));
|
|
2309
|
+
if ((0, types_1.isVariant)(market.status, 'settlement')) {
|
|
2310
|
+
marginRatio = numericConstants_1.ZERO;
|
|
2311
|
+
}
|
|
2312
|
+
// convert liability to quote value and apply margin ratio
|
|
2313
|
+
const quotePrice = strict
|
|
2314
|
+
? anchor_1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min)
|
|
2315
|
+
: quoteOraclePriceData.price;
|
|
2316
|
+
let perpMarginRequirement = worstCaseLiabilityValue
|
|
2317
|
+
.mul(quotePrice)
|
|
2318
|
+
.div(numericConstants_1.PRICE_PRECISION)
|
|
2319
|
+
.mul(marginRatio)
|
|
2320
|
+
.div(numericConstants_1.MARGIN_PRECISION);
|
|
2321
|
+
// add open orders IM
|
|
2322
|
+
if (includeOpenOrders) {
|
|
2323
|
+
perpMarginRequirement = perpMarginRequirement.add(new anchor_1.BN(marketPosition.openOrders).mul(numericConstants_1.OPEN_ORDER_MARGIN_REQUIREMENT));
|
|
2324
|
+
}
|
|
2325
|
+
// weighted unrealized pnl
|
|
2326
|
+
let positionUnrealizedPnl = (0, position_2.calculatePositionPNL)(market, marketPosition, true, oraclePriceData);
|
|
2327
|
+
let pnlQuotePrice;
|
|
2328
|
+
if (strict && positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
|
|
2329
|
+
pnlQuotePrice = anchor_1.BN.min(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
|
|
2330
|
+
}
|
|
2331
|
+
else if (strict && positionUnrealizedPnl.lt(numericConstants_1.ZERO)) {
|
|
2332
|
+
pnlQuotePrice = anchor_1.BN.max(quoteOraclePriceData.price, quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min);
|
|
2333
|
+
}
|
|
2334
|
+
else {
|
|
2335
|
+
pnlQuotePrice = quoteOraclePriceData.price;
|
|
2336
|
+
}
|
|
2337
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
2338
|
+
.mul(pnlQuotePrice)
|
|
2339
|
+
.div(numericConstants_1.PRICE_PRECISION);
|
|
2340
|
+
if (marginCategory !== undefined) {
|
|
2341
|
+
if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
|
|
2342
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
2343
|
+
.mul((0, market_1.calculateUnrealizedAssetWeight)(market, quoteSpotMarket, positionUnrealizedPnl, marginCategory, oraclePriceData))
|
|
2344
|
+
.div(new anchor_1.BN(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION));
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
// Add perp contribution: isolated vs cross
|
|
2348
|
+
const isIsolated = this.isPerpPositionIsolated(marketPosition);
|
|
2349
|
+
if (isIsolated) {
|
|
2350
|
+
// derive isolated quote deposit value, mirroring on-chain logic
|
|
2351
|
+
let depositValue = numericConstants_1.ZERO;
|
|
2352
|
+
if ((_j = marketPosition.isolatedPositionScaledBalance) === null || _j === void 0 ? void 0 : _j.gt(numericConstants_1.ZERO)) {
|
|
2353
|
+
const quoteSpotMarket = this.driftClient.getSpotMarketAccount(market.quoteSpotMarketIndex);
|
|
2354
|
+
const quoteOraclePriceData = this.getOracleDataForSpotMarket(market.quoteSpotMarketIndex);
|
|
2355
|
+
const strictQuote = new strictOraclePrice_1.StrictOraclePrice(quoteOraclePriceData.price, strict
|
|
2356
|
+
? quoteSpotMarket.historicalOracleData.lastOraclePriceTwap5Min
|
|
2357
|
+
: undefined);
|
|
2358
|
+
const quoteTokenAmount = (0, spotBalance_2.getTokenAmount)((_k = marketPosition.isolatedPositionScaledBalance) !== null && _k !== void 0 ? _k : numericConstants_1.ZERO, quoteSpotMarket, types_2.SpotBalanceType.DEPOSIT);
|
|
2359
|
+
depositValue = (0, spotBalance_1.getStrictTokenValue)(quoteTokenAmount, quoteSpotMarket.decimals, strictQuote);
|
|
2360
|
+
}
|
|
2361
|
+
calc.addIsolatedMarginCalculation(market.marketIndex, depositValue, positionUnrealizedPnl, worstCaseLiabilityValue, perpMarginRequirement);
|
|
2362
|
+
calc.addPerpLiabilityValue(worstCaseLiabilityValue);
|
|
2363
|
+
}
|
|
2364
|
+
else {
|
|
2365
|
+
// cross: add to global requirement and collateral
|
|
2366
|
+
calc.addCrossMarginRequirement(perpMarginRequirement, worstCaseLiabilityValue);
|
|
2367
|
+
calc.addCrossMarginTotalCollateral(positionUnrealizedPnl);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
return calc;
|
|
2371
|
+
}
|
|
2372
|
+
isPerpPositionIsolated(perpPosition) {
|
|
2373
|
+
return (perpPosition.positionFlag & types_2.PositionFlag.IsolatedPosition) !== 0;
|
|
2374
|
+
}
|
|
2007
2375
|
}
|
|
2008
2376
|
exports.User = User;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/// <reference types="bn.js" />
|
|
2
|
+
import { BN } from '@coral-xyz/anchor';
|
|
3
|
+
import { MarketType } from './types';
|
|
4
|
+
export type MarginCategory = 'Initial' | 'Maintenance' | 'Fill';
|
|
5
|
+
export type MarginCalculationMode = {
|
|
6
|
+
type: 'Standard';
|
|
7
|
+
} | {
|
|
8
|
+
type: 'Liquidation';
|
|
9
|
+
};
|
|
10
|
+
export declare class MarketIdentifier {
|
|
11
|
+
marketType: MarketType;
|
|
12
|
+
marketIndex: number;
|
|
13
|
+
private constructor();
|
|
14
|
+
static spot(marketIndex: number): MarketIdentifier;
|
|
15
|
+
static perp(marketIndex: number): MarketIdentifier;
|
|
16
|
+
equals(other: MarketIdentifier | undefined): boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class MarginContext {
|
|
19
|
+
marginType: MarginCategory;
|
|
20
|
+
mode: MarginCalculationMode;
|
|
21
|
+
strict: boolean;
|
|
22
|
+
ignoreInvalidDepositOracles: boolean;
|
|
23
|
+
isolatedMarginBuffers: Map<number, BN>;
|
|
24
|
+
crossMarginBuffer: BN;
|
|
25
|
+
private constructor();
|
|
26
|
+
static standard(marginType: MarginCategory): MarginContext;
|
|
27
|
+
static liquidation(crossMarginBuffer: BN, isolatedMarginBuffers: Map<number, BN>): MarginContext;
|
|
28
|
+
strictMode(strict: boolean): this;
|
|
29
|
+
ignoreInvalidDeposits(ignore: boolean): this;
|
|
30
|
+
setCrossMarginBuffer(crossMarginBuffer: BN): this;
|
|
31
|
+
setIsolatedMarginBuffers(isolatedMarginBuffers: Map<number, BN>): this;
|
|
32
|
+
setIsolatedMarginBuffer(marketIndex: number, isolatedMarginBuffer: BN): this;
|
|
33
|
+
}
|
|
34
|
+
export declare class IsolatedMarginCalculation {
|
|
35
|
+
marginRequirement: BN;
|
|
36
|
+
totalCollateral: BN;
|
|
37
|
+
totalCollateralBuffer: BN;
|
|
38
|
+
marginRequirementPlusBuffer: BN;
|
|
39
|
+
constructor();
|
|
40
|
+
getTotalCollateralPlusBuffer(): BN;
|
|
41
|
+
meetsMarginRequirement(): boolean;
|
|
42
|
+
meetsMarginRequirementWithBuffer(): boolean;
|
|
43
|
+
marginShortage(): BN;
|
|
44
|
+
}
|
|
45
|
+
export declare class MarginCalculation {
|
|
46
|
+
context: MarginContext;
|
|
47
|
+
totalCollateral: BN;
|
|
48
|
+
totalCollateralBuffer: BN;
|
|
49
|
+
marginRequirement: BN;
|
|
50
|
+
marginRequirementPlusBuffer: BN;
|
|
51
|
+
isolatedMarginCalculations: Map<number, IsolatedMarginCalculation>;
|
|
52
|
+
allDepositOraclesValid: boolean;
|
|
53
|
+
allLiabilityOraclesValid: boolean;
|
|
54
|
+
withPerpIsolatedLiability: boolean;
|
|
55
|
+
withSpotIsolatedLiability: boolean;
|
|
56
|
+
totalPerpLiabilityValue: BN;
|
|
57
|
+
trackedMarketMarginRequirement: BN;
|
|
58
|
+
fuelDeposits: number;
|
|
59
|
+
fuelBorrows: number;
|
|
60
|
+
fuelPositions: number;
|
|
61
|
+
constructor(context: MarginContext);
|
|
62
|
+
addCrossMarginTotalCollateral(delta: BN): void;
|
|
63
|
+
addCrossMarginRequirement(marginRequirement: BN, liabilityValue: BN): void;
|
|
64
|
+
addIsolatedMarginCalculation(marketIndex: number, depositValue: BN, pnl: BN, liabilityValue: BN, marginRequirement: BN): void;
|
|
65
|
+
addPerpLiabilityValue(perpLiabilityValue: BN): void;
|
|
66
|
+
updateAllDepositOraclesValid(valid: boolean): void;
|
|
67
|
+
updateAllLiabilityOraclesValid(valid: boolean): void;
|
|
68
|
+
updateWithSpotIsolatedLiability(isolated: boolean): void;
|
|
69
|
+
updateWithPerpIsolatedLiability(isolated: boolean): void;
|
|
70
|
+
getCrossTotalCollateralPlusBuffer(): BN;
|
|
71
|
+
meetsCrossMarginRequirement(): boolean;
|
|
72
|
+
meetsCrossMarginRequirementWithBuffer(): boolean;
|
|
73
|
+
meetsMarginRequirement(): boolean;
|
|
74
|
+
meetsMarginRequirementWithBuffer(): boolean;
|
|
75
|
+
getCrossFreeCollateral(): BN;
|
|
76
|
+
getIsolatedFreeCollateral(marketIndex: number): BN;
|
|
77
|
+
getIsolatedMarginCalculation(marketIndex: number): IsolatedMarginCalculation | undefined;
|
|
78
|
+
hasIsolatedMarginCalculation(marketIndex: number): boolean;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=marginCalculation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marginCalculation.d.ts","sourceRoot":"","sources":["../../src/marginCalculation.ts"],"names":[],"mappings":"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"}
|