@drift-labs/sdk 2.60.0-beta.5 → 2.60.0-beta.7
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/driftClient.js +13 -4
- 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/user.d.ts +1 -1
- package/lib/user.js +19 -4
- package/package.json +1 -1
- package/src/driftClient.ts +11 -4
- package/src/math/spotMarket.ts +2 -1
- package/src/math/superStake.ts +51 -61
- package/src/math/utils.ts +23 -0
- package/src/user.ts +24 -6
- package/tests/bn/test.ts +15 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.60.0-beta.
|
|
1
|
+
2.60.0-beta.7
|
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/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/user.d.ts
CHANGED
|
@@ -248,7 +248,7 @@ 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
252
|
calculateFreeCollateralDeltaForPerp(market: PerpMarketAccount, perpPosition: PerpPosition, positionBaseSizeChange: BN): BN | undefined;
|
|
253
253
|
calculateFreeCollateralDeltaForSpot(market: SpotMarketAccount, signedTokenAmount: BN): BN;
|
|
254
254
|
/**
|
package/lib/user.js
CHANGED
|
@@ -1082,10 +1082,27 @@ 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;
|
|
1091
|
+
// update free collateral to accoutn from pnl based on entry price
|
|
1092
|
+
if (!estimatedEntryPrice.eq(numericConstants_1.ZERO) && !positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
|
|
1093
|
+
const costBasis = oraclePrice
|
|
1094
|
+
.mul(positionBaseSizeChange.abs())
|
|
1095
|
+
.div(numericConstants_1.BASE_PRECISION);
|
|
1096
|
+
const newPositionValue = estimatedEntryPrice
|
|
1097
|
+
.mul(positionBaseSizeChange.abs())
|
|
1098
|
+
.div(numericConstants_1.BASE_PRECISION);
|
|
1099
|
+
if (positionBaseSizeChange.gt(numericConstants_1.ZERO)) {
|
|
1100
|
+
freeCollateral = freeCollateral.add(costBasis.sub(newPositionValue));
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
freeCollateral = freeCollateral.add(newPositionValue.sub(costBasis));
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1089
1106
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1090
1107
|
const currentPerpPosition = this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
|
|
1091
1108
|
this.getEmptyPosition(marketIndex);
|
|
@@ -1093,7 +1110,6 @@ class User {
|
|
|
1093
1110
|
if (!freeCollateralDelta) {
|
|
1094
1111
|
return new _1.BN(-1);
|
|
1095
1112
|
}
|
|
1096
|
-
const oracle = this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1097
1113
|
const spotMarketWithSameOracle = this.driftClient
|
|
1098
1114
|
.getSpotMarketAccounts()
|
|
1099
1115
|
.find((market) => market.oracle.equals(oracle));
|
|
@@ -1108,7 +1124,6 @@ class User {
|
|
|
1108
1124
|
if (freeCollateralDelta.eq(numericConstants_1.ZERO)) {
|
|
1109
1125
|
return new _1.BN(-1);
|
|
1110
1126
|
}
|
|
1111
|
-
const oraclePrice = this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1112
1127
|
const liqPriceDelta = freeCollateral
|
|
1113
1128
|
.mul(numericConstants_1.QUOTE_PRECISION)
|
|
1114
1129
|
.div(freeCollateralDelta);
|
package/package.json
CHANGED
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/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
|
}
|
package/src/math/superStake.ts
CHANGED
|
@@ -267,66 +267,59 @@ export async function findBestLstSuperStakeIxs({
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
date: string;
|
|
285
|
-
}[];
|
|
286
|
-
};
|
|
287
|
-
};
|
|
270
|
+
tvl: {
|
|
271
|
+
// TVL in SOL, BN
|
|
272
|
+
data: number;
|
|
273
|
+
date: string;
|
|
274
|
+
}[];
|
|
275
|
+
supply: {
|
|
276
|
+
// jitoSOL supply
|
|
277
|
+
data: number;
|
|
278
|
+
date: string;
|
|
279
|
+
}[];
|
|
280
|
+
apy: {
|
|
281
|
+
data: number;
|
|
282
|
+
date: string;
|
|
283
|
+
}[];
|
|
288
284
|
};
|
|
289
285
|
|
|
290
|
-
|
|
286
|
+
/**
|
|
287
|
+
* Removes hours, minutes, seconds from a date, and returns the ISO string value (with milliseconds trimmed from the output (required by Jito API))
|
|
288
|
+
* @param inDate
|
|
289
|
+
* @returns
|
|
290
|
+
*/
|
|
291
|
+
const getNormalizedDateString = (inDate: Date) => {
|
|
292
|
+
const date = new Date(inDate.getTime());
|
|
293
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
294
|
+
return date.toISOString().slice(0, 19) + 'Z';
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const get30DAgo = () => {
|
|
298
|
+
const date = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
|
299
|
+
return date;
|
|
300
|
+
};
|
|
291
301
|
|
|
292
302
|
export async function fetchJitoSolMetrics() {
|
|
293
|
-
const res = await fetch(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
bucketType: 'DAILY',
|
|
299
|
-
rangeFilter: {
|
|
300
|
-
start: JITO_SOL_START_DATE,
|
|
301
|
-
end: new Date().toISOString(),
|
|
302
|
-
},
|
|
303
|
-
sortBy: {
|
|
304
|
-
order: 'ASC',
|
|
305
|
-
field: 'BLOCK_TIME',
|
|
306
|
-
},
|
|
307
|
-
},
|
|
303
|
+
const res = await fetch(
|
|
304
|
+
'https://kobe.mainnet.jito.network/api/v1/stake_pool_stats',
|
|
305
|
+
{
|
|
306
|
+
headers: {
|
|
307
|
+
'Content-Type': 'application/json',
|
|
308
308
|
},
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
`,
|
|
327
|
-
}),
|
|
328
|
-
method: 'POST',
|
|
329
|
-
});
|
|
309
|
+
body: JSON.stringify({
|
|
310
|
+
bucket_type: 'Daily',
|
|
311
|
+
range_filter: {
|
|
312
|
+
start: getNormalizedDateString(get30DAgo()),
|
|
313
|
+
end: getNormalizedDateString(new Date()),
|
|
314
|
+
},
|
|
315
|
+
sort_by: {
|
|
316
|
+
order: 'Asc',
|
|
317
|
+
field: 'BlockTime',
|
|
318
|
+
},
|
|
319
|
+
}),
|
|
320
|
+
method: 'POST',
|
|
321
|
+
}
|
|
322
|
+
);
|
|
330
323
|
|
|
331
324
|
const data: JITO_SOL_METRICS_ENDPOINT_RESPONSE = await res.json();
|
|
332
325
|
|
|
@@ -396,14 +389,11 @@ const getJitoSolHistoricalPriceMap = async (timestamps: number[]) => {
|
|
|
396
389
|
const jitoSolHistoricalPriceMap = new Map<number, number>();
|
|
397
390
|
const jitoSolHistoricalPriceInSol = [];
|
|
398
391
|
|
|
399
|
-
for (let i = 0; i < data.
|
|
400
|
-
const priceInSol =
|
|
401
|
-
data.data.getStakePoolStats.tvl[i].data /
|
|
402
|
-
10 ** 9 /
|
|
403
|
-
data.data.getStakePoolStats.supply[i].data;
|
|
392
|
+
for (let i = 0; i < data.supply.length; i++) {
|
|
393
|
+
const priceInSol = data.tvl[i].data / 10 ** 9 / data.supply[i].data;
|
|
404
394
|
jitoSolHistoricalPriceInSol.push({
|
|
405
395
|
price: priceInSol,
|
|
406
|
-
ts: data.
|
|
396
|
+
ts: data.tvl[i].date,
|
|
407
397
|
});
|
|
408
398
|
}
|
|
409
399
|
|
package/src/math/utils.ts
CHANGED
|
@@ -95,3 +95,26 @@ export const checkSameDate = (dateString1: string, dateString2: string) => {
|
|
|
95
95
|
|
|
96
96
|
return isSameDate;
|
|
97
97
|
};
|
|
98
|
+
|
|
99
|
+
export function isBNSafe(number: number): boolean {
|
|
100
|
+
return number <= 0x1fffffffffffff;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 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)
|
|
105
|
+
* @param number the number to convert to BN
|
|
106
|
+
* @param precision the BN precision to use (i.e. QUOTE_PRECISION and BASE_PRECISION from drift sdk)
|
|
107
|
+
*/
|
|
108
|
+
export function numberToSafeBN(number: number, precision: BN): BN {
|
|
109
|
+
// check if number has decimals
|
|
110
|
+
const candidate = number * precision.toNumber();
|
|
111
|
+
if (isBNSafe(candidate)) {
|
|
112
|
+
return new BN(candidate);
|
|
113
|
+
} else {
|
|
114
|
+
if (number % 1 === 0) {
|
|
115
|
+
return new BN(number.toString()).mul(precision);
|
|
116
|
+
} else {
|
|
117
|
+
return new BN(number).mul(precision);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/user.ts
CHANGED
|
@@ -1973,15 +1973,37 @@ export class User {
|
|
|
1973
1973
|
*/
|
|
1974
1974
|
public liquidationPrice(
|
|
1975
1975
|
marketIndex: number,
|
|
1976
|
-
positionBaseSizeChange: BN = ZERO
|
|
1976
|
+
positionBaseSizeChange: BN = ZERO,
|
|
1977
|
+
estimatedEntryPrice: BN = ZERO
|
|
1977
1978
|
): BN {
|
|
1978
1979
|
const totalCollateral = this.getTotalCollateral('Maintenance');
|
|
1979
1980
|
const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
|
|
1980
|
-
|
|
1981
|
+
let freeCollateral = BN.max(
|
|
1981
1982
|
ZERO,
|
|
1982
1983
|
totalCollateral.sub(maintenanceMarginRequirement)
|
|
1983
1984
|
);
|
|
1984
1985
|
|
|
1986
|
+
const oracle =
|
|
1987
|
+
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
1988
|
+
|
|
1989
|
+
const oraclePrice =
|
|
1990
|
+
this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
1991
|
+
|
|
1992
|
+
// update free collateral to accoutn from pnl based on entry price
|
|
1993
|
+
if (!estimatedEntryPrice.eq(ZERO) && !positionBaseSizeChange.eq(ZERO)) {
|
|
1994
|
+
const costBasis = oraclePrice
|
|
1995
|
+
.mul(positionBaseSizeChange.abs())
|
|
1996
|
+
.div(BASE_PRECISION);
|
|
1997
|
+
const newPositionValue = estimatedEntryPrice
|
|
1998
|
+
.mul(positionBaseSizeChange.abs())
|
|
1999
|
+
.div(BASE_PRECISION);
|
|
2000
|
+
if (positionBaseSizeChange.gt(ZERO)) {
|
|
2001
|
+
freeCollateral = freeCollateral.add(costBasis.sub(newPositionValue));
|
|
2002
|
+
} else {
|
|
2003
|
+
freeCollateral = freeCollateral.add(newPositionValue.sub(costBasis));
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
|
|
1985
2007
|
const market = this.driftClient.getPerpMarketAccount(marketIndex);
|
|
1986
2008
|
const currentPerpPosition =
|
|
1987
2009
|
this.getPerpPositionWithLPSettle(marketIndex, undefined, true)[0] ||
|
|
@@ -1997,8 +2019,6 @@ export class User {
|
|
|
1997
2019
|
return new BN(-1);
|
|
1998
2020
|
}
|
|
1999
2021
|
|
|
2000
|
-
const oracle =
|
|
2001
|
-
this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
2002
2022
|
const spotMarketWithSameOracle = this.driftClient
|
|
2003
2023
|
.getSpotMarketAccounts()
|
|
2004
2024
|
.find((market) => market.oracle.equals(oracle));
|
|
@@ -2031,8 +2051,6 @@ export class User {
|
|
|
2031
2051
|
return new BN(-1);
|
|
2032
2052
|
}
|
|
2033
2053
|
|
|
2034
|
-
const oraclePrice =
|
|
2035
|
-
this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
|
|
2036
2054
|
const liqPriceDelta = freeCollateral
|
|
2037
2055
|
.mul(QUOTE_PRECISION)
|
|
2038
2056
|
.div(freeCollateralDelta);
|
package/tests/bn/test.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { BN } from '../../src/index';
|
|
1
|
+
import { BN, numberToSafeBN } from '../../src/index';
|
|
2
2
|
import { expect } from 'chai';
|
|
3
3
|
import { BigNum } from '../../src/factory/bigNum';
|
|
4
4
|
import {
|
|
5
5
|
AMM_RESERVE_PRECISION_EXP,
|
|
6
|
+
BASE_PRECISION,
|
|
6
7
|
BASE_PRECISION_EXP,
|
|
7
8
|
TEN_THOUSAND,
|
|
8
9
|
} from '../../src/constants/numericConstants';
|
|
@@ -324,4 +325,17 @@ describe('BigNum Tests', () => {
|
|
|
324
325
|
const val6 = BigNum.from('0', 5);
|
|
325
326
|
expect(val6.toRounded(3).print()).to.equal('0.00000');
|
|
326
327
|
});
|
|
328
|
+
|
|
329
|
+
it('test numberToSafeBN', async () => {
|
|
330
|
+
expect(
|
|
331
|
+
numberToSafeBN(32445073.479281776, BASE_PRECISION).toString()
|
|
332
|
+
).to.equal(new BN('32445073000000000').toString());
|
|
333
|
+
expect(
|
|
334
|
+
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
|
|
335
|
+
numberToSafeBN(9999999999111111111, BASE_PRECISION).toString()
|
|
336
|
+
).to.equal(new BN('9999999999111110000000000000').toString());
|
|
337
|
+
expect(numberToSafeBN(123, BASE_PRECISION).toString()).to.equal(
|
|
338
|
+
new BN('123000000000').toString()
|
|
339
|
+
);
|
|
340
|
+
});
|
|
327
341
|
});
|