@drift-labs/sdk 2.31.1-beta.3 → 2.31.1-beta.4
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/idl/drift.json +1 -1
- package/lib/math/tiers.d.ts +4 -0
- package/lib/math/tiers.js +52 -0
- package/lib/user.d.ts +10 -1
- package/lib/user.js +29 -4
- package/package.json +1 -1
- package/src/idl/drift.json +1 -1
- package/src/math/tiers.ts +44 -0
- package/src/user.ts +54 -9
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.31.1-beta.
|
|
1
|
+
2.31.1-beta.4
|
package/lib/idl/drift.json
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { PerpMarketAccount, SpotMarketAccount } from '../types';
|
|
2
|
+
export declare function getPerpMarketTierNumber(perpMarket: PerpMarketAccount): number;
|
|
3
|
+
export declare function getSpotMarketTierNumber(spotMarket: SpotMarketAccount): number;
|
|
4
|
+
export declare function perpTierIsAsSafeAs(perpTier: number, otherPerpTier: number, otherSpotTier: number): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.perpTierIsAsSafeAs = exports.getSpotMarketTierNumber = exports.getPerpMarketTierNumber = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
function getPerpMarketTierNumber(perpMarket) {
|
|
6
|
+
if ((0, types_1.isVariant)(perpMarket.contractTier, 'a')) {
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'b')) {
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'c')) {
|
|
13
|
+
return 2;
|
|
14
|
+
}
|
|
15
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'speculative')) {
|
|
16
|
+
return 3;
|
|
17
|
+
}
|
|
18
|
+
else if ((0, types_1.isVariant)(perpMarket.contractTier, 'isolated')) {
|
|
19
|
+
return 4;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return 5;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.getPerpMarketTierNumber = getPerpMarketTierNumber;
|
|
26
|
+
function getSpotMarketTierNumber(spotMarket) {
|
|
27
|
+
if ((0, types_1.isVariant)(spotMarket.assetTier, 'collateral')) {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'protected')) {
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'cross')) {
|
|
34
|
+
return 2;
|
|
35
|
+
}
|
|
36
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'isolated')) {
|
|
37
|
+
return 3;
|
|
38
|
+
}
|
|
39
|
+
else if ((0, types_1.isVariant)(spotMarket.assetTier, 'unlisted')) {
|
|
40
|
+
return 4;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return 5;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.getSpotMarketTierNumber = getSpotMarketTierNumber;
|
|
47
|
+
function perpTierIsAsSafeAs(perpTier, otherPerpTier, otherSpotTier) {
|
|
48
|
+
const asSafeAsPerp = perpTier <= otherPerpTier;
|
|
49
|
+
const asSafeAsSpot = otherSpotTier === 4 || (otherSpotTier >= 2 && perpTier <= 2);
|
|
50
|
+
return asSafeAsSpot && asSafeAsPerp;
|
|
51
|
+
}
|
|
52
|
+
exports.perpTierIsAsSafeAs = perpTierIsAsSafeAs;
|
package/lib/user.d.ts
CHANGED
|
@@ -107,6 +107,7 @@ export declare class User {
|
|
|
107
107
|
*/
|
|
108
108
|
getMaintenanceMarginRequirement(liquidationBuffer?: BN): BN;
|
|
109
109
|
getActivePerpPositions(): PerpPosition[];
|
|
110
|
+
getActiveSpotPositions(): SpotPosition[];
|
|
110
111
|
/**
|
|
111
112
|
* calculates unrealized position price pnl
|
|
112
113
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -185,7 +186,11 @@ export declare class User {
|
|
|
185
186
|
* @returns : Precision TEN_THOUSAND
|
|
186
187
|
*/
|
|
187
188
|
getMarginRatio(): BN;
|
|
188
|
-
canBeLiquidated():
|
|
189
|
+
canBeLiquidated(): {
|
|
190
|
+
canBeLiquidated: boolean;
|
|
191
|
+
marginRequirement: BN;
|
|
192
|
+
totalCollateral: BN;
|
|
193
|
+
};
|
|
189
194
|
isBeingLiquidated(): boolean;
|
|
190
195
|
isBankrupt(): boolean;
|
|
191
196
|
/**
|
|
@@ -277,6 +282,10 @@ export declare class User {
|
|
|
277
282
|
maxDepositAmount: BN;
|
|
278
283
|
};
|
|
279
284
|
canMakeIdle(slot: BN, slotsBeforeIdle: BN): boolean;
|
|
285
|
+
getSafestTiers(): {
|
|
286
|
+
perpTier: number;
|
|
287
|
+
spotTier: number;
|
|
288
|
+
};
|
|
280
289
|
/**
|
|
281
290
|
* Get the total position value, excluding any position coming from the given target market
|
|
282
291
|
* @param marketToIgnore
|
package/lib/user.js
CHANGED
|
@@ -12,6 +12,7 @@ const pollingUserAccountSubscriber_1 = require("./accounts/pollingUserAccountSub
|
|
|
12
12
|
const webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccountSubscriber");
|
|
13
13
|
const spotPosition_1 = require("./math/spotPosition");
|
|
14
14
|
const oracles_1 = require("./math/oracles");
|
|
15
|
+
const tiers_1 = require("./math/tiers");
|
|
15
16
|
class User {
|
|
16
17
|
get isSubscribed() {
|
|
17
18
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -308,6 +309,9 @@ class User {
|
|
|
308
309
|
!(pos.openOrders == 0) ||
|
|
309
310
|
!pos.lpShares.eq(numericConstants_1.ZERO));
|
|
310
311
|
}
|
|
312
|
+
getActiveSpotPositions() {
|
|
313
|
+
return this.getUserAccount().spotPositions.filter((pos) => !(0, spotPosition_1.isSpotPositionAvailable)(pos));
|
|
314
|
+
}
|
|
311
315
|
/**
|
|
312
316
|
* calculates unrealized position price pnl
|
|
313
317
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -778,12 +782,16 @@ class User {
|
|
|
778
782
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
779
783
|
// if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
|
|
780
784
|
let liquidationBuffer = undefined;
|
|
781
|
-
|
|
782
|
-
if (isBeingLiquidated) {
|
|
785
|
+
if (this.isBeingLiquidated()) {
|
|
783
786
|
liquidationBuffer = new _1.BN(this.driftClient.getStateAccount().liquidationMarginBufferRatio);
|
|
784
787
|
}
|
|
785
|
-
const
|
|
786
|
-
|
|
788
|
+
const marginRequirement = this.getMaintenanceMarginRequirement(liquidationBuffer);
|
|
789
|
+
const canBeLiquidated = totalCollateral.lt(marginRequirement);
|
|
790
|
+
return {
|
|
791
|
+
canBeLiquidated,
|
|
792
|
+
marginRequirement,
|
|
793
|
+
totalCollateral,
|
|
794
|
+
};
|
|
787
795
|
}
|
|
788
796
|
isBeingLiquidated() {
|
|
789
797
|
return (0, types_1.isOneOfVariant)(this.getUserAccount().status, [
|
|
@@ -1284,6 +1292,23 @@ class User {
|
|
|
1284
1292
|
}
|
|
1285
1293
|
return true;
|
|
1286
1294
|
}
|
|
1295
|
+
getSafestTiers() {
|
|
1296
|
+
let safestPerpTier = 4;
|
|
1297
|
+
let safestSpotTier = 4;
|
|
1298
|
+
for (const perpPosition of this.getActivePerpPositions()) {
|
|
1299
|
+
safestPerpTier = Math.min(safestPerpTier, (0, tiers_1.getPerpMarketTierNumber)(this.driftClient.getPerpMarketAccount(perpPosition.marketIndex)));
|
|
1300
|
+
}
|
|
1301
|
+
for (const spotPosition of this.getActiveSpotPositions()) {
|
|
1302
|
+
if ((0, types_1.isVariant)(spotPosition.balanceType, 'deposit')) {
|
|
1303
|
+
continue;
|
|
1304
|
+
}
|
|
1305
|
+
safestSpotTier = Math.min(safestSpotTier, (0, tiers_1.getSpotMarketTierNumber)(this.driftClient.getSpotMarketAccount(spotPosition.marketIndex)));
|
|
1306
|
+
}
|
|
1307
|
+
return {
|
|
1308
|
+
perpTier: safestPerpTier,
|
|
1309
|
+
spotTier: safestSpotTier,
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1287
1312
|
/**
|
|
1288
1313
|
* Get the total position value, excluding any position coming from the given target market
|
|
1289
1314
|
* @param marketToIgnore
|
package/package.json
CHANGED
package/src/idl/drift.json
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isVariant, PerpMarketAccount, SpotMarketAccount } from '../types';
|
|
2
|
+
|
|
3
|
+
export function getPerpMarketTierNumber(perpMarket: PerpMarketAccount): number {
|
|
4
|
+
if (isVariant(perpMarket.contractTier, 'a')) {
|
|
5
|
+
return 0;
|
|
6
|
+
} else if (isVariant(perpMarket.contractTier, 'b')) {
|
|
7
|
+
return 1;
|
|
8
|
+
} else if (isVariant(perpMarket.contractTier, 'c')) {
|
|
9
|
+
return 2;
|
|
10
|
+
} else if (isVariant(perpMarket.contractTier, 'speculative')) {
|
|
11
|
+
return 3;
|
|
12
|
+
} else if (isVariant(perpMarket.contractTier, 'isolated')) {
|
|
13
|
+
return 4;
|
|
14
|
+
} else {
|
|
15
|
+
return 5;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getSpotMarketTierNumber(spotMarket: SpotMarketAccount): number {
|
|
20
|
+
if (isVariant(spotMarket.assetTier, 'collateral')) {
|
|
21
|
+
return 0;
|
|
22
|
+
} else if (isVariant(spotMarket.assetTier, 'protected')) {
|
|
23
|
+
return 1;
|
|
24
|
+
} else if (isVariant(spotMarket.assetTier, 'cross')) {
|
|
25
|
+
return 2;
|
|
26
|
+
} else if (isVariant(spotMarket.assetTier, 'isolated')) {
|
|
27
|
+
return 3;
|
|
28
|
+
} else if (isVariant(spotMarket.assetTier, 'unlisted')) {
|
|
29
|
+
return 4;
|
|
30
|
+
} else {
|
|
31
|
+
return 5;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function perpTierIsAsSafeAs(
|
|
36
|
+
perpTier: number,
|
|
37
|
+
otherPerpTier: number,
|
|
38
|
+
otherSpotTier: number
|
|
39
|
+
): boolean {
|
|
40
|
+
const asSafeAsPerp = perpTier <= otherPerpTier;
|
|
41
|
+
const asSafeAsSpot =
|
|
42
|
+
otherSpotTier === 4 || (otherSpotTier >= 2 && perpTier <= 2);
|
|
43
|
+
return asSafeAsSpot && asSafeAsPerp;
|
|
44
|
+
}
|
package/src/user.ts
CHANGED
|
@@ -72,6 +72,7 @@ import {
|
|
|
72
72
|
} from './math/spotPosition';
|
|
73
73
|
|
|
74
74
|
import { calculateLiveOracleTwap } from './math/oracles';
|
|
75
|
+
import { getPerpMarketTierNumber, getSpotMarketTierNumber } from './math/tiers';
|
|
75
76
|
|
|
76
77
|
export class User {
|
|
77
78
|
driftClient: DriftClient;
|
|
@@ -492,6 +493,12 @@ export class User {
|
|
|
492
493
|
);
|
|
493
494
|
}
|
|
494
495
|
|
|
496
|
+
public getActiveSpotPositions(): SpotPosition[] {
|
|
497
|
+
return this.getUserAccount().spotPositions.filter(
|
|
498
|
+
(pos) => !isSpotPositionAvailable(pos)
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
495
502
|
/**
|
|
496
503
|
* calculates unrealized position price pnl
|
|
497
504
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -1437,24 +1444,29 @@ export class User {
|
|
|
1437
1444
|
return netAssetValue.mul(TEN_THOUSAND).div(totalLiabilityValue);
|
|
1438
1445
|
}
|
|
1439
1446
|
|
|
1440
|
-
public canBeLiquidated():
|
|
1447
|
+
public canBeLiquidated(): {
|
|
1448
|
+
canBeLiquidated: boolean;
|
|
1449
|
+
marginRequirement: BN;
|
|
1450
|
+
totalCollateral: BN;
|
|
1451
|
+
} {
|
|
1441
1452
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
1442
1453
|
|
|
1443
1454
|
// if user being liq'd, can continue to be liq'd until total collateral above the margin requirement plus buffer
|
|
1444
1455
|
let liquidationBuffer = undefined;
|
|
1445
|
-
|
|
1446
|
-
this.getUserAccount().status,
|
|
1447
|
-
'beingLiquidated'
|
|
1448
|
-
);
|
|
1449
|
-
|
|
1450
|
-
if (isBeingLiquidated) {
|
|
1456
|
+
if (this.isBeingLiquidated()) {
|
|
1451
1457
|
liquidationBuffer = new BN(
|
|
1452
1458
|
this.driftClient.getStateAccount().liquidationMarginBufferRatio
|
|
1453
1459
|
);
|
|
1454
1460
|
}
|
|
1455
|
-
const
|
|
1461
|
+
const marginRequirement =
|
|
1456
1462
|
this.getMaintenanceMarginRequirement(liquidationBuffer);
|
|
1457
|
-
|
|
1463
|
+
const canBeLiquidated = totalCollateral.lt(marginRequirement);
|
|
1464
|
+
|
|
1465
|
+
return {
|
|
1466
|
+
canBeLiquidated,
|
|
1467
|
+
marginRequirement,
|
|
1468
|
+
totalCollateral,
|
|
1469
|
+
};
|
|
1458
1470
|
}
|
|
1459
1471
|
|
|
1460
1472
|
public isBeingLiquidated(): boolean {
|
|
@@ -2306,6 +2318,38 @@ export class User {
|
|
|
2306
2318
|
return true;
|
|
2307
2319
|
}
|
|
2308
2320
|
|
|
2321
|
+
public getSafestTiers(): { perpTier: number; spotTier: number } {
|
|
2322
|
+
let safestPerpTier = 4;
|
|
2323
|
+
let safestSpotTier = 4;
|
|
2324
|
+
|
|
2325
|
+
for (const perpPosition of this.getActivePerpPositions()) {
|
|
2326
|
+
safestPerpTier = Math.min(
|
|
2327
|
+
safestPerpTier,
|
|
2328
|
+
getPerpMarketTierNumber(
|
|
2329
|
+
this.driftClient.getPerpMarketAccount(perpPosition.marketIndex)
|
|
2330
|
+
)
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
for (const spotPosition of this.getActiveSpotPositions()) {
|
|
2335
|
+
if (isVariant(spotPosition.balanceType, 'deposit')) {
|
|
2336
|
+
continue;
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
safestSpotTier = Math.min(
|
|
2340
|
+
safestSpotTier,
|
|
2341
|
+
getSpotMarketTierNumber(
|
|
2342
|
+
this.driftClient.getSpotMarketAccount(spotPosition.marketIndex)
|
|
2343
|
+
)
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
return {
|
|
2348
|
+
perpTier: safestPerpTier,
|
|
2349
|
+
spotTier: safestSpotTier,
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2309
2353
|
/**
|
|
2310
2354
|
* Get the total position value, excluding any position coming from the given target market
|
|
2311
2355
|
* @param marketToIgnore
|
|
@@ -2347,6 +2391,7 @@ export class User {
|
|
|
2347
2391
|
|
|
2348
2392
|
return oracleData;
|
|
2349
2393
|
}
|
|
2394
|
+
|
|
2350
2395
|
private getOracleDataForSpotMarket(marketIndex: number): OraclePriceData {
|
|
2351
2396
|
const oracleKey = this.driftClient.getSpotMarketAccount(marketIndex).oracle;
|
|
2352
2397
|
|