@drift-labs/sdk 2.60.0-beta.1 → 2.60.0-beta.11
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/constants/perpMarkets.js +10 -0
- package/lib/constants/spotMarkets.d.ts +1 -0
- package/lib/constants/spotMarkets.js +13 -0
- package/lib/driftClient.js +13 -4
- package/lib/idl/drift.json +6 -4
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/spotMarket.js +2 -1
- package/lib/math/superStake.d.ts +12 -16
- package/lib/math/superStake.js +29 -38
- package/lib/math/utils.d.ts +7 -0
- package/lib/math/utils.js +26 -1
- package/lib/types.d.ts +6 -0
- package/lib/types.js +4 -0
- package/lib/user.d.ts +3 -2
- package/lib/user.js +50 -6
- package/package.json +1 -1
- package/src/constants/perpMarkets.ts +10 -0
- package/src/constants/spotMarkets.ts +20 -0
- package/src/driftClient.ts +11 -4
- package/src/idl/drift.json +6 -4
- package/src/index.ts +1 -0
- package/src/math/spotMarket.ts +2 -1
- package/src/math/superStake.ts +51 -61
- package/src/math/utils.ts +23 -0
- package/src/types.ts +4 -0
- package/src/user.ts +105 -8
- package/tests/amm/test.ts +6 -1
- package/tests/bn/test.ts +15 -1
- package/examples/phoenix.ts +0 -66
- package/lib/examples/loadDlob.d.ts +0 -1
- package/lib/examples/loadDlob.js +0 -59
- package/lib/examples/makeTradeExample.d.ts +0 -2
- package/lib/examples/makeTradeExample.js +0 -83
- package/src/examples/loadDlob.ts +0 -86
- package/src/examples/makeTradeExample.ts +0 -162
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.60.0-beta.
|
|
1
|
+
2.60.0-beta.11
|
|
@@ -486,6 +486,16 @@ exports.MainnetPerpMarkets = [
|
|
|
486
486
|
launchTs: 1706219971000,
|
|
487
487
|
oracleSource: __1.OracleSource.PYTH,
|
|
488
488
|
},
|
|
489
|
+
{
|
|
490
|
+
fullName: 'JUP',
|
|
491
|
+
category: ['Exchange', 'Infra'],
|
|
492
|
+
symbol: 'JUP-PERP',
|
|
493
|
+
baseAssetSymbol: 'JUP',
|
|
494
|
+
marketIndex: 24,
|
|
495
|
+
oracle: new web3_js_1.PublicKey('g6eRCbboSwK4tSWngn773RCMexr1APQr4uA9bGZBYfo'),
|
|
496
|
+
launchTs: 1706713201000,
|
|
497
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
498
|
+
},
|
|
489
499
|
];
|
|
490
500
|
exports.PerpMarkets = {
|
|
491
501
|
devnet: exports.DevnetPerpMarkets,
|
|
@@ -139,6 +139,7 @@ exports.MainnetSpotMarkets = [
|
|
|
139
139
|
precision: new __1.BN(10).pow(numericConstants_1.NINE),
|
|
140
140
|
precisionExp: numericConstants_1.NINE,
|
|
141
141
|
serumMarket: new web3_js_1.PublicKey('H87FfmHABiZLRGrDsXRZtqq25YpARzaokCzL1vMYGiep'),
|
|
142
|
+
phoenixMarket: new web3_js_1.PublicKey('BRLLmdtPGuuFn3BU6orYw4KHaohAEptBToi3dwRUnHQZ'),
|
|
142
143
|
},
|
|
143
144
|
{
|
|
144
145
|
symbol: 'WIF',
|
|
@@ -149,6 +150,18 @@ exports.MainnetSpotMarkets = [
|
|
|
149
150
|
precision: new __1.BN(10).pow(numericConstants_1.SIX),
|
|
150
151
|
precisionExp: numericConstants_1.SIX,
|
|
151
152
|
serumMarket: new web3_js_1.PublicKey('2BtDHBTCTUxvdur498ZEcMgimasaFrY5GzLv8wS8XgCb'),
|
|
153
|
+
phoenixMarket: new web3_js_1.PublicKey('6ojSigXF7nDPyhFRgmn3V9ywhYseKF9J32ZrranMGVSX'),
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
symbol: 'JUP',
|
|
157
|
+
marketIndex: 11,
|
|
158
|
+
oracle: new web3_js_1.PublicKey('g6eRCbboSwK4tSWngn773RCMexr1APQr4uA9bGZBYfo'),
|
|
159
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
160
|
+
mint: new web3_js_1.PublicKey('JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN'),
|
|
161
|
+
precision: new __1.BN(10).pow(numericConstants_1.SIX),
|
|
162
|
+
precisionExp: numericConstants_1.SIX,
|
|
163
|
+
phoenixMarket: new web3_js_1.PublicKey('2pspvjWWaf3dNgt3jsgSzFCNvMGPb7t8FrEYvLGjvcCe'),
|
|
164
|
+
launchTs: 1706731200000,
|
|
152
165
|
},
|
|
153
166
|
];
|
|
154
167
|
exports.SpotMarkets = {
|
package/lib/driftClient.js
CHANGED
|
@@ -55,6 +55,7 @@ const spotMarket_1 = require("./math/spotMarket");
|
|
|
55
55
|
const memcmp_1 = require("./memcmp");
|
|
56
56
|
const marinade_1 = require("./marinade");
|
|
57
57
|
const orderParams_1 = require("./orderParams");
|
|
58
|
+
const utils_2 = require("./math/utils");
|
|
58
59
|
/**
|
|
59
60
|
* # DriftClient
|
|
60
61
|
* This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
|
|
@@ -794,16 +795,24 @@ class DriftClient {
|
|
|
794
795
|
* @param amount
|
|
795
796
|
*/
|
|
796
797
|
convertToPerpPrecision(amount) {
|
|
797
|
-
|
|
798
|
-
|
|
798
|
+
if (typeof amount === 'number') {
|
|
799
|
+
return (0, utils_2.numberToSafeBN)(amount, numericConstants_1.BASE_PRECISION);
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
return amount.mul(numericConstants_1.BASE_PRECISION);
|
|
803
|
+
}
|
|
799
804
|
}
|
|
800
805
|
/**
|
|
801
806
|
* Converts an amount to the price precision. The perp market precision is {@link PRICE_PRECISION} (1e6).
|
|
802
807
|
* @param amount
|
|
803
808
|
*/
|
|
804
809
|
convertToPricePrecision(amount) {
|
|
805
|
-
|
|
806
|
-
|
|
810
|
+
if (typeof amount === 'number') {
|
|
811
|
+
return (0, utils_2.numberToSafeBN)(amount, numericConstants_1.PRICE_PRECISION);
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
return amount.mul(numericConstants_1.BASE_PRECISION);
|
|
815
|
+
}
|
|
807
816
|
}
|
|
808
817
|
/**
|
|
809
818
|
* Each drift instruction must include perp and sport market accounts in the ix remaining accounts.
|
package/lib/idl/drift.json
CHANGED
|
@@ -8463,6 +8463,9 @@
|
|
|
8463
8463
|
},
|
|
8464
8464
|
{
|
|
8465
8465
|
"name": "OrderFilledWithLPJit"
|
|
8466
|
+
},
|
|
8467
|
+
{
|
|
8468
|
+
"name": "DeriskLp"
|
|
8466
8469
|
}
|
|
8467
8470
|
]
|
|
8468
8471
|
}
|
|
@@ -8480,6 +8483,9 @@
|
|
|
8480
8483
|
},
|
|
8481
8484
|
{
|
|
8482
8485
|
"name": "SettleLiquidity"
|
|
8486
|
+
},
|
|
8487
|
+
{
|
|
8488
|
+
"name": "RemoveLiquidityDerisk"
|
|
8483
8489
|
}
|
|
8484
8490
|
]
|
|
8485
8491
|
}
|
|
@@ -8621,10 +8627,6 @@
|
|
|
8621
8627
|
{
|
|
8622
8628
|
"name": "Liquidation",
|
|
8623
8629
|
"fields": [
|
|
8624
|
-
{
|
|
8625
|
-
"name": "margin_buffer",
|
|
8626
|
-
"type": "u128"
|
|
8627
|
-
},
|
|
8628
8630
|
{
|
|
8629
8631
|
"name": "market_to_track_margin_requirement",
|
|
8630
8632
|
"type": {
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -119,3 +119,4 @@ __exportStar(require("./orderSubscriber/types"), exports);
|
|
|
119
119
|
__exportStar(require("./auctionSubscriber"), exports);
|
|
120
120
|
__exportStar(require("./auctionSubscriber/types"), exports);
|
|
121
121
|
__exportStar(require("./memcmp"), exports);
|
|
122
|
+
__exportStar(require("./decode/user"), exports);
|
package/lib/math/spotMarket.js
CHANGED
|
@@ -5,9 +5,10 @@ const anchor_1 = require("@coral-xyz/anchor");
|
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const spotBalance_1 = require("./spotBalance");
|
|
7
7
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
8
9
|
function castNumberToSpotPrecision(value, spotMarket) {
|
|
9
10
|
if (typeof value === 'number') {
|
|
10
|
-
return new anchor_1.BN(
|
|
11
|
+
return (0, utils_1.numberToSafeBN)(value, new anchor_1.BN(Math.pow(10, spotMarket.decimals)));
|
|
11
12
|
}
|
|
12
13
|
else {
|
|
13
14
|
return value.mul(new anchor_1.BN(Math.pow(10, spotMarket.decimals)));
|
package/lib/math/superStake.d.ts
CHANGED
|
@@ -93,22 +93,18 @@ export declare function findBestLstSuperStakeIxs({ amount, jupiterClient, driftC
|
|
|
93
93
|
method: 'jupiter' | 'marinade';
|
|
94
94
|
}>;
|
|
95
95
|
export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
date: string;
|
|
109
|
-
}[];
|
|
110
|
-
};
|
|
111
|
-
};
|
|
96
|
+
tvl: {
|
|
97
|
+
data: number;
|
|
98
|
+
date: string;
|
|
99
|
+
}[];
|
|
100
|
+
supply: {
|
|
101
|
+
data: number;
|
|
102
|
+
date: string;
|
|
103
|
+
}[];
|
|
104
|
+
apy: {
|
|
105
|
+
data: number;
|
|
106
|
+
date: string;
|
|
107
|
+
}[];
|
|
112
108
|
};
|
|
113
109
|
export declare function fetchJitoSolMetrics(): Promise<JITO_SOL_METRICS_ENDPOINT_RESPONSE>;
|
|
114
110
|
export type MSOL_METRICS_ENDPOINT_RESPONSE = {
|
package/lib/math/superStake.js
CHANGED
|
@@ -151,42 +151,35 @@ async function findBestLstSuperStakeIxs({ amount, jupiterClient, driftClient, us
|
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
exports.findBestLstSuperStakeIxs = findBestLstSuperStakeIxs;
|
|
154
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Removes hours, minutes, seconds from a date, and returns the ISO string value (with milliseconds trimmed from the output (required by Jito API))
|
|
156
|
+
* @param inDate
|
|
157
|
+
* @returns
|
|
158
|
+
*/
|
|
159
|
+
const getNormalizedDateString = (inDate) => {
|
|
160
|
+
const date = new Date(inDate.getTime());
|
|
161
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
162
|
+
return date.toISOString().slice(0, 19) + 'Z';
|
|
163
|
+
};
|
|
164
|
+
const get30DAgo = () => {
|
|
165
|
+
const date = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
166
|
+
return date;
|
|
167
|
+
};
|
|
155
168
|
async function fetchJitoSolMetrics() {
|
|
156
|
-
const res = await (0, node_fetch_1.default)('https://kobe.mainnet.jito.network/', {
|
|
169
|
+
const res = await (0, node_fetch_1.default)('https://kobe.mainnet.jito.network/api/v1/stake_pool_stats', {
|
|
170
|
+
headers: {
|
|
171
|
+
'Content-Type': 'application/json',
|
|
172
|
+
},
|
|
157
173
|
body: JSON.stringify({
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
sortBy: {
|
|
167
|
-
order: 'ASC',
|
|
168
|
-
field: 'BLOCK_TIME',
|
|
169
|
-
},
|
|
170
|
-
},
|
|
174
|
+
bucket_type: 'Daily',
|
|
175
|
+
range_filter: {
|
|
176
|
+
start: getNormalizedDateString(get30DAgo()),
|
|
177
|
+
end: getNormalizedDateString(new Date()),
|
|
178
|
+
},
|
|
179
|
+
sort_by: {
|
|
180
|
+
order: 'Asc',
|
|
181
|
+
field: 'BlockTime',
|
|
171
182
|
},
|
|
172
|
-
query: `
|
|
173
|
-
query QueryRoot($request: GetStakePoolStatsRequest!) {
|
|
174
|
-
getStakePoolStats(req: $request) {
|
|
175
|
-
tvl {
|
|
176
|
-
data
|
|
177
|
-
date
|
|
178
|
-
}
|
|
179
|
-
apy {
|
|
180
|
-
data
|
|
181
|
-
date
|
|
182
|
-
}
|
|
183
|
-
supply {
|
|
184
|
-
data
|
|
185
|
-
date
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
`,
|
|
190
183
|
}),
|
|
191
184
|
method: 'POST',
|
|
192
185
|
});
|
|
@@ -205,13 +198,11 @@ const getJitoSolHistoricalPriceMap = async (timestamps) => {
|
|
|
205
198
|
const data = await fetchJitoSolMetrics();
|
|
206
199
|
const jitoSolHistoricalPriceMap = new Map();
|
|
207
200
|
const jitoSolHistoricalPriceInSol = [];
|
|
208
|
-
for (let i = 0; i < data.
|
|
209
|
-
const priceInSol = data.
|
|
210
|
-
10 ** 9 /
|
|
211
|
-
data.data.getStakePoolStats.supply[i].data;
|
|
201
|
+
for (let i = 0; i < data.supply.length; i++) {
|
|
202
|
+
const priceInSol = data.tvl[i].data / 10 ** 9 / data.supply[i].data;
|
|
212
203
|
jitoSolHistoricalPriceInSol.push({
|
|
213
204
|
price: priceInSol,
|
|
214
|
-
ts: data.
|
|
205
|
+
ts: data.tvl[i].date,
|
|
215
206
|
});
|
|
216
207
|
}
|
|
217
208
|
for (const timestamp of timestamps) {
|
package/lib/math/utils.d.ts
CHANGED
|
@@ -14,3 +14,10 @@ export declare const sigNum: (x: BN) => BN;
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function timeRemainingUntilUpdate(now: BN, lastUpdateTs: BN, updatePeriod: BN): BN;
|
|
16
16
|
export declare const checkSameDate: (dateString1: string, dateString2: string) => boolean;
|
|
17
|
+
export declare function isBNSafe(number: number): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Converts a number to BN makes sure the number is safe to convert to BN (that it does not overflow number after multiplying by precision)
|
|
20
|
+
* @param number the number to convert to BN
|
|
21
|
+
* @param precision the BN precision to use (i.e. QUOTE_PRECISION and BASE_PRECISION from drift sdk)
|
|
22
|
+
*/
|
|
23
|
+
export declare function numberToSafeBN(number: number, precision: BN): BN;
|
package/lib/math/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkSameDate = exports.timeRemainingUntilUpdate = exports.sigNum = exports.divCeil = exports.squareRootBN = exports.clampBN = void 0;
|
|
3
|
+
exports.numberToSafeBN = exports.isBNSafe = exports.checkSameDate = exports.timeRemainingUntilUpdate = exports.sigNum = exports.divCeil = exports.squareRootBN = exports.clampBN = void 0;
|
|
4
4
|
const __1 = require("../");
|
|
5
5
|
function clampBN(x, min, max) {
|
|
6
6
|
return __1.BN.max(min, __1.BN.min(x, max));
|
|
@@ -85,3 +85,28 @@ const checkSameDate = (dateString1, dateString2) => {
|
|
|
85
85
|
return isSameDate;
|
|
86
86
|
};
|
|
87
87
|
exports.checkSameDate = checkSameDate;
|
|
88
|
+
function isBNSafe(number) {
|
|
89
|
+
return number <= 0x1fffffffffffff;
|
|
90
|
+
}
|
|
91
|
+
exports.isBNSafe = isBNSafe;
|
|
92
|
+
/**
|
|
93
|
+
* Converts a number to BN makes sure the number is safe to convert to BN (that it does not overflow number after multiplying by precision)
|
|
94
|
+
* @param number the number to convert to BN
|
|
95
|
+
* @param precision the BN precision to use (i.e. QUOTE_PRECISION and BASE_PRECISION from drift sdk)
|
|
96
|
+
*/
|
|
97
|
+
function numberToSafeBN(number, precision) {
|
|
98
|
+
// check if number has decimals
|
|
99
|
+
const candidate = number * precision.toNumber();
|
|
100
|
+
if (isBNSafe(candidate)) {
|
|
101
|
+
return new __1.BN(candidate);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
if (number % 1 === 0) {
|
|
105
|
+
return new __1.BN(number.toString()).mul(precision);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
return new __1.BN(number).mul(precision);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.numberToSafeBN = numberToSafeBN;
|
package/lib/types.d.ts
CHANGED
|
@@ -252,6 +252,9 @@ export declare class OrderActionExplanation {
|
|
|
252
252
|
static readonly REDUCE_ONLY_ORDER_INCREASED_POSITION: {
|
|
253
253
|
reduceOnlyOrderIncreasedPosition: {};
|
|
254
254
|
};
|
|
255
|
+
static readonly DERISK_LP: {
|
|
256
|
+
deriskLp: {};
|
|
257
|
+
};
|
|
255
258
|
}
|
|
256
259
|
export declare class OrderTriggerCondition {
|
|
257
260
|
static readonly ABOVE: {
|
|
@@ -447,6 +450,9 @@ export declare class LPAction {
|
|
|
447
450
|
static readonly SETTLE_LIQUIDITY: {
|
|
448
451
|
settleLiquidity: {};
|
|
449
452
|
};
|
|
453
|
+
static readonly REMOVE_LIQUIDITY_DERISK: {
|
|
454
|
+
removeLiquidityDerisk: {};
|
|
455
|
+
};
|
|
450
456
|
}
|
|
451
457
|
export type FundingRateRecord = {
|
|
452
458
|
ts: BN;
|
package/lib/types.js
CHANGED
|
@@ -175,6 +175,9 @@ OrderActionExplanation.ORDER_FILLED_WITH_PHOENIX = {
|
|
|
175
175
|
OrderActionExplanation.REDUCE_ONLY_ORDER_INCREASED_POSITION = {
|
|
176
176
|
reduceOnlyOrderIncreasedPosition: {},
|
|
177
177
|
};
|
|
178
|
+
OrderActionExplanation.DERISK_LP = {
|
|
179
|
+
deriskLp: {},
|
|
180
|
+
};
|
|
178
181
|
class OrderTriggerCondition {
|
|
179
182
|
}
|
|
180
183
|
exports.OrderTriggerCondition = OrderTriggerCondition;
|
|
@@ -243,6 +246,7 @@ exports.LPAction = LPAction;
|
|
|
243
246
|
LPAction.ADD_LIQUIDITY = { addLiquidity: {} };
|
|
244
247
|
LPAction.REMOVE_LIQUIDITY = { removeLiquidity: {} };
|
|
245
248
|
LPAction.SETTLE_LIQUIDITY = { settleLiquidity: {} };
|
|
249
|
+
LPAction.REMOVE_LIQUIDITY_DERISK = { removeLiquidityDerisk: {} };
|
|
246
250
|
class LiquidationType {
|
|
247
251
|
}
|
|
248
252
|
exports.LiquidationType = LiquidationType;
|
package/lib/user.d.ts
CHANGED
|
@@ -248,7 +248,8 @@ export declare class User {
|
|
|
248
248
|
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
249
249
|
* @returns Precision : PRICE_PRECISION
|
|
250
250
|
*/
|
|
251
|
-
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN): BN;
|
|
251
|
+
liquidationPrice(marketIndex: number, positionBaseSizeChange?: BN, estimatedEntryPrice?: BN): BN;
|
|
252
|
+
calculateEntriesEffectOnFreeCollateral(market: PerpMarketAccount, oraclePrice: BN, perpPosition: PerpPosition, positionBaseSizeChange: BN, estimatedEntryPrice: BN): BN;
|
|
252
253
|
calculateFreeCollateralDeltaForPerp(market: PerpMarketAccount, perpPosition: PerpPosition, positionBaseSizeChange: BN): BN | undefined;
|
|
253
254
|
calculateFreeCollateralDeltaForSpot(market: SpotMarketAccount, signedTokenAmount: BN): BN;
|
|
254
255
|
/**
|
|
@@ -257,7 +258,7 @@ export declare class User {
|
|
|
257
258
|
* @param closeQuoteAmount
|
|
258
259
|
* @returns : Precision PRICE_PRECISION
|
|
259
260
|
*/
|
|
260
|
-
liquidationPriceAfterClose(positionMarketIndex: number, closeQuoteAmount: BN): BN;
|
|
261
|
+
liquidationPriceAfterClose(positionMarketIndex: number, closeQuoteAmount: BN, estimatedEntryPrice?: BN): BN;
|
|
261
262
|
/**
|
|
262
263
|
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
|
|
263
264
|
*
|
package/lib/user.js
CHANGED
|
@@ -1082,18 +1082,22 @@ class User {
|
|
|
1082
1082
|
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
1083
1083
|
* @returns Precision : PRICE_PRECISION
|
|
1084
1084
|
*/
|
|
1085
|
-
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO) {
|
|
1085
|
+
liquidationPrice(marketIndex, positionBaseSizeChange = numericConstants_1.ZERO, estimatedEntryPrice = numericConstants_1.ZERO) {
|
|
1086
1086
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
1087
1087
|
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
1088
|
-
|
|
1088
|
+
let freeCollateral = _1.BN.max(numericConstants_1.ZERO, totalCollateral.sub(maintenanceMarginRequirement));
|
|
1089
|
+
const oracle = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1090
|
+
const oraclePrice = this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1089
1091
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1090
1092
|
const currentPerpPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
|
|
1091
1093
|
this.getEmptyPosition(marketIndex);
|
|
1094
|
+
positionBaseSizeChange = (0, _1.standardizeBaseAssetAmount)(positionBaseSizeChange, market.amm.orderStepSize);
|
|
1095
|
+
const freeCollateralChangeFromNewPosition = this.calculateEntriesEffectOnFreeCollateral(market, oraclePrice, currentPerpPosition, positionBaseSizeChange, estimatedEntryPrice);
|
|
1096
|
+
freeCollateral = freeCollateral.add(freeCollateralChangeFromNewPosition);
|
|
1092
1097
|
let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(market, currentPerpPosition, positionBaseSizeChange);
|
|
1093
1098
|
if (!freeCollateralDelta) {
|
|
1094
1099
|
return new _1.BN(-1);
|
|
1095
1100
|
}
|
|
1096
|
-
const oracle = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1097
1101
|
const spotMarketWithSameOracle = this.driftClient
|
|
1098
1102
|
.getSpotMarketAccounts()
|
|
1099
1103
|
.find((market) => market.oracle.equals(oracle));
|
|
@@ -1108,7 +1112,6 @@ class User {
|
|
|
1108
1112
|
if (freeCollateralDelta.eq(numericConstants_1.ZERO)) {
|
|
1109
1113
|
return new _1.BN(-1);
|
|
1110
1114
|
}
|
|
1111
|
-
const oraclePrice = this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1112
1115
|
const liqPriceDelta = freeCollateral
|
|
1113
1116
|
.mul(numericConstants_1.QUOTE_PRECISION)
|
|
1114
1117
|
.div(freeCollateralDelta);
|
|
@@ -1118,6 +1121,47 @@ class User {
|
|
|
1118
1121
|
}
|
|
1119
1122
|
return liqPrice;
|
|
1120
1123
|
}
|
|
1124
|
+
calculateEntriesEffectOnFreeCollateral(market, oraclePrice, perpPosition, positionBaseSizeChange, estimatedEntryPrice) {
|
|
1125
|
+
let freeCollateralChange = numericConstants_1.ZERO;
|
|
1126
|
+
// update free collateral to account for change in pnl from new position
|
|
1127
|
+
if (!estimatedEntryPrice.eq(numericConstants_1.ZERO) && !positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
|
|
1128
|
+
const costBasis = oraclePrice
|
|
1129
|
+
.mul(positionBaseSizeChange.abs())
|
|
1130
|
+
.div(numericConstants_1.BASE_PRECISION);
|
|
1131
|
+
const newPositionValue = estimatedEntryPrice
|
|
1132
|
+
.mul(positionBaseSizeChange.abs())
|
|
1133
|
+
.div(numericConstants_1.BASE_PRECISION);
|
|
1134
|
+
if (positionBaseSizeChange.gt(numericConstants_1.ZERO)) {
|
|
1135
|
+
freeCollateralChange = costBasis.sub(newPositionValue);
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
freeCollateralChange = newPositionValue.sub(costBasis);
|
|
1139
|
+
}
|
|
1140
|
+
// assume worst fee tier
|
|
1141
|
+
const takerFeeTier = this.driftClient.getStateAccount().perpFeeStructure.feeTiers[0];
|
|
1142
|
+
const takerFee = newPositionValue
|
|
1143
|
+
.muln(takerFeeTier.feeNumerator)
|
|
1144
|
+
.divn(takerFeeTier.feeDenominator);
|
|
1145
|
+
freeCollateralChange = freeCollateralChange.sub(takerFee);
|
|
1146
|
+
}
|
|
1147
|
+
const worstCaseBaseAssetAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition);
|
|
1148
|
+
const marginRatioBefore = (0, _1.calculateMarketMarginRatio)(market, worstCaseBaseAssetAmount.abs(), 'Maintenance');
|
|
1149
|
+
const newWorstCaseBaseAssetAmount = worstCaseBaseAssetAmount.add(positionBaseSizeChange);
|
|
1150
|
+
const newMarginRatio = (0, _1.calculateMarketMarginRatio)(market, newWorstCaseBaseAssetAmount.abs(), 'Maintenance');
|
|
1151
|
+
// update free collateral to account for change in margin ratio from position change
|
|
1152
|
+
freeCollateralChange = freeCollateralChange.sub(worstCaseBaseAssetAmount
|
|
1153
|
+
.mul(oraclePrice)
|
|
1154
|
+
.div(numericConstants_1.BASE_PRECISION)
|
|
1155
|
+
.mul(new _1.BN(newMarginRatio - marginRatioBefore))
|
|
1156
|
+
.div(numericConstants_1.MARGIN_PRECISION));
|
|
1157
|
+
// update free collateral to account for new margin requirement from position change
|
|
1158
|
+
freeCollateralChange = freeCollateralChange.sub(positionBaseSizeChange
|
|
1159
|
+
.mul(oraclePrice)
|
|
1160
|
+
.div(numericConstants_1.BASE_PRECISION)
|
|
1161
|
+
.mul(new _1.BN(newMarginRatio))
|
|
1162
|
+
.div(numericConstants_1.MARGIN_PRECISION));
|
|
1163
|
+
return freeCollateralChange;
|
|
1164
|
+
}
|
|
1121
1165
|
calculateFreeCollateralDeltaForPerp(market, perpPosition, positionBaseSizeChange) {
|
|
1122
1166
|
const currentBaseAssetAmount = perpPosition.baseAssetAmount;
|
|
1123
1167
|
const worstCaseBaseAssetAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition);
|
|
@@ -1174,7 +1218,7 @@ class User {
|
|
|
1174
1218
|
* @param closeQuoteAmount
|
|
1175
1219
|
* @returns : Precision PRICE_PRECISION
|
|
1176
1220
|
*/
|
|
1177
|
-
liquidationPriceAfterClose(positionMarketIndex, closeQuoteAmount) {
|
|
1221
|
+
liquidationPriceAfterClose(positionMarketIndex, closeQuoteAmount, estimatedEntryPrice = numericConstants_1.ZERO) {
|
|
1178
1222
|
const currentPosition = this.getPerpPositionWithLPSettle(positionMarketIndex, undefined, true)[0] || this.getEmptyPosition(positionMarketIndex);
|
|
1179
1223
|
const closeBaseAmount = currentPosition.baseAssetAmount
|
|
1180
1224
|
.mul(closeQuoteAmount)
|
|
@@ -1183,7 +1227,7 @@ class User {
|
|
|
1183
1227
|
.mul(closeQuoteAmount)
|
|
1184
1228
|
.mod(currentPosition.quoteAssetAmount.abs()))
|
|
1185
1229
|
.neg();
|
|
1186
|
-
return this.liquidationPrice(positionMarketIndex, closeBaseAmount);
|
|
1230
|
+
return this.liquidationPrice(positionMarketIndex, closeBaseAmount, estimatedEntryPrice);
|
|
1187
1231
|
}
|
|
1188
1232
|
/**
|
|
1189
1233
|
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
|
package/package.json
CHANGED
|
@@ -497,6 +497,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
497
497
|
launchTs: 1706219971000,
|
|
498
498
|
oracleSource: OracleSource.PYTH,
|
|
499
499
|
},
|
|
500
|
+
{
|
|
501
|
+
fullName: 'JUP',
|
|
502
|
+
category: ['Exchange', 'Infra'],
|
|
503
|
+
symbol: 'JUP-PERP',
|
|
504
|
+
baseAssetSymbol: 'JUP',
|
|
505
|
+
marketIndex: 24,
|
|
506
|
+
oracle: new PublicKey('g6eRCbboSwK4tSWngn773RCMexr1APQr4uA9bGZBYfo'),
|
|
507
|
+
launchTs: 1706713201000,
|
|
508
|
+
oracleSource: OracleSource.PYTH,
|
|
509
|
+
},
|
|
500
510
|
];
|
|
501
511
|
|
|
502
512
|
export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
|
|
@@ -20,6 +20,7 @@ export type SpotMarketConfig = {
|
|
|
20
20
|
precisionExp: BN;
|
|
21
21
|
serumMarket?: PublicKey;
|
|
22
22
|
phoenixMarket?: PublicKey;
|
|
23
|
+
launchTs?: number;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
export const WRAPPED_SOL_MINT = new PublicKey(
|
|
@@ -169,6 +170,9 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
|
|
|
169
170
|
precision: new BN(10).pow(NINE),
|
|
170
171
|
precisionExp: NINE,
|
|
171
172
|
serumMarket: new PublicKey('H87FfmHABiZLRGrDsXRZtqq25YpARzaokCzL1vMYGiep'),
|
|
173
|
+
phoenixMarket: new PublicKey(
|
|
174
|
+
'BRLLmdtPGuuFn3BU6orYw4KHaohAEptBToi3dwRUnHQZ'
|
|
175
|
+
),
|
|
172
176
|
},
|
|
173
177
|
{
|
|
174
178
|
symbol: 'WIF',
|
|
@@ -179,6 +183,22 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
|
|
|
179
183
|
precision: new BN(10).pow(SIX),
|
|
180
184
|
precisionExp: SIX,
|
|
181
185
|
serumMarket: new PublicKey('2BtDHBTCTUxvdur498ZEcMgimasaFrY5GzLv8wS8XgCb'),
|
|
186
|
+
phoenixMarket: new PublicKey(
|
|
187
|
+
'6ojSigXF7nDPyhFRgmn3V9ywhYseKF9J32ZrranMGVSX'
|
|
188
|
+
),
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
symbol: 'JUP',
|
|
192
|
+
marketIndex: 11,
|
|
193
|
+
oracle: new PublicKey('g6eRCbboSwK4tSWngn773RCMexr1APQr4uA9bGZBYfo'),
|
|
194
|
+
oracleSource: OracleSource.PYTH,
|
|
195
|
+
mint: new PublicKey('JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN'),
|
|
196
|
+
precision: new BN(10).pow(SIX),
|
|
197
|
+
precisionExp: SIX,
|
|
198
|
+
phoenixMarket: new PublicKey(
|
|
199
|
+
'2pspvjWWaf3dNgt3jsgSzFCNvMGPb7t8FrEYvLGjvcCe'
|
|
200
|
+
),
|
|
201
|
+
launchTs: 1706731200000,
|
|
182
202
|
},
|
|
183
203
|
];
|
|
184
204
|
|
package/src/driftClient.ts
CHANGED
|
@@ -124,6 +124,7 @@ import { getNonIdleUserFilter } from './memcmp';
|
|
|
124
124
|
import { UserStatsSubscriptionConfig } from './userStatsConfig';
|
|
125
125
|
import { getMarinadeDepositIx, getMarinadeFinanceProgram } from './marinade';
|
|
126
126
|
import { getOrderParams } from './orderParams';
|
|
127
|
+
import { numberToSafeBN } from './math/utils';
|
|
127
128
|
|
|
128
129
|
type RemainingAccountParams = {
|
|
129
130
|
userAccounts: UserAccount[];
|
|
@@ -1339,8 +1340,11 @@ export class DriftClient {
|
|
|
1339
1340
|
* @param amount
|
|
1340
1341
|
*/
|
|
1341
1342
|
public convertToPerpPrecision(amount: BN | number): BN {
|
|
1342
|
-
|
|
1343
|
-
|
|
1343
|
+
if (typeof amount === 'number') {
|
|
1344
|
+
return numberToSafeBN(amount, BASE_PRECISION);
|
|
1345
|
+
} else {
|
|
1346
|
+
return amount.mul(BASE_PRECISION);
|
|
1347
|
+
}
|
|
1344
1348
|
}
|
|
1345
1349
|
|
|
1346
1350
|
/**
|
|
@@ -1348,8 +1352,11 @@ export class DriftClient {
|
|
|
1348
1352
|
* @param amount
|
|
1349
1353
|
*/
|
|
1350
1354
|
public convertToPricePrecision(amount: BN | number): BN {
|
|
1351
|
-
|
|
1352
|
-
|
|
1355
|
+
if (typeof amount === 'number') {
|
|
1356
|
+
return numberToSafeBN(amount, PRICE_PRECISION);
|
|
1357
|
+
} else {
|
|
1358
|
+
return amount.mul(BASE_PRECISION);
|
|
1359
|
+
}
|
|
1353
1360
|
}
|
|
1354
1361
|
|
|
1355
1362
|
/**
|
package/src/idl/drift.json
CHANGED
|
@@ -8463,6 +8463,9 @@
|
|
|
8463
8463
|
},
|
|
8464
8464
|
{
|
|
8465
8465
|
"name": "OrderFilledWithLPJit"
|
|
8466
|
+
},
|
|
8467
|
+
{
|
|
8468
|
+
"name": "DeriskLp"
|
|
8466
8469
|
}
|
|
8467
8470
|
]
|
|
8468
8471
|
}
|
|
@@ -8480,6 +8483,9 @@
|
|
|
8480
8483
|
},
|
|
8481
8484
|
{
|
|
8482
8485
|
"name": "SettleLiquidity"
|
|
8486
|
+
},
|
|
8487
|
+
{
|
|
8488
|
+
"name": "RemoveLiquidityDerisk"
|
|
8483
8489
|
}
|
|
8484
8490
|
]
|
|
8485
8491
|
}
|
|
@@ -8621,10 +8627,6 @@
|
|
|
8621
8627
|
{
|
|
8622
8628
|
"name": "Liquidation",
|
|
8623
8629
|
"fields": [
|
|
8624
|
-
{
|
|
8625
|
-
"name": "margin_buffer",
|
|
8626
|
-
"type": "u128"
|
|
8627
|
-
},
|
|
8628
8630
|
{
|
|
8629
8631
|
"name": "market_to_track_margin_requirement",
|
|
8630
8632
|
"type": {
|
package/src/index.ts
CHANGED
package/src/math/spotMarket.ts
CHANGED
|
@@ -7,13 +7,14 @@ import {
|
|
|
7
7
|
} from '../types';
|
|
8
8
|
import { calculateAssetWeight, calculateLiabilityWeight } from './spotBalance';
|
|
9
9
|
import { MARGIN_PRECISION } from '../constants/numericConstants';
|
|
10
|
+
import { numberToSafeBN } from './utils';
|
|
10
11
|
|
|
11
12
|
export function castNumberToSpotPrecision(
|
|
12
13
|
value: number | BN,
|
|
13
14
|
spotMarket: SpotMarketAccount
|
|
14
15
|
): BN {
|
|
15
16
|
if (typeof value === 'number') {
|
|
16
|
-
return new BN(
|
|
17
|
+
return numberToSafeBN(value, new BN(Math.pow(10, spotMarket.decimals)));
|
|
17
18
|
} else {
|
|
18
19
|
return value.mul(new BN(Math.pow(10, spotMarket.decimals)));
|
|
19
20
|
}
|