@drift-labs/sdk 2.60.0-beta.6 → 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 CHANGED
@@ -1 +1 @@
1
- 2.60.0-beta.6
1
+ 2.60.0-beta.7
@@ -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
- amount = typeof amount === 'number' ? new anchor_1.BN(amount) : amount;
798
- return amount.mul(numericConstants_1.BASE_PRECISION);
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
- amount = typeof amount === 'number' ? new anchor_1.BN(amount) : amount;
806
- return amount.mul(numericConstants_1.PRICE_PRECISION);
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.
@@ -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(value * Math.pow(10, spotMarket.decimals));
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)));
@@ -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
- data: {
97
- getStakePoolStats: {
98
- tvl: {
99
- data: number;
100
- date: string;
101
- }[];
102
- supply: {
103
- data: number;
104
- date: string;
105
- }[];
106
- apy: {
107
- data: number;
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 = {
@@ -151,42 +151,35 @@ async function findBestLstSuperStakeIxs({ amount, jupiterClient, driftClient, us
151
151
  };
152
152
  }
153
153
  exports.findBestLstSuperStakeIxs = findBestLstSuperStakeIxs;
154
- const JITO_SOL_START_DATE = '2022-10-31T00:00:00Z';
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
- operationName: 'QueryRoot',
159
- variables: {
160
- request: {
161
- bucketType: 'DAILY',
162
- rangeFilter: {
163
- start: JITO_SOL_START_DATE,
164
- end: new Date().toISOString(),
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.data.getStakePoolStats.supply.length; i++) {
209
- const priceInSol = data.data.getStakePoolStats.tvl[i].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.data.getStakePoolStats.tvl[i].date,
205
+ ts: data.tvl[i].date,
215
206
  });
216
207
  }
217
208
  for (const timestamp of timestamps) {
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.60.0-beta.6",
3
+ "version": "2.60.0-beta.7",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -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
- amount = typeof amount === 'number' ? new BN(amount) : amount;
1343
- return amount.mul(BASE_PRECISION);
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
- amount = typeof amount === 'number' ? new BN(amount) : amount;
1352
- return amount.mul(PRICE_PRECISION);
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
  /**
@@ -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(value * Math.pow(10, spotMarket.decimals));
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
  }
@@ -267,66 +267,59 @@ export async function findBestLstSuperStakeIxs({
267
267
  }
268
268
 
269
269
  export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
270
- data: {
271
- getStakePoolStats: {
272
- tvl: {
273
- // TVL in SOL, BN
274
- data: number;
275
- date: string;
276
- }[];
277
- supply: {
278
- // jitoSOL supply
279
- data: number;
280
- date: string;
281
- }[];
282
- apy: {
283
- data: number;
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
- const JITO_SOL_START_DATE = '2022-10-31T00:00:00Z';
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('https://kobe.mainnet.jito.network/', {
294
- body: JSON.stringify({
295
- operationName: 'QueryRoot',
296
- variables: {
297
- request: {
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
- query: `
310
- query QueryRoot($request: GetStakePoolStatsRequest!) {
311
- getStakePoolStats(req: $request) {
312
- tvl {
313
- data
314
- date
315
- }
316
- apy {
317
- data
318
- date
319
- }
320
- supply {
321
- data
322
- date
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.data.getStakePoolStats.supply.length; i++) {
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.data.getStakePoolStats.tvl[i].date,
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/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
  });