@drift-labs/sdk 0.1.18-orders.3 → 0.1.18-orders.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +3 -4
  2. package/lib/accounts/bulkAccountLoader.js +23 -4
  3. package/lib/accounts/types.d.ts +4 -0
  4. package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -2
  5. package/lib/accounts/webSocketAccountSubscriber.js +43 -12
  6. package/lib/clearingHouse.d.ts +4 -0
  7. package/lib/clearingHouse.js +40 -0
  8. package/lib/clearingHouseUser.d.ts +3 -3
  9. package/lib/clearingHouseUser.js +16 -20
  10. package/lib/config.js +1 -1
  11. package/lib/constants/markets.d.ts +2 -1
  12. package/lib/constants/markets.js +20 -15
  13. package/lib/constants/numericConstants.d.ts +3 -1
  14. package/lib/constants/numericConstants.js +15 -17
  15. package/lib/examples/makeTradeExample.js +1 -1
  16. package/lib/idl/clearing_house.json +6 -2
  17. package/lib/math/conversion.d.ts +1 -1
  18. package/lib/math/insuranceFund.d.ts +2 -1
  19. package/lib/math/insuranceFund.js +3 -6
  20. package/lib/math/position.d.ts +2 -1
  21. package/lib/math/position.js +2 -5
  22. package/lib/math/utils.d.ts +2 -1
  23. package/lib/math/utils.js +3 -6
  24. package/lib/mockUSDCFaucet.d.ts +2 -1
  25. package/lib/orderParams.d.ts +2 -2
  26. package/lib/orderParams.js +7 -7
  27. package/lib/orders.d.ts +2 -1
  28. package/lib/types.d.ts +7 -5
  29. package/lib/types.js +2 -2
  30. package/package.json +9 -1
  31. package/src/accounts/bulkAccountLoader.ts +35 -15
  32. package/src/accounts/types.ts +5 -0
  33. package/src/accounts/webSocketAccountSubscriber.ts +67 -17
  34. package/src/clearingHouse.ts +56 -0
  35. package/src/clearingHouseUser.ts +2 -2
  36. package/src/config.ts +1 -1
  37. package/src/constants/markets.ts +9 -1
  38. package/src/constants/numericConstants.ts +2 -1
  39. package/src/examples/makeTradeExample.ts +4 -1
  40. package/src/idl/clearing_house.json +6 -2
  41. package/src/math/conversion.ts +1 -1
  42. package/src/math/insuranceFund.ts +1 -1
  43. package/src/math/position.ts +1 -1
  44. package/src/math/utils.ts +1 -1
  45. package/src/mockUSDCFaucet.ts +1 -1
  46. package/src/orderParams.ts +4 -4
  47. package/src/orders.ts +1 -1
  48. package/src/types.ts +4 -3
@@ -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
  }
@@ -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
6
  export declare function calculateAmountToTradeForStopLimit(market: Market, order: Order): BN;
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;
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.3",
3
+ "version": "0.1.18-orders.4",
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> {
@@ -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
  }
@@ -414,6 +414,20 @@ export class ClearingHouse {
414
414
  return this.userOrdersAccountPublicKey;
415
415
  }
416
416
 
417
+ userOrdersExist?: boolean;
418
+ async userOrdersAccountExists(): Promise<boolean> {
419
+ if (this.userOrdersExist) {
420
+ return this.userOrdersExist;
421
+ }
422
+ const userOrdersAccountRPCResponse =
423
+ await this.connection.getParsedAccountInfo(
424
+ await this.getUserOrdersAccountPublicKey()
425
+ );
426
+
427
+ this.userOrdersExist = userOrdersAccountRPCResponse.value !== null;
428
+ return this.userOrdersExist;
429
+ }
430
+
417
431
  public async depositCollateral(
418
432
  amount: BN,
419
433
  collateralAccountPublicKey: PublicKey,
@@ -668,6 +682,27 @@ export class ClearingHouse {
668
682
  );
669
683
  }
670
684
 
685
+ public async initializeUserOrdersThenPlaceOrder(
686
+ orderParams: OrderParams,
687
+ discountToken?: PublicKey,
688
+ referrer?: PublicKey
689
+ ): Promise<TransactionSignature> {
690
+ const instructions: anchor.web3.TransactionInstruction[] = [];
691
+ const userOrdersAccountExists = await this.userOrdersAccountExists();
692
+ if (!userOrdersAccountExists) {
693
+ instructions.push(await this.getInitializeUserOrdersInstruction());
694
+ }
695
+ instructions.push(
696
+ await this.getPlaceOrderIx(orderParams, discountToken, referrer)
697
+ );
698
+ const tx = new Transaction();
699
+ for (const instruction of instructions) {
700
+ tx.add(instruction);
701
+ }
702
+
703
+ return await this.txSender.send(tx, [], this.opts);
704
+ }
705
+
671
706
  public async placeOrder(
672
707
  orderParams: OrderParams,
673
708
  discountToken?: PublicKey,
@@ -872,6 +907,27 @@ export class ClearingHouse {
872
907
  });
873
908
  }
874
909
 
910
+ public async initializeUserOrdersThenPlaceAndFillOrder(
911
+ orderParams: OrderParams,
912
+ discountToken?: PublicKey,
913
+ referrer?: PublicKey
914
+ ): Promise<TransactionSignature> {
915
+ const instructions: anchor.web3.TransactionInstruction[] = [];
916
+ const userOrdersAccountExists = await this.userOrdersAccountExists();
917
+ if (!userOrdersAccountExists) {
918
+ instructions.push(await this.getInitializeUserOrdersInstruction());
919
+ }
920
+ instructions.push(
921
+ await this.getPlaceAndFillOrderIx(orderParams, discountToken, referrer)
922
+ );
923
+ const tx = new Transaction();
924
+ for (const instruction of instructions) {
925
+ tx.add(instruction);
926
+ }
927
+
928
+ return await this.txSender.send(tx, [], this.opts);
929
+ }
930
+
875
931
  public async placeAndFillOrder(
876
932
  orderParams: OrderParams,
877
933
  discountToken?: PublicKey,
@@ -1,5 +1,4 @@
1
1
  import { PublicKey } from '@solana/web3.js';
2
- import BN from 'bn.js';
3
2
  import { EventEmitter } from 'events';
4
3
  import StrictEventEmitter from 'strict-event-emitter-types';
5
4
  import { ClearingHouse } from './clearingHouse';
@@ -33,6 +32,7 @@ import {
33
32
  getUserOrdersAccountPublicKey,
34
33
  calculateNewStateAfterOrder,
35
34
  calculateTradeSlippage,
35
+ BN,
36
36
  } from '.';
37
37
  import { getUserAccountPublicKey } from './addresses';
38
38
  import {
@@ -120,7 +120,7 @@ export class ClearingHouseUser {
120
120
  return this.accountSubscriber.getUserPositionsAccount();
121
121
  }
122
122
 
123
- public getUserOrdersAccount(): UserOrdersAccount {
123
+ public getUserOrdersAccount(): UserOrdersAccount | undefined {
124
124
  return this.accountSubscriber.getUserOrdersAccount();
125
125
  }
126
126
 
package/src/config.ts CHANGED
@@ -11,7 +11,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
11
11
  devnet: {
12
12
  ENV: 'devnet',
13
13
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
14
- CLEARING_HOUSE_PROGRAM_ID: '8mKouB1uzsoMAhAu4qAXCiu8KAfwH7nonpuYfTM21Xg2',
14
+ CLEARING_HOUSE_PROGRAM_ID: '3PfbDmWxR6e2rJ2brhSv7KJyUrHbSCu63d3FHqdLhxUJ',
15
15
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
16
16
  },
17
17
  'mainnet-beta': {
@@ -1,4 +1,4 @@
1
- import BN from 'bn.js';
1
+ import { BN } from '../';
2
2
 
3
3
  type Market = {
4
4
  symbol: string;
@@ -98,6 +98,14 @@ export const Markets: Market[] = [
98
98
  mainnetPythOracle: 'HqFyq1wh1xKvL7KDqqT7NJeSPdAqsDqnmBisUC2XdXAX',
99
99
  launchTs: 1643686767000,
100
100
  },
101
+ {
102
+ symbol: 'FTT-PERP',
103
+ baseAssetSymbol: 'FTT',
104
+ marketIndex: new BN(11),
105
+ devnetPythOracle: '6vivTRs5ZPeeXbjo7dfburfaYDWoXjBtdtuYgQRuGfu',
106
+ mainnetPythOracle: '8JPJJkmDScpcNmBRKGZuPuG2GYAveQgP3t5gFuMymwvF',
107
+ launchTs: 1644382122000,
108
+ },
101
109
  // {
102
110
  // symbol: 'mSOL-PERP',
103
111
  // baseAssetSymbol: 'mSOL',
@@ -1,4 +1,4 @@
1
- import BN from 'bn.js';
1
+ import { BN } from '../';
2
2
 
3
3
  export const ZERO = new BN(0);
4
4
  export const ONE = new BN(1);
@@ -15,6 +15,7 @@ export const FUNDING_PAYMENT_PRECISION = new BN(10000);
15
15
  export const PEG_PRECISION = new BN(1000);
16
16
 
17
17
  export const AMM_RESERVE_PRECISION = new BN(10 ** 13);
18
+ export const BASE_PRECISION = AMM_RESERVE_PRECISION;
18
19
  export const AMM_TO_QUOTE_PRECISION_RATIO =
19
20
  AMM_RESERVE_PRECISION.div(QUOTE_PRECISION); // 10^7
20
21
  export const PRICE_TO_QUOTE_PRECISION =
@@ -95,7 +95,10 @@ const main = async () => {
95
95
  clearingHouse.getMarket(solMarketInfo.marketIndex)
96
96
  );
97
97
 
98
- const formattedPrice = convertToNumber(currentMarketPrice, QUOTE_PRECISION);
98
+ const formattedPrice = convertToNumber(
99
+ currentMarketPrice,
100
+ MARK_PRICE_PRECISION
101
+ );
99
102
 
100
103
  console.log(`Current Market Price is $${formattedPrice}`);
101
104
 
@@ -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
  }
@@ -1,4 +1,4 @@
1
- import BN from 'bn.js';
1
+ import { BN } from '../';
2
2
  import {
3
3
  MARK_PRICE_PRECISION,
4
4
  PEG_PRECISION,
@@ -1,5 +1,5 @@
1
1
  import { MarketsAccount, StateAccount } from '../types';
2
- import BN from 'bn.js';
2
+ import { BN } from '../';
3
3
  import { Connection } from '@solana/web3.js';
4
4
 
5
5
  /**
@@ -1,4 +1,4 @@
1
- import BN from 'bn.js';
1
+ import { BN } from '../';
2
2
  import {
3
3
  AMM_RESERVE_PRECISION,
4
4
  AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO,
package/src/math/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import BN from 'bn.js';
1
+ import { BN } from '../';
2
2
 
3
3
  export const squareRootBN = (n, closeness = new BN(1)) => {
4
4
  // Assuming the sqrt of n as n only