@drift-labs/sdk 0.1.18-orders.2 → 0.1.18-orders.6

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.
Files changed (56) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +3 -4
  2. package/lib/accounts/bulkAccountLoader.js +23 -4
  3. package/lib/accounts/pollingUserAccountSubscriber.js +8 -5
  4. package/lib/accounts/types.d.ts +4 -0
  5. package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -2
  6. package/lib/accounts/webSocketAccountSubscriber.js +43 -12
  7. package/lib/clearingHouse.d.ts +4 -0
  8. package/lib/clearingHouse.js +40 -0
  9. package/lib/clearingHouseUser.d.ts +8 -3
  10. package/lib/clearingHouseUser.js +23 -20
  11. package/lib/config.js +1 -1
  12. package/lib/constants/markets.d.ts +2 -1
  13. package/lib/constants/markets.js +20 -15
  14. package/lib/constants/numericConstants.d.ts +4 -1
  15. package/lib/constants/numericConstants.js +16 -17
  16. package/lib/examples/makeTradeExample.js +1 -1
  17. package/lib/idl/clearing_house.json +8 -4
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.js +2 -5
  20. package/lib/math/conversion.d.ts +1 -1
  21. package/lib/math/insuranceFund.d.ts +2 -1
  22. package/lib/math/insuranceFund.js +3 -6
  23. package/lib/math/orders.js +2 -1
  24. package/lib/math/position.d.ts +2 -1
  25. package/lib/math/position.js +2 -5
  26. package/lib/math/utils.d.ts +2 -1
  27. package/lib/math/utils.js +3 -6
  28. package/lib/mockUSDCFaucet.d.ts +2 -1
  29. package/lib/orderParams.d.ts +2 -2
  30. package/lib/orderParams.js +7 -7
  31. package/lib/orders.d.ts +3 -2
  32. package/lib/orders.js +8 -8
  33. package/lib/types.d.ts +8 -5
  34. package/lib/types.js +2 -2
  35. package/package.json +9 -1
  36. package/src/accounts/bulkAccountLoader.ts +35 -15
  37. package/src/accounts/pollingUserAccountSubscriber.ts +13 -5
  38. package/src/accounts/types.ts +5 -0
  39. package/src/accounts/webSocketAccountSubscriber.ts +67 -17
  40. package/src/clearingHouse.ts +56 -0
  41. package/src/clearingHouseUser.ts +12 -2
  42. package/src/config.ts +1 -1
  43. package/src/constants/markets.ts +9 -1
  44. package/src/constants/numericConstants.ts +3 -1
  45. package/src/examples/makeTradeExample.ts +4 -1
  46. package/src/idl/clearing_house.json +8 -4
  47. package/src/index.ts +1 -1
  48. package/src/math/conversion.ts +1 -1
  49. package/src/math/insuranceFund.ts +1 -1
  50. package/src/math/orders.ts +4 -2
  51. package/src/math/position.ts +1 -1
  52. package/src/math/utils.ts +1 -1
  53. package/src/mockUSDCFaucet.ts +1 -1
  54. package/src/orderParams.ts +4 -4
  55. package/src/orders.ts +13 -7
  56. package/src/types.ts +5 -3
@@ -53,7 +53,7 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
53
53
  // Get current price
54
54
  const solMarketInfo = __2.Markets.find((market) => market.baseAssetSymbol === 'SOL');
55
55
  const currentMarketPrice = __2.calculateMarkPrice(clearingHouse.getMarket(solMarketInfo.marketIndex));
56
- const formattedPrice = __2.convertToNumber(currentMarketPrice, __2.QUOTE_PRECISION);
56
+ const formattedPrice = __2.convertToNumber(currentMarketPrice, __2.MARK_PRICE_PRECISION);
57
57
  console.log(`Current Market Price is $${formattedPrice}`);
58
58
  // Estimate the slippage for a $5000 LONG trade
59
59
  const solMarketAccount = clearingHouse.getMarket(solMarketInfo.marketIndex);
@@ -572,7 +572,7 @@
572
572
  },
573
573
  {
574
574
  "name": "markets",
575
- "isMut": true,
575
+ "isMut": false,
576
576
  "isSigner": false
577
577
  },
578
578
  {
@@ -628,7 +628,7 @@
628
628
  },
629
629
  {
630
630
  "name": "markets",
631
- "isMut": true,
631
+ "isMut": false,
632
632
  "isSigner": false
633
633
  },
634
634
  {
@@ -3547,6 +3547,10 @@
3547
3547
  "name": "price",
3548
3548
  "type": "u128"
3549
3549
  },
3550
+ {
3551
+ "name": "userBaseAssetAmount",
3552
+ "type": "i128"
3553
+ },
3550
3554
  {
3551
3555
  "name": "quoteAssetAmount",
3552
3556
  "type": "u128"
@@ -3734,10 +3738,10 @@
3734
3738
  "name": "Limit"
3735
3739
  },
3736
3740
  {
3737
- "name": "Stop"
3741
+ "name": "TriggerMarket"
3738
3742
  },
3739
3743
  {
3740
- "name": "StopLimit"
3744
+ "name": "TriggerLimit"
3741
3745
  }
3742
3746
  ]
3743
3747
  }
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import BN from 'bn.js';
1
+ import { BN } from '@project-serum/anchor';
2
2
  import { PublicKey } from '@solana/web3.js';
3
3
  export * from './mockUSDCFaucet';
4
4
  export * from './pythClient';
package/lib/index.js CHANGED
@@ -9,13 +9,10 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
9
9
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
10
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
11
  };
12
- var __importDefault = (this && this.__importDefault) || function (mod) {
13
- return (mod && mod.__esModule) ? mod : { "default": mod };
14
- };
15
12
  Object.defineProperty(exports, "__esModule", { value: true });
16
13
  exports.PublicKey = exports.BN = void 0;
17
- const bn_js_1 = __importDefault(require("bn.js"));
18
- exports.BN = bn_js_1.default;
14
+ const anchor_1 = require("@project-serum/anchor");
15
+ Object.defineProperty(exports, "BN", { enumerable: true, get: function () { return anchor_1.BN; } });
19
16
  const web3_js_1 = require("@solana/web3.js");
20
17
  Object.defineProperty(exports, "PublicKey", { enumerable: true, get: function () { return web3_js_1.PublicKey; } });
21
18
  __exportStar(require("./mockUSDCFaucet"), exports);
@@ -1,3 +1,3 @@
1
- import BN from 'bn.js';
1
+ import { BN } from '../';
2
2
  export declare const convertToNumber: (bigNumber: BN, precision?: BN) => number;
3
3
  export declare const convertBaseAssetAmountToNumber: (baseAssetAmount: BN) => number;
@@ -1,5 +1,6 @@
1
+ /// <reference types="bn.js" />
1
2
  import { MarketsAccount, StateAccount } from '../types';
2
- import BN from 'bn.js';
3
+ import { BN } from '../';
3
4
  import { Connection } from '@solana/web3.js';
4
5
  /**
5
6
  * In the case of a levered loss, the exchange first pays out undistributed fees and then the insurance fund.
@@ -8,12 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
12
  exports.calculateInsuranceFundSize = void 0;
16
- const bn_js_1 = __importDefault(require("bn.js"));
13
+ const __1 = require("../");
17
14
  /**
18
15
  * In the case of a levered loss, the exchange first pays out undistributed fees and then the insurance fund.
19
16
  * Thus the de facto size of the insurance fund is the amount in the insurance vault plus the sum of each markets
@@ -27,9 +24,9 @@ const bn_js_1 = __importDefault(require("bn.js"));
27
24
  function calculateInsuranceFundSize(connection, state, marketsAccount) {
28
25
  return __awaiter(this, void 0, void 0, function* () {
29
26
  const insuranceVaultPublicKey = state.insuranceVault;
30
- const insuranceVaultAmount = new bn_js_1.default((yield connection.getTokenAccountBalance(insuranceVaultPublicKey)).value.amount);
27
+ const insuranceVaultAmount = new __1.BN((yield connection.getTokenAccountBalance(insuranceVaultPublicKey)).value.amount);
31
28
  return marketsAccount.markets.reduce((insuranceVaultAmount, market) => {
32
- return insuranceVaultAmount.add(market.amm.totalFee.div(new bn_js_1.default(2)));
29
+ return insuranceVaultAmount.add(market.amm.totalFee.div(new __1.BN(2)));
33
30
  }, insuranceVaultAmount);
34
31
  });
35
32
  }
@@ -23,8 +23,9 @@ function isOrderRiskIncreasing(user, order) {
23
23
  return true;
24
24
  }
25
25
  // if order will flip position
26
- if (position.baseAssetAmount.abs().gt(order.baseAssetAmountFilled)) {
26
+ if (order.baseAssetAmountFilled.gt(position.baseAssetAmount.abs().mul(numericConstants_1.TWO))) {
27
27
  return true;
28
28
  }
29
+ return false;
29
30
  }
30
31
  exports.isOrderRiskIncreasing = isOrderRiskIncreasing;
@@ -1,4 +1,5 @@
1
- import BN from 'bn.js';
1
+ /// <reference types="bn.js" />
2
+ import { BN } from '../';
2
3
  import { Market, PositionDirection, UserPosition } from '../types';
3
4
  /**
4
5
  * calculateBaseAssetValue
@@ -1,10 +1,7 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateEntryPrice = exports.calculatePositionFundingPNL = exports.calculatePositionPNL = exports.calculateBaseAssetValue = void 0;
7
- const bn_js_1 = __importDefault(require("bn.js"));
4
+ const __1 = require("../");
8
5
  const numericConstants_1 = require("../constants/numericConstants");
9
6
  const types_1 = require("../types");
10
7
  const amm_1 = require("./amm");
@@ -84,7 +81,7 @@ function calculatePositionFundingPNL(market, marketPosition) {
84
81
  .mul(marketPosition.baseAssetAmount)
85
82
  .div(numericConstants_1.AMM_RESERVE_PRECISION)
86
83
  .div(numericConstants_1.FUNDING_PAYMENT_PRECISION)
87
- .mul(new bn_js_1.default(-1));
84
+ .mul(new __1.BN(-1));
88
85
  return perPositionFundingRate;
89
86
  }
90
87
  exports.calculatePositionFundingPNL = calculatePositionFundingPNL;
@@ -1,2 +1,3 @@
1
- import BN from 'bn.js';
1
+ /// <reference types="bn.js" />
2
+ import { BN } from '../';
2
3
  export declare const squareRootBN: (n: any, closeness?: BN) => any;
package/lib/math/utils.js CHANGED
@@ -1,18 +1,15 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.squareRootBN = void 0;
7
- const bn_js_1 = __importDefault(require("bn.js"));
8
- const squareRootBN = (n, closeness = new bn_js_1.default(1)) => {
4
+ const __1 = require("../");
5
+ const squareRootBN = (n, closeness = new __1.BN(1)) => {
9
6
  // Assuming the sqrt of n as n only
10
7
  let x = n;
11
8
  // The closed guess will be stored in the root
12
9
  let root;
13
10
  // To count the number of iterations
14
11
  let count = 0;
15
- const TWO = new bn_js_1.default(2);
12
+ const TWO = new __1.BN(2);
16
13
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
17
14
  while (count < Number.MAX_SAFE_INTEGER) {
18
15
  count++;
@@ -1,8 +1,9 @@
1
+ /// <reference types="bn.js" />
1
2
  import * as anchor from '@project-serum/anchor';
2
3
  import { Program, Provider } from '@project-serum/anchor';
3
4
  import { AccountInfo } from '@solana/spl-token';
4
5
  import { ConfirmOptions, Connection, PublicKey, TransactionInstruction, TransactionSignature } from '@solana/web3.js';
5
- import BN from 'bn.js';
6
+ import { BN } from '.';
6
7
  import { IWallet } from './types';
7
8
  export declare class MockUSDCFaucet {
8
9
  connection: Connection;
@@ -2,6 +2,6 @@
2
2
  import { OrderParams, OrderTriggerCondition, PositionDirection } from './types';
3
3
  import { BN } from '@project-serum/anchor';
4
4
  export declare function getLimitOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, price: BN, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number): OrderParams;
5
- export declare function getStopOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, triggerPrice: BN, triggerCondition: OrderTriggerCondition, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number): OrderParams;
6
- export declare function getStopLimitOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, price: BN, triggerPrice: BN, triggerCondition: OrderTriggerCondition, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number): OrderParams;
5
+ export declare function getTriggerMarketOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, triggerPrice: BN, triggerCondition: OrderTriggerCondition, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number): OrderParams;
6
+ export declare function getTriggerLimitOrderParams(marketIndex: BN, direction: PositionDirection, baseAssetAmount: BN, price: BN, triggerPrice: BN, triggerCondition: OrderTriggerCondition, reduceOnly: boolean, discountToken?: boolean, referrer?: boolean, userOrderId?: number): OrderParams;
7
7
  export declare function getMarketOrderParams(marketIndex: BN, direction: PositionDirection, quoteAssetAmount: BN, baseAssetAmount: BN, reduceOnly: boolean, price?: BN, discountToken?: boolean, referrer?: boolean): OrderParams;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMarketOrderParams = exports.getStopLimitOrderParams = exports.getStopOrderParams = exports.getLimitOrderParams = void 0;
3
+ exports.getMarketOrderParams = exports.getTriggerLimitOrderParams = exports.getTriggerMarketOrderParams = exports.getLimitOrderParams = void 0;
4
4
  const types_1 = require("./types");
5
5
  const numericConstants_1 = require("./constants/numericConstants");
6
6
  function getLimitOrderParams(marketIndex, direction, baseAssetAmount, price, reduceOnly, discountToken = false, referrer = false, userOrderId = 0) {
@@ -28,9 +28,9 @@ function getLimitOrderParams(marketIndex, direction, baseAssetAmount, price, red
28
28
  };
29
29
  }
30
30
  exports.getLimitOrderParams = getLimitOrderParams;
31
- function getStopOrderParams(marketIndex, direction, baseAssetAmount, triggerPrice, triggerCondition, reduceOnly, discountToken = false, referrer = false, userOrderId = 0) {
31
+ function getTriggerMarketOrderParams(marketIndex, direction, baseAssetAmount, triggerPrice, triggerCondition, reduceOnly, discountToken = false, referrer = false, userOrderId = 0) {
32
32
  return {
33
- orderType: types_1.OrderType.STOP,
33
+ orderType: types_1.OrderType.TRIGGER_MARKET,
34
34
  userOrderId,
35
35
  marketIndex,
36
36
  direction,
@@ -52,10 +52,10 @@ function getStopOrderParams(marketIndex, direction, baseAssetAmount, triggerPric
52
52
  oraclePriceOffset: numericConstants_1.ZERO,
53
53
  };
54
54
  }
55
- exports.getStopOrderParams = getStopOrderParams;
56
- function getStopLimitOrderParams(marketIndex, direction, baseAssetAmount, price, triggerPrice, triggerCondition, reduceOnly, discountToken = false, referrer = false, userOrderId = 0) {
55
+ exports.getTriggerMarketOrderParams = getTriggerMarketOrderParams;
56
+ function getTriggerLimitOrderParams(marketIndex, direction, baseAssetAmount, price, triggerPrice, triggerCondition, reduceOnly, discountToken = false, referrer = false, userOrderId = 0) {
57
57
  return {
58
- orderType: types_1.OrderType.STOP_LIMIT,
58
+ orderType: types_1.OrderType.TRIGGER_LIMIT,
59
59
  userOrderId,
60
60
  marketIndex,
61
61
  direction,
@@ -77,7 +77,7 @@ function getStopLimitOrderParams(marketIndex, direction, baseAssetAmount, price,
77
77
  oraclePriceOffset: numericConstants_1.ZERO,
78
78
  };
79
79
  }
80
- exports.getStopLimitOrderParams = getStopLimitOrderParams;
80
+ exports.getTriggerLimitOrderParams = getTriggerLimitOrderParams;
81
81
  function getMarketOrderParams(marketIndex, direction, quoteAssetAmount, baseAssetAmount, reduceOnly, price = numericConstants_1.ZERO, discountToken = false, referrer = false) {
82
82
  if (baseAssetAmount.eq(numericConstants_1.ZERO) && quoteAssetAmount.eq(numericConstants_1.ZERO)) {
83
83
  throw Error('baseAssetAmount or quoteAssetAmount must be zero');
package/lib/orders.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ /// <reference types="bn.js" />
1
2
  import { Market, Order, UserAccount, UserPosition } from './types';
2
- import BN from 'bn.js';
3
+ import { BN } from '.';
3
4
  export declare function calculateNewStateAfterOrder(userAccount: UserAccount, userPosition: UserPosition, market: Market, order: Order): [UserAccount, UserPosition, Market] | null;
4
5
  export declare function calculateAmountToTradeForLimit(market: Market, order: Order): BN;
5
- export declare function calculateAmountToTradeForStopLimit(market: Market, order: Order): BN;
6
+ export declare function calculateAmountToTradeForTriggerLimit(market: Market, order: Order): BN;
package/lib/orders.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateAmountToTradeForStopLimit = exports.calculateAmountToTradeForLimit = exports.calculateNewStateAfterOrder = void 0;
3
+ exports.calculateAmountToTradeForTriggerLimit = exports.calculateAmountToTradeForLimit = exports.calculateNewStateAfterOrder = void 0;
4
4
  const types_1 = require("./types");
5
5
  const market_1 = require("./math/market");
6
6
  const numericConstants_1 = require("./constants/numericConstants");
@@ -83,15 +83,15 @@ function calculateAmountToTrade(market, order) {
83
83
  if (types_1.isVariant(order.orderType, 'limit')) {
84
84
  return calculateAmountToTradeForLimit(market, order);
85
85
  }
86
- else if (types_1.isVariant(order.orderType, 'stopLimit')) {
87
- return calculateAmountToTradeForStopLimit(market, order);
86
+ else if (types_1.isVariant(order.orderType, 'triggerLimit')) {
87
+ return calculateAmountToTradeForTriggerLimit(market, order);
88
88
  }
89
89
  else if (types_1.isVariant(order.orderType, 'market')) {
90
90
  // should never be a market order queued
91
91
  return numericConstants_1.ZERO;
92
92
  }
93
93
  else {
94
- return calculateAmountToTradeForStop(market, order);
94
+ return calculateAmountToTradeForTriggerMarket(market, order);
95
95
  }
96
96
  }
97
97
  function calculateAmountToTradeForLimit(market, order) {
@@ -106,21 +106,21 @@ function calculateAmountToTradeForLimit(market, order) {
106
106
  : maxAmountToTrade;
107
107
  }
108
108
  exports.calculateAmountToTradeForLimit = calculateAmountToTradeForLimit;
109
- function calculateAmountToTradeForStopLimit(market, order) {
109
+ function calculateAmountToTradeForTriggerLimit(market, order) {
110
110
  if (order.baseAssetAmountFilled.eq(numericConstants_1.ZERO)) {
111
- const baseAssetAmount = calculateAmountToTradeForStop(market, order);
111
+ const baseAssetAmount = calculateAmountToTradeForTriggerMarket(market, order);
112
112
  if (baseAssetAmount.eq(numericConstants_1.ZERO)) {
113
113
  return numericConstants_1.ZERO;
114
114
  }
115
115
  }
116
116
  return calculateAmountToTradeForLimit(market, order);
117
117
  }
118
- exports.calculateAmountToTradeForStopLimit = calculateAmountToTradeForStopLimit;
118
+ exports.calculateAmountToTradeForTriggerLimit = calculateAmountToTradeForTriggerLimit;
119
119
  function isSameDirection(firstDirection, secondDirection) {
120
120
  return ((types_1.isVariant(firstDirection, 'long') && types_1.isVariant(secondDirection, 'long')) ||
121
121
  (types_1.isVariant(firstDirection, 'short') && types_1.isVariant(secondDirection, 'short')));
122
122
  }
123
- function calculateAmountToTradeForStop(market, order) {
123
+ function calculateAmountToTradeForTriggerMarket(market, order) {
124
124
  return isTriggerConditionSatisfied(market, order)
125
125
  ? order.baseAssetAmount
126
126
  : numericConstants_1.ZERO;
package/lib/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ /// <reference types="bn.js" />
1
2
  import { PublicKey, Transaction } from '@solana/web3.js';
2
- import BN from 'bn.js';
3
+ import { BN } from '.';
3
4
  export declare class SwapDirection {
4
5
  static readonly ADD: {
5
6
  add: {};
@@ -28,11 +29,11 @@ export declare class OrderType {
28
29
  static readonly LIMIT: {
29
30
  limit: {};
30
31
  };
31
- static readonly STOP: {
32
- stop: {};
32
+ static readonly TRIGGER_MARKET: {
33
+ triggerMarket: {};
33
34
  };
34
- static readonly STOP_LIMIT: {
35
- stopLimit: {};
35
+ static readonly TRIGGER_LIMIT: {
36
+ triggerLimit: {};
36
37
  };
37
38
  static readonly MARKET: {
38
39
  market: {};
@@ -341,6 +342,7 @@ export declare type Order = {
341
342
  userOrderId: number;
342
343
  marketIndex: BN;
343
344
  price: BN;
345
+ userBaseAssetAmount: BN;
344
346
  baseAssetAmount: BN;
345
347
  baseAssetAmountFilled: BN;
346
348
  quoteAssetAmount: BN;
@@ -354,6 +356,7 @@ export declare type Order = {
354
356
  referrer: PublicKey;
355
357
  postOnly: boolean;
356
358
  immediateOrCancel: boolean;
359
+ oraclePriceOffset: BN;
357
360
  };
358
361
  export declare type OrderParams = {
359
362
  orderType: OrderType;
package/lib/types.js CHANGED
@@ -21,8 +21,8 @@ class OrderType {
21
21
  }
22
22
  exports.OrderType = OrderType;
23
23
  OrderType.LIMIT = { limit: {} };
24
- OrderType.STOP = { stop: {} };
25
- OrderType.STOP_LIMIT = { stopLimit: {} };
24
+ OrderType.TRIGGER_MARKET = { triggerMarket: {} };
25
+ OrderType.TRIGGER_LIMIT = { triggerLimit: {} };
26
26
  OrderType.MARKET = { market: {} };
27
27
  class OrderStatus {
28
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.1.18-orders.2",
3
+ "version": "0.1.18-orders.6",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -10,6 +10,7 @@
10
10
  "url": "git@github.com:drift-labs/protocol-v1.git"
11
11
  },
12
12
  "scripts": {
13
+ "lint": "eslint './**/*.{ts,tsx}' --quiet",
13
14
  "build": "yarn clean && tsc",
14
15
  "clean": "rm -rf lib",
15
16
  "patch-and-pub": "npm version patch --force && npm publish"
@@ -34,6 +35,13 @@
34
35
  "strict-event-emitter-types": "^2.0.0",
35
36
  "uuid": "^8.3.2"
36
37
  },
38
+ "devDependencies": {
39
+ "@typescript-eslint/eslint-plugin": "^4.28.0",
40
+ "@typescript-eslint/parser": "^4.28.0",
41
+ "eslint": "^7.29.0",
42
+ "eslint-config-prettier": "^8.3.0",
43
+ "eslint-plugin-prettier": "^3.4.0"
44
+ },
37
45
  "description": "SDK for Drift Protocol v1",
38
46
  "engines": {
39
47
  "node": ">=12"
@@ -1,16 +1,12 @@
1
1
  import { Commitment, Connection, PublicKey } from '@solana/web3.js';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
+ import { AccountData } from './types';
3
4
 
4
5
  type AccountToLoad = {
5
6
  publicKey: PublicKey;
6
7
  callbacks: Map<string, (buffer: Buffer) => void>;
7
8
  };
8
9
 
9
- type AccountData = {
10
- slot: number;
11
- buffer: Buffer | undefined;
12
- };
13
-
14
10
  const GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE = 99;
15
11
 
16
12
  export class BulkAccountLoader {
@@ -21,6 +17,9 @@ export class BulkAccountLoader {
21
17
  accountData = new Map<string, AccountData>();
22
18
  errorCallbacks = new Map<string, (e) => void>();
23
19
  intervalId?: NodeJS.Timer;
20
+ // to handle clients spamming load
21
+ loadPromise?: Promise<void>;
22
+ loadPromiseResolver: () => void;
24
23
 
25
24
  public constructor(
26
25
  connection: Connection,
@@ -56,6 +55,9 @@ export class BulkAccountLoader {
56
55
  this.startPolling();
57
56
  }
58
57
 
58
+ // if a new account needs to be polled, remove the cached loadPromise in case client calls load immediately after
59
+ this.loadPromise = undefined;
60
+
59
61
  return callbackId;
60
62
  }
61
63
 
@@ -91,16 +93,34 @@ export class BulkAccountLoader {
91
93
  }
92
94
 
93
95
  public async load(): Promise<void> {
94
- const chunks = this.chunks(
95
- Array.from(this.accountsToLoad.values()),
96
- GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE
97
- );
98
-
99
- await Promise.all(
100
- chunks.map((chunk) => {
101
- return this.loadChunk(chunk);
102
- })
103
- );
96
+ if (this.loadPromise) {
97
+ return this.loadPromise;
98
+ }
99
+ this.loadPromise = new Promise((resolver) => {
100
+ this.loadPromiseResolver = resolver;
101
+ });
102
+
103
+ try {
104
+ const chunks = this.chunks(
105
+ Array.from(this.accountsToLoad.values()),
106
+ GET_MULTIPLE_ACCOUNTS_CHUNK_SIZE
107
+ );
108
+
109
+ await Promise.all(
110
+ chunks.map((chunk) => {
111
+ return this.loadChunk(chunk);
112
+ })
113
+ );
114
+ } catch (e) {
115
+ console.error(`Error in bulkAccountLoader.load()`);
116
+ console.error(e);
117
+ for (const [_, callback] of this.errorCallbacks) {
118
+ callback(e);
119
+ }
120
+ }
121
+
122
+ this.loadPromiseResolver();
123
+ this.loadPromise = undefined;
104
124
  }
105
125
 
106
126
  async loadChunk(accountsToLoad: AccountToLoad[]): Promise<void> {
@@ -89,11 +89,19 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
89
89
  userPublicKey
90
90
  );
91
91
 
92
- this.accountsToPoll.set(userOrdersPublicKey.toString(), {
93
- key: 'userOrders',
94
- publicKey: userOrdersPublicKey,
95
- eventType: 'userOrdersData',
96
- });
92
+ const userOrdersExist =
93
+ (
94
+ await this.program.provider.connection.getParsedAccountInfo(
95
+ userOrdersPublicKey
96
+ )
97
+ ).value !== null;
98
+ if (userOrdersExist) {
99
+ this.accountsToPoll.set(userOrdersPublicKey.toString(), {
100
+ key: 'userOrders',
101
+ publicKey: userOrdersPublicKey,
102
+ eventType: 'userOrdersData',
103
+ });
104
+ }
97
105
 
98
106
  for (const [_, accountToPoll] of this.accountsToPoll) {
99
107
  accountToPoll.callbackId = this.accountLoader.addAccount(
@@ -127,3 +127,8 @@ export type AccountToPoll = {
127
127
  eventType: string;
128
128
  callbackId?: string;
129
129
  };
130
+
131
+ export type AccountData = {
132
+ slot: number;
133
+ buffer: Buffer | undefined;
134
+ };
@@ -1,13 +1,17 @@
1
- import { AccountSubscriber } from './types';
1
+ import { AccountData, AccountSubscriber } from './types';
2
2
  import { Program } from '@project-serum/anchor';
3
- import { PublicKey } from '@solana/web3.js';
3
+ import { AccountInfo, Context, PublicKey } from '@solana/web3.js';
4
+ import { capitalize } from './utils';
5
+ import * as Buffer from 'buffer';
4
6
 
5
7
  export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
6
8
  data?: T;
9
+ accountData?: AccountData;
7
10
  accountName: string;
8
11
  program: Program;
9
12
  accountPublicKey: PublicKey;
10
13
  onChange: (data: T) => void;
14
+ listenerId?: number;
11
15
 
12
16
  public constructor(
13
17
  accountName: string,
@@ -20,32 +24,78 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
20
24
  }
21
25
 
22
26
  async subscribe(onChange: (data: T) => void): Promise<void> {
27
+ if (this.listenerId) {
28
+ return;
29
+ }
30
+
23
31
  this.onChange = onChange;
24
32
  await this.fetch();
25
33
 
26
- this.program.account[this.accountName]
27
- .subscribe(this.accountPublicKey, this.program.provider.opts.commitment)
28
- .on('change', async (data: T) => {
29
- this.data = data;
30
- this.onChange(data);
31
- });
34
+ this.listenerId = this.program.provider.connection.onAccountChange(
35
+ this.accountPublicKey,
36
+ (accountInfo, context) => {
37
+ this.handleRpcResponse(context, accountInfo);
38
+ },
39
+ this.program.provider.opts.commitment
40
+ );
32
41
  }
33
42
 
34
43
  async fetch(): Promise<void> {
35
- const newData = (await this.program.account[this.accountName].fetch(
36
- this.accountPublicKey
37
- )) as T;
44
+ const rpcResponse =
45
+ await this.program.provider.connection.getAccountInfoAndContext(
46
+ this.accountPublicKey,
47
+ this.program.provider.opts.commitment
48
+ );
49
+ this.handleRpcResponse(rpcResponse.context, rpcResponse?.value);
50
+ }
51
+
52
+ handleRpcResponse(context: Context, accountInfo?: AccountInfo<Buffer>): void {
53
+ const newSlot = context.slot;
54
+ let newBuffer: Buffer | undefined = undefined;
55
+ if (accountInfo) {
56
+ newBuffer = accountInfo.data;
57
+ }
38
58
 
39
- // if data has changed trigger update
40
- if (JSON.stringify(newData) !== JSON.stringify(this.data)) {
41
- this.data = newData;
59
+ if (!this.accountData) {
60
+ this.accountData = {
61
+ buffer: newBuffer,
62
+ slot: newSlot,
63
+ };
64
+ if (newBuffer) {
65
+ this.data = this.program.account[
66
+ this.accountName
67
+ ].coder.accounts.decode(capitalize(this.accountName), newBuffer);
68
+ this.onChange(this.data);
69
+ }
70
+ return;
71
+ }
72
+
73
+ if (newSlot <= this.accountData.slot) {
74
+ return;
75
+ }
76
+
77
+ const oldBuffer = this.accountData.buffer;
78
+ if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
79
+ this.accountData = {
80
+ buffer: newBuffer,
81
+ slot: newSlot,
82
+ };
83
+ this.data = this.program.account[this.accountName].coder.accounts.decode(
84
+ capitalize(this.accountName),
85
+ newBuffer
86
+ );
42
87
  this.onChange(this.data);
43
88
  }
44
89
  }
45
90
 
46
91
  unsubscribe(): Promise<void> {
47
- return this.program.account[this.accountName].unsubscribe(
48
- this.accountPublicKey
49
- );
92
+ if (this.listenerId) {
93
+ const promise =
94
+ this.program.provider.connection.removeAccountChangeListener(
95
+ this.listenerId
96
+ );
97
+ this.listenerId = undefined;
98
+ return promise;
99
+ }
50
100
  }
51
101
  }