@drift-labs/sdk 2.148.0-beta.1 → 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/idl/drift.json +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/idl/drift.json +1 -1
- 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/idl/drift.json +1 -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/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.149.0-beta.1
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MarginCalculation = exports.IsolatedMarginCalculation = exports.MarginContext = exports.MarketIdentifier = void 0;
|
|
4
|
+
const numericConstants_1 = require("./constants/numericConstants");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
class MarketIdentifier {
|
|
7
|
+
constructor(marketType, marketIndex) {
|
|
8
|
+
this.marketType = marketType;
|
|
9
|
+
this.marketIndex = marketIndex;
|
|
10
|
+
}
|
|
11
|
+
static spot(marketIndex) {
|
|
12
|
+
return new MarketIdentifier(types_1.MarketType.SPOT, marketIndex);
|
|
13
|
+
}
|
|
14
|
+
static perp(marketIndex) {
|
|
15
|
+
return new MarketIdentifier(types_1.MarketType.PERP, marketIndex);
|
|
16
|
+
}
|
|
17
|
+
equals(other) {
|
|
18
|
+
return (!!other &&
|
|
19
|
+
(0, types_1.isVariant)(this.marketType, (0, types_1.getVariant)(other.marketType)) &&
|
|
20
|
+
this.marketIndex === other.marketIndex);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.MarketIdentifier = MarketIdentifier;
|
|
24
|
+
class MarginContext {
|
|
25
|
+
constructor(marginType) {
|
|
26
|
+
this.marginType = marginType;
|
|
27
|
+
this.mode = { type: 'Standard' };
|
|
28
|
+
this.strict = false;
|
|
29
|
+
this.ignoreInvalidDepositOracles = false;
|
|
30
|
+
this.isolatedMarginBuffers = new Map();
|
|
31
|
+
}
|
|
32
|
+
static standard(marginType) {
|
|
33
|
+
return new MarginContext(marginType);
|
|
34
|
+
}
|
|
35
|
+
static liquidation(crossMarginBuffer, isolatedMarginBuffers) {
|
|
36
|
+
const ctx = new MarginContext('Maintenance');
|
|
37
|
+
ctx.mode = { type: 'Liquidation' };
|
|
38
|
+
ctx.crossMarginBuffer = crossMarginBuffer;
|
|
39
|
+
ctx.isolatedMarginBuffers = isolatedMarginBuffers;
|
|
40
|
+
return ctx;
|
|
41
|
+
}
|
|
42
|
+
strictMode(strict) {
|
|
43
|
+
this.strict = strict;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
ignoreInvalidDeposits(ignore) {
|
|
47
|
+
this.ignoreInvalidDepositOracles = ignore;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
setCrossMarginBuffer(crossMarginBuffer) {
|
|
51
|
+
this.crossMarginBuffer = crossMarginBuffer;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
setIsolatedMarginBuffers(isolatedMarginBuffers) {
|
|
55
|
+
this.isolatedMarginBuffers = isolatedMarginBuffers;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
setIsolatedMarginBuffer(marketIndex, isolatedMarginBuffer) {
|
|
59
|
+
this.isolatedMarginBuffers.set(marketIndex, isolatedMarginBuffer);
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.MarginContext = MarginContext;
|
|
64
|
+
class IsolatedMarginCalculation {
|
|
65
|
+
constructor() {
|
|
66
|
+
this.marginRequirement = numericConstants_1.ZERO;
|
|
67
|
+
this.totalCollateral = numericConstants_1.ZERO;
|
|
68
|
+
this.totalCollateralBuffer = numericConstants_1.ZERO;
|
|
69
|
+
this.marginRequirementPlusBuffer = numericConstants_1.ZERO;
|
|
70
|
+
}
|
|
71
|
+
getTotalCollateralPlusBuffer() {
|
|
72
|
+
return this.totalCollateral.add(this.totalCollateralBuffer);
|
|
73
|
+
}
|
|
74
|
+
meetsMarginRequirement() {
|
|
75
|
+
return this.totalCollateral.gte(this.marginRequirement);
|
|
76
|
+
}
|
|
77
|
+
meetsMarginRequirementWithBuffer() {
|
|
78
|
+
return this.getTotalCollateralPlusBuffer().gte(this.marginRequirementPlusBuffer);
|
|
79
|
+
}
|
|
80
|
+
marginShortage() {
|
|
81
|
+
const shortage = this.marginRequirementPlusBuffer.sub(this.getTotalCollateralPlusBuffer());
|
|
82
|
+
return shortage.isNeg() ? numericConstants_1.ZERO : shortage;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.IsolatedMarginCalculation = IsolatedMarginCalculation;
|
|
86
|
+
class MarginCalculation {
|
|
87
|
+
constructor(context) {
|
|
88
|
+
this.context = context;
|
|
89
|
+
this.totalCollateral = numericConstants_1.ZERO;
|
|
90
|
+
this.totalCollateralBuffer = numericConstants_1.ZERO;
|
|
91
|
+
this.marginRequirement = numericConstants_1.ZERO;
|
|
92
|
+
this.marginRequirementPlusBuffer = numericConstants_1.ZERO;
|
|
93
|
+
this.isolatedMarginCalculations = new Map();
|
|
94
|
+
this.allDepositOraclesValid = true;
|
|
95
|
+
this.allLiabilityOraclesValid = true;
|
|
96
|
+
this.withPerpIsolatedLiability = false;
|
|
97
|
+
this.withSpotIsolatedLiability = false;
|
|
98
|
+
this.totalPerpLiabilityValue = numericConstants_1.ZERO;
|
|
99
|
+
this.trackedMarketMarginRequirement = numericConstants_1.ZERO;
|
|
100
|
+
this.fuelDeposits = 0;
|
|
101
|
+
this.fuelBorrows = 0;
|
|
102
|
+
this.fuelPositions = 0;
|
|
103
|
+
}
|
|
104
|
+
addCrossMarginTotalCollateral(delta) {
|
|
105
|
+
const crossMarginBuffer = this.context.crossMarginBuffer;
|
|
106
|
+
this.totalCollateral = this.totalCollateral.add(delta);
|
|
107
|
+
if (crossMarginBuffer.gt(numericConstants_1.ZERO) && delta.isNeg()) {
|
|
108
|
+
this.totalCollateralBuffer = this.totalCollateralBuffer.add(delta.mul(crossMarginBuffer).div(numericConstants_1.MARGIN_PRECISION));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
addCrossMarginRequirement(marginRequirement, liabilityValue) {
|
|
112
|
+
const crossMarginBuffer = this.context.crossMarginBuffer;
|
|
113
|
+
this.marginRequirement = this.marginRequirement.add(marginRequirement);
|
|
114
|
+
if (crossMarginBuffer.gt(numericConstants_1.ZERO)) {
|
|
115
|
+
this.marginRequirementPlusBuffer = this.marginRequirementPlusBuffer.add(marginRequirement.add(liabilityValue.mul(crossMarginBuffer).div(numericConstants_1.MARGIN_PRECISION)));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
addIsolatedMarginCalculation(marketIndex, depositValue, pnl, liabilityValue, marginRequirement) {
|
|
119
|
+
var _a;
|
|
120
|
+
const totalCollateral = depositValue.add(pnl);
|
|
121
|
+
const isolatedMarginBuffer = (_a = this.context.isolatedMarginBuffers.get(marketIndex)) !== null && _a !== void 0 ? _a : numericConstants_1.ZERO;
|
|
122
|
+
const totalCollateralBuffer = isolatedMarginBuffer.gt(numericConstants_1.ZERO) && pnl.isNeg()
|
|
123
|
+
? pnl.mul(isolatedMarginBuffer).div(numericConstants_1.MARGIN_PRECISION)
|
|
124
|
+
: numericConstants_1.ZERO;
|
|
125
|
+
const marginRequirementPlusBuffer = isolatedMarginBuffer.gt(numericConstants_1.ZERO)
|
|
126
|
+
? marginRequirement.add(liabilityValue.mul(isolatedMarginBuffer).div(numericConstants_1.MARGIN_PRECISION))
|
|
127
|
+
: marginRequirement;
|
|
128
|
+
const iso = new IsolatedMarginCalculation();
|
|
129
|
+
iso.marginRequirement = marginRequirement;
|
|
130
|
+
iso.totalCollateral = totalCollateral;
|
|
131
|
+
iso.totalCollateralBuffer = totalCollateralBuffer;
|
|
132
|
+
iso.marginRequirementPlusBuffer = marginRequirementPlusBuffer;
|
|
133
|
+
this.isolatedMarginCalculations.set(marketIndex, iso);
|
|
134
|
+
}
|
|
135
|
+
addPerpLiabilityValue(perpLiabilityValue) {
|
|
136
|
+
this.totalPerpLiabilityValue =
|
|
137
|
+
this.totalPerpLiabilityValue.add(perpLiabilityValue);
|
|
138
|
+
}
|
|
139
|
+
updateAllDepositOraclesValid(valid) {
|
|
140
|
+
this.allDepositOraclesValid = this.allDepositOraclesValid && valid;
|
|
141
|
+
}
|
|
142
|
+
updateAllLiabilityOraclesValid(valid) {
|
|
143
|
+
this.allLiabilityOraclesValid = this.allLiabilityOraclesValid && valid;
|
|
144
|
+
}
|
|
145
|
+
updateWithSpotIsolatedLiability(isolated) {
|
|
146
|
+
this.withSpotIsolatedLiability = this.withSpotIsolatedLiability || isolated;
|
|
147
|
+
}
|
|
148
|
+
updateWithPerpIsolatedLiability(isolated) {
|
|
149
|
+
this.withPerpIsolatedLiability = this.withPerpIsolatedLiability || isolated;
|
|
150
|
+
}
|
|
151
|
+
getCrossTotalCollateralPlusBuffer() {
|
|
152
|
+
return this.totalCollateral.add(this.totalCollateralBuffer);
|
|
153
|
+
}
|
|
154
|
+
meetsCrossMarginRequirement() {
|
|
155
|
+
return this.totalCollateral.gte(this.marginRequirement);
|
|
156
|
+
}
|
|
157
|
+
meetsCrossMarginRequirementWithBuffer() {
|
|
158
|
+
return this.getCrossTotalCollateralPlusBuffer().gte(this.marginRequirementPlusBuffer);
|
|
159
|
+
}
|
|
160
|
+
meetsMarginRequirement() {
|
|
161
|
+
if (!this.meetsCrossMarginRequirement())
|
|
162
|
+
return false;
|
|
163
|
+
for (const [, iso] of this.isolatedMarginCalculations) {
|
|
164
|
+
if (!iso.meetsMarginRequirement())
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
meetsMarginRequirementWithBuffer() {
|
|
170
|
+
if (!this.meetsCrossMarginRequirementWithBuffer())
|
|
171
|
+
return false;
|
|
172
|
+
for (const [, iso] of this.isolatedMarginCalculations) {
|
|
173
|
+
if (!iso.meetsMarginRequirementWithBuffer())
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
getCrossFreeCollateral() {
|
|
179
|
+
const free = this.totalCollateral.sub(this.marginRequirement);
|
|
180
|
+
return free.isNeg() ? numericConstants_1.ZERO : free;
|
|
181
|
+
}
|
|
182
|
+
getIsolatedFreeCollateral(marketIndex) {
|
|
183
|
+
const iso = this.isolatedMarginCalculations.get(marketIndex);
|
|
184
|
+
if (!iso)
|
|
185
|
+
throw new Error('InvalidMarginCalculation: missing isolated calc');
|
|
186
|
+
const free = iso.totalCollateral.sub(iso.marginRequirement);
|
|
187
|
+
return free.isNeg() ? numericConstants_1.ZERO : free;
|
|
188
|
+
}
|
|
189
|
+
getIsolatedMarginCalculation(marketIndex) {
|
|
190
|
+
return this.isolatedMarginCalculations.get(marketIndex);
|
|
191
|
+
}
|
|
192
|
+
hasIsolatedMarginCalculation(marketIndex) {
|
|
193
|
+
return this.isolatedMarginCalculations.has(marketIndex);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.MarginCalculation = MarginCalculation;
|
|
@@ -19,7 +19,7 @@ export declare function calculateOraclePriceForPerpMargin(perpPosition: PerpPosi
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function calculateBaseAssetValueWithOracle(market: PerpMarketAccount, perpPosition: PerpPosition, oraclePriceData: Pick<OraclePriceData, 'price'>, includeOpenOrders?: boolean): BN;
|
|
21
21
|
export declare function calculateWorstCaseBaseAssetAmount(perpPosition: PerpPosition, perpMarket: PerpMarketAccount, oraclePrice: BN): BN;
|
|
22
|
-
export declare function calculateWorstCasePerpLiabilityValue(perpPosition: PerpPosition, perpMarket: PerpMarketAccount, oraclePrice: BN): {
|
|
22
|
+
export declare function calculateWorstCasePerpLiabilityValue(perpPosition: PerpPosition, perpMarket: PerpMarketAccount, oraclePrice: BN, includeOpenOrders?: boolean): {
|
|
23
23
|
worstCaseBaseAssetAmount: BN;
|
|
24
24
|
worstCaseLiabilityValue: BN;
|
|
25
25
|
};
|
|
@@ -89,10 +89,16 @@ function calculateWorstCaseBaseAssetAmount(perpPosition, perpMarket, oraclePrice
|
|
|
89
89
|
return calculateWorstCasePerpLiabilityValue(perpPosition, perpMarket, oraclePrice).worstCaseBaseAssetAmount;
|
|
90
90
|
}
|
|
91
91
|
exports.calculateWorstCaseBaseAssetAmount = calculateWorstCaseBaseAssetAmount;
|
|
92
|
-
function calculateWorstCasePerpLiabilityValue(perpPosition, perpMarket, oraclePrice) {
|
|
92
|
+
function calculateWorstCasePerpLiabilityValue(perpPosition, perpMarket, oraclePrice, includeOpenOrders = true) {
|
|
93
|
+
const isPredictionMarket = (0, types_1.isVariant)(perpMarket.contractType, 'prediction');
|
|
94
|
+
if (!includeOpenOrders) {
|
|
95
|
+
return {
|
|
96
|
+
worstCaseBaseAssetAmount: perpPosition.baseAssetAmount,
|
|
97
|
+
worstCaseLiabilityValue: calculatePerpLiabilityValue(perpPosition.baseAssetAmount, oraclePrice, isPredictionMarket),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
93
100
|
const allBids = perpPosition.baseAssetAmount.add(perpPosition.openBids);
|
|
94
101
|
const allAsks = perpPosition.baseAssetAmount.add(perpPosition.openAsks);
|
|
95
|
-
const isPredictionMarket = (0, types_1.isVariant)(perpMarket.contractType, 'prediction');
|
|
96
102
|
const allBidsLiabilityValue = calculatePerpLiabilityValue(allBids, oraclePrice, isPredictionMarket);
|
|
97
103
|
const allAsksLiabilityValue = calculatePerpLiabilityValue(allAsks, oraclePrice, isPredictionMarket);
|
|
98
104
|
if (allAsksLiabilityValue.gte(allBidsLiabilityValue)) {
|
|
@@ -11,7 +11,7 @@ export type OrderFillSimulation = {
|
|
|
11
11
|
weightedTokenValue: BN;
|
|
12
12
|
freeCollateralContribution: any;
|
|
13
13
|
};
|
|
14
|
-
export declare function getWorstCaseTokenAmounts(spotPosition: SpotPosition, spotMarketAccount: SpotMarketAccount, strictOraclePrice: StrictOraclePrice, marginCategory: MarginCategory, customMarginRatio?: number): OrderFillSimulation;
|
|
14
|
+
export declare function getWorstCaseTokenAmounts(spotPosition: SpotPosition, spotMarketAccount: SpotMarketAccount, strictOraclePrice: StrictOraclePrice, marginCategory: MarginCategory, customMarginRatio?: number, includeOpenOrders?: boolean): OrderFillSimulation;
|
|
15
15
|
export declare function calculateWeightedTokenValue(tokenAmount: BN, tokenValue: BN, oraclePrice: BN, spotMarket: SpotMarketAccount, marginCategory: MarginCategory, customMarginRatio?: number): {
|
|
16
16
|
weight: BN;
|
|
17
17
|
weightedTokenValue: BN;
|
|
@@ -8,10 +8,11 @@ function isSpotPositionAvailable(position) {
|
|
|
8
8
|
return position.scaledBalance.eq(numericConstants_1.ZERO) && position.openOrders === 0;
|
|
9
9
|
}
|
|
10
10
|
exports.isSpotPositionAvailable = isSpotPositionAvailable;
|
|
11
|
-
function getWorstCaseTokenAmounts(spotPosition, spotMarketAccount, strictOraclePrice, marginCategory, customMarginRatio) {
|
|
11
|
+
function getWorstCaseTokenAmounts(spotPosition, spotMarketAccount, strictOraclePrice, marginCategory, customMarginRatio, includeOpenOrders = true) {
|
|
12
12
|
const tokenAmount = (0, spotBalance_1.getSignedTokenAmount)((0, spotBalance_1.getTokenAmount)(spotPosition.scaledBalance, spotMarketAccount, spotPosition.balanceType), spotPosition.balanceType);
|
|
13
13
|
const tokenValue = (0, spotBalance_1.getStrictTokenValue)(tokenAmount, spotMarketAccount.decimals, strictOraclePrice);
|
|
14
|
-
if (spotPosition.openBids.eq(numericConstants_1.ZERO) && spotPosition.openAsks.eq(numericConstants_1.ZERO))
|
|
14
|
+
if ((spotPosition.openBids.eq(numericConstants_1.ZERO) && spotPosition.openAsks.eq(numericConstants_1.ZERO)) ||
|
|
15
|
+
!includeOpenOrders) {
|
|
15
16
|
const { weight, weightedTokenValue } = calculateWeightedTokenValue(tokenAmount, tokenValue, strictOraclePrice.current, spotMarketAccount, marginCategory, customMarginRatio);
|
|
16
17
|
return {
|
|
17
18
|
tokenAmount,
|
package/lib/browser/types.d.ts
CHANGED
|
@@ -1195,6 +1195,11 @@ export type PerpPosition = {
|
|
|
1195
1195
|
isolatedPositionScaledBalance: BN;
|
|
1196
1196
|
positionFlag: number;
|
|
1197
1197
|
};
|
|
1198
|
+
export declare class PositionFlag {
|
|
1199
|
+
static readonly IsolatedPosition = 1;
|
|
1200
|
+
static readonly BeingLiquidated = 2;
|
|
1201
|
+
static readonly Bankruptcy = 4;
|
|
1202
|
+
}
|
|
1198
1203
|
export type UserStatsAccount = {
|
|
1199
1204
|
numberOfSubAccounts: number;
|
|
1200
1205
|
numberOfSubAccountsCreated: number;
|
|
@@ -1860,4 +1865,9 @@ export type CacheInfo = {
|
|
|
1860
1865
|
export type AmmCache = {
|
|
1861
1866
|
cache: CacheInfo[];
|
|
1862
1867
|
};
|
|
1868
|
+
export type AccountLiquidatableStatus = {
|
|
1869
|
+
canBeLiquidated: boolean;
|
|
1870
|
+
marginRequirement: BN;
|
|
1871
|
+
totalCollateral: BN;
|
|
1872
|
+
};
|
|
1863
1873
|
export {};
|
package/lib/browser/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ConstituentLpOperation = exports.ConstituentStatus = exports.OracleValidity = exports.SwapReduceOnly = exports.PlaceAndTakeOrderSuccessCondition = exports.FuelOverflowStatus = exports.ReferrerStatus = exports.DefaultOrderParams = exports.ModifyOrderPolicy = exports.OrderParamsBitFlag = exports.PostOnlyParams = exports.LiquidationType = exports.LPAction = exports.TradeSide = exports.getVariant = exports.isOneOfVariant = exports.isVariant = exports.SettlePnlMode = exports.StakeAction = exports.SpotFulfillmentConfigStatus = exports.SettlePnlExplanation = exports.DepositExplanation = exports.SpotFulfillmentStatus = exports.SpotFulfillmentType = exports.OrderTriggerCondition = exports.OrderActionExplanation = exports.OrderAction = exports.OrderBitFlag = exports.OrderStatus = exports.MarketType = exports.OrderType = exports.OracleSourceNum = exports.OracleSource = exports.DepositDirection = exports.PositionDirection = exports.SpotBalanceType = exports.SwapDirection = exports.TokenProgramFlag = exports.AssetTier = exports.ContractTier = exports.ContractType = exports.MarginMode = exports.UserStatus = exports.InsuranceFundOperation = exports.SpotOperation = exports.PerpOperation = exports.MarketStatus = exports.FeatureBitFlags = exports.ExchangeStatus = void 0;
|
|
3
|
+
exports.ConstituentLpOperation = exports.ConstituentStatus = exports.OracleValidity = exports.SwapReduceOnly = exports.PlaceAndTakeOrderSuccessCondition = exports.FuelOverflowStatus = exports.ReferrerStatus = exports.DefaultOrderParams = exports.ModifyOrderPolicy = exports.OrderParamsBitFlag = exports.PostOnlyParams = exports.PositionFlag = exports.LiquidationType = exports.LPAction = exports.TradeSide = exports.getVariant = exports.isOneOfVariant = exports.isVariant = exports.SettlePnlMode = exports.StakeAction = exports.SpotFulfillmentConfigStatus = exports.SettlePnlExplanation = exports.DepositExplanation = exports.SpotFulfillmentStatus = exports.SpotFulfillmentType = exports.OrderTriggerCondition = exports.OrderActionExplanation = exports.OrderAction = exports.OrderBitFlag = exports.OrderStatus = exports.MarketType = exports.OrderType = exports.OracleSourceNum = exports.OracleSource = exports.DepositDirection = exports.PositionDirection = exports.SpotBalanceType = exports.SwapDirection = exports.TokenProgramFlag = exports.AssetTier = exports.ContractTier = exports.ContractType = exports.MarginMode = exports.UserStatus = exports.InsuranceFundOperation = exports.SpotOperation = exports.PerpOperation = exports.MarketStatus = exports.FeatureBitFlags = exports.ExchangeStatus = void 0;
|
|
4
4
|
const numericConstants_1 = require("./constants/numericConstants");
|
|
5
5
|
// # Utility Types / Enums / Constants
|
|
6
6
|
var ExchangeStatus;
|
|
@@ -353,6 +353,12 @@ LiquidationType.SPOT_BANKRUPTCY = {
|
|
|
353
353
|
LiquidationType.LIQUIDATE_SPOT = {
|
|
354
354
|
liquidateSpot: {},
|
|
355
355
|
};
|
|
356
|
+
class PositionFlag {
|
|
357
|
+
}
|
|
358
|
+
exports.PositionFlag = PositionFlag;
|
|
359
|
+
PositionFlag.IsolatedPosition = 1;
|
|
360
|
+
PositionFlag.BeingLiquidated = 2;
|
|
361
|
+
PositionFlag.Bankruptcy = 4;
|
|
356
362
|
class PostOnlyParams {
|
|
357
363
|
}
|
|
358
364
|
exports.PostOnlyParams = PostOnlyParams;
|
package/lib/browser/user.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { PublicKey } from '@solana/web3.js';
|
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
5
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
6
6
|
import { DriftClient } from './driftClient';
|
|
7
|
-
import { HealthComponent, HealthComponents, MarginCategory, Order, PerpMarketAccount, PerpPosition, SpotPosition, UserAccount, UserStatus } from './types';
|
|
7
|
+
import { HealthComponent, HealthComponents, MarginCategory, Order, PerpMarketAccount, PerpPosition, SpotPosition, UserAccount, UserStatus, AccountLiquidatableStatus } from './types';
|
|
8
8
|
import { DataAndSlot, UserAccountEvents, UserAccountSubscriber } from './accounts/types';
|
|
9
9
|
import { BN } from '@coral-xyz/anchor';
|
|
10
10
|
import { MarketType, PositionDirection, SpotMarketAccount } from './types';
|
|
@@ -12,6 +12,8 @@ import { UserStats } from './userStats';
|
|
|
12
12
|
import { OraclePriceData } from './oracles/types';
|
|
13
13
|
import { UserConfig } from './userConfig';
|
|
14
14
|
import { StrictOraclePrice } from './oracles/strictOraclePrice';
|
|
15
|
+
import { IsolatedMarginCalculation, MarginCalculation } from './marginCalculation';
|
|
16
|
+
export type MarginType = 'Cross' | 'Isolated';
|
|
15
17
|
export declare class User {
|
|
16
18
|
driftClient: DriftClient;
|
|
17
19
|
userAccountPublicKey: PublicKey;
|
|
@@ -60,6 +62,7 @@ export declare class User {
|
|
|
60
62
|
*/
|
|
61
63
|
getTokenAmount(marketIndex: number): BN;
|
|
62
64
|
getEmptyPosition(marketIndex: number): PerpPosition;
|
|
65
|
+
getIsolatePerpPositionTokenAmount(perpMarketIndex: number): BN;
|
|
63
66
|
getClonedPosition(position: PerpPosition): PerpPosition;
|
|
64
67
|
getOrderForUserAccount(userAccount: UserAccount, orderId: number): Order | undefined;
|
|
65
68
|
/**
|
|
@@ -96,19 +99,32 @@ export declare class User {
|
|
|
96
99
|
* calculates Free Collateral = Total collateral - margin requirement
|
|
97
100
|
* @returns : Precision QUOTE_PRECISION
|
|
98
101
|
*/
|
|
99
|
-
getFreeCollateral(marginCategory?: MarginCategory, enterHighLeverageMode?:
|
|
102
|
+
getFreeCollateral(marginCategory?: MarginCategory, enterHighLeverageMode?: boolean, perpMarketIndex?: number): BN;
|
|
100
103
|
/**
|
|
101
|
-
* @
|
|
104
|
+
* @deprecated Use the overload that includes { marginType, perpMarketIndex }
|
|
102
105
|
*/
|
|
103
|
-
getMarginRequirement(marginCategory: MarginCategory, liquidationBuffer?: BN, strict?: boolean, includeOpenOrders?: boolean, enteringHighLeverage?:
|
|
106
|
+
getMarginRequirement(marginCategory: MarginCategory, liquidationBuffer?: BN, strict?: boolean, includeOpenOrders?: boolean, enteringHighLeverage?: boolean): BN;
|
|
107
|
+
/**
|
|
108
|
+
* Calculates the margin requirement based on the specified parameters.
|
|
109
|
+
*
|
|
110
|
+
* @param marginCategory - The category of margin to calculate ('Initial' or 'Maintenance').
|
|
111
|
+
* @param liquidationBuffer - Optional buffer amount to consider during liquidation scenarios.
|
|
112
|
+
* @param strict - Optional flag to enforce strict margin calculations.
|
|
113
|
+
* @param includeOpenOrders - Optional flag to include open orders in the margin calculation.
|
|
114
|
+
* @param enteringHighLeverage - Optional flag indicating if the user is entering high leverage mode.
|
|
115
|
+
* @param perpMarketIndex - Optional index of the perpetual market. Required if marginType is 'Isolated'.
|
|
116
|
+
*
|
|
117
|
+
* @returns The calculated margin requirement as a BN (BigNumber).
|
|
118
|
+
*/
|
|
119
|
+
getMarginRequirement(marginCategory: MarginCategory, liquidationBuffer?: BN, strict?: boolean, includeOpenOrders?: boolean, enteringHighLeverage?: boolean, perpMarketIndex?: number): BN;
|
|
104
120
|
/**
|
|
105
121
|
* @returns The initial margin requirement in USDC. : QUOTE_PRECISION
|
|
106
122
|
*/
|
|
107
|
-
getInitialMarginRequirement(enterHighLeverageMode?:
|
|
123
|
+
getInitialMarginRequirement(enterHighLeverageMode?: boolean, perpMarketIndex?: number): BN;
|
|
108
124
|
/**
|
|
109
125
|
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
|
|
110
126
|
*/
|
|
111
|
-
getMaintenanceMarginRequirement(liquidationBuffer?: BN): BN;
|
|
127
|
+
getMaintenanceMarginRequirement(liquidationBuffer?: BN, perpMarketIndex?: number): BN;
|
|
112
128
|
getActivePerpPositionsForUserAccount(userAccount: UserAccount): PerpPosition[];
|
|
113
129
|
getActivePerpPositions(): PerpPosition[];
|
|
114
130
|
getActivePerpPositionsAndSlot(): DataAndSlot<PerpPosition[]>;
|
|
@@ -147,13 +163,13 @@ export declare class User {
|
|
|
147
163
|
* calculates TotalCollateral: collateral + unrealized pnl
|
|
148
164
|
* @returns : Precision QUOTE_PRECISION
|
|
149
165
|
*/
|
|
150
|
-
getTotalCollateral(marginCategory?: MarginCategory, strict?: boolean, includeOpenOrders?: boolean, liquidationBuffer?: BN): BN;
|
|
151
|
-
getLiquidationBuffer():
|
|
166
|
+
getTotalCollateral(marginCategory?: MarginCategory, strict?: boolean, includeOpenOrders?: boolean, liquidationBuffer?: BN, perpMarketIndex?: number): BN;
|
|
167
|
+
getLiquidationBuffer(): Map<number | 'cross', BN>;
|
|
152
168
|
/**
|
|
153
169
|
* calculates User Health by comparing total collateral and maint. margin requirement
|
|
154
170
|
* @returns : number (value from [0, 100])
|
|
155
171
|
*/
|
|
156
|
-
getHealth(): number;
|
|
172
|
+
getHealth(perpMarketIndex?: number): number;
|
|
157
173
|
calculateWeightedPerpPositionLiability(perpPosition: PerpPosition, marginCategory?: MarginCategory, liquidationBuffer?: BN, includeOpenOrders?: boolean, strict?: boolean, enteringHighLeverage?: any): BN;
|
|
158
174
|
/**
|
|
159
175
|
* calculates position value of a single perp market in margin system
|
|
@@ -185,14 +201,14 @@ export declare class User {
|
|
|
185
201
|
* calculates current user leverage which is (total liability size) / (net asset value)
|
|
186
202
|
* @returns : Precision TEN_THOUSAND
|
|
187
203
|
*/
|
|
188
|
-
getLeverage(includeOpenOrders?: boolean): BN;
|
|
204
|
+
getLeverage(includeOpenOrders?: boolean, perpMarketIndex?: number): BN;
|
|
189
205
|
calculateLeverageFromComponents({ perpLiabilityValue, perpPnl, spotAssetValue, spotLiabilityValue, }: {
|
|
190
206
|
perpLiabilityValue: BN;
|
|
191
207
|
perpPnl: BN;
|
|
192
208
|
spotAssetValue: BN;
|
|
193
209
|
spotLiabilityValue: BN;
|
|
194
210
|
}): BN;
|
|
195
|
-
getLeverageComponents(includeOpenOrders?: boolean, marginCategory?: MarginCategory): {
|
|
211
|
+
getLeverageComponents(includeOpenOrders?: boolean, marginCategory?: MarginCategory, perpMarketIndex?: number): {
|
|
196
212
|
perpLiabilityValue: BN;
|
|
197
213
|
perpPnl: BN;
|
|
198
214
|
spotAssetValue: BN;
|
|
@@ -230,12 +246,25 @@ export declare class User {
|
|
|
230
246
|
* @returns : Precision TEN_THOUSAND
|
|
231
247
|
*/
|
|
232
248
|
getMarginRatio(): BN;
|
|
233
|
-
canBeLiquidated(): {
|
|
234
|
-
|
|
235
|
-
marginRequirement: BN;
|
|
236
|
-
totalCollateral: BN;
|
|
249
|
+
canBeLiquidated(): AccountLiquidatableStatus & {
|
|
250
|
+
isolatedPositions: Map<number, AccountLiquidatableStatus>;
|
|
237
251
|
};
|
|
252
|
+
/**
|
|
253
|
+
* New API: Returns liquidation status for cross and each isolated perp position.
|
|
254
|
+
* Map keys:
|
|
255
|
+
* - 'cross' for cross margin
|
|
256
|
+
* - marketIndex (number) for each isolated perp position
|
|
257
|
+
*/
|
|
258
|
+
getLiquidationStatuses(marginCalc?: MarginCalculation): Map<'cross' | number, AccountLiquidatableStatus>;
|
|
238
259
|
isBeingLiquidated(): boolean;
|
|
260
|
+
isCrossMarginBeingLiquidated(): boolean;
|
|
261
|
+
/** Returns true if cross margin is currently below maintenance requirement (no buffer). */
|
|
262
|
+
canCrossMarginBeLiquidated(marginCalc?: MarginCalculation): boolean;
|
|
263
|
+
hasIsolatedPositionBeingLiquidated(): boolean;
|
|
264
|
+
isIsolatedPositionBeingLiquidated(perpMarketIndex: number): boolean;
|
|
265
|
+
/** Returns true if any isolated perp position is currently below its maintenance requirement (no buffer). */
|
|
266
|
+
getLiquidatableIsolatedPositions(marginCalc?: MarginCalculation): number[];
|
|
267
|
+
canIsolatedPositionMarginBeLiquidated(isolatedMarginCalculation: IsolatedMarginCalculation): boolean;
|
|
239
268
|
hasStatus(status: UserStatus): boolean;
|
|
240
269
|
isBankrupt(): boolean;
|
|
241
270
|
isHighLeverageMode(marginCategory: MarginCategory): boolean;
|
|
@@ -260,7 +289,7 @@ export declare class User {
|
|
|
260
289
|
* @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)
|
|
261
290
|
* @returns Precision : PRICE_PRECISION
|
|
262
291
|
*/
|
|
263
|
-
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN, estimatedEntryPrice?: BN, marginCategory?: MarginCategory, includeOpenOrders?: boolean, offsetCollateral?: BN, enteringHighLeverage?:
|
|
292
|
+
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN, estimatedEntryPrice?: BN, marginCategory?: MarginCategory, includeOpenOrders?: boolean, offsetCollateral?: BN, enteringHighLeverage?: boolean, marginType?: MarginType): BN;
|
|
264
293
|
calculateEntriesEffectOnFreeCollateral(market: PerpMarketAccount, oraclePrice: BN, perpPosition: PerpPosition, positionBaseSizeChange: BN, estimatedEntryPrice: BN, includeOpenOrders: boolean, enteringHighLeverage?: any, marginCategory?: MarginCategory): BN;
|
|
265
294
|
calculateFreeCollateralDeltaForPerp(market: PerpMarketAccount, perpPosition: PerpPosition, positionBaseSizeChange: BN, oraclePrice: BN, marginCategory?: MarginCategory, includeOpenOrders?: boolean, enteringHighLeverage?: any): BN | undefined;
|
|
266
295
|
calculateFreeCollateralDeltaForSpot(market: SpotMarketAccount, signedTokenAmount: BN, marginCategory?: MarginCategory): BN;
|
|
@@ -395,4 +424,15 @@ export declare class User {
|
|
|
395
424
|
activePerpPositions: number[];
|
|
396
425
|
activeSpotPositions: number[];
|
|
397
426
|
};
|
|
427
|
+
/**
|
|
428
|
+
* Compute a consolidated margin snapshot once, without caching.
|
|
429
|
+
* Consumers can use this to avoid duplicating work across separate calls.
|
|
430
|
+
*/
|
|
431
|
+
getMarginCalculation(marginCategory?: MarginCategory, opts?: {
|
|
432
|
+
strict?: boolean;
|
|
433
|
+
includeOpenOrders?: boolean;
|
|
434
|
+
enteringHighLeverage?: boolean;
|
|
435
|
+
liquidationBufferMap?: Map<number | 'cross', BN>;
|
|
436
|
+
}): MarginCalculation;
|
|
437
|
+
private isPerpPositionIsolated;
|
|
398
438
|
}
|