@drift-labs/sdk 2.28.0-beta.1 → 2.28.0-beta.3

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.
@@ -203,6 +203,11 @@ export declare class DriftClient {
203
203
  getCancelOrderByUserIdIx(userOrderId: number): Promise<TransactionInstruction>;
204
204
  cancelOrders(marketType?: MarketType, marketIndex?: number, direction?: PositionDirection, txParams?: TxParams): Promise<TransactionSignature>;
205
205
  getCancelOrdersIx(marketType: MarketType | null, marketIndex: number | null, direction: PositionDirection | null): Promise<TransactionInstruction>;
206
+ cancelAndPlaceOrders(cancelOrderParams: {
207
+ marketType?: MarketType;
208
+ marketIndex?: number;
209
+ direction?: PositionDirection;
210
+ }, placeOrderParams: OrderParams[], txParams?: TxParams): Promise<TransactionSignature>;
206
211
  fillPerpOrder(userAccountPublicKey: PublicKey, user: UserAccount, order?: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<TransactionSignature>;
207
212
  getFillPerpOrderIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, order: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo): Promise<TransactionInstruction>;
208
213
  getRevertFillIx(): Promise<TransactionInstruction>;
@@ -1525,6 +1525,25 @@ class DriftClient {
1525
1525
  remainingAccounts,
1526
1526
  });
1527
1527
  }
1528
+ async cancelAndPlaceOrders(cancelOrderParams, placeOrderParams, txParams) {
1529
+ const tx = (0, utils_1.wrapInTx)(await this.getCancelOrdersIx(cancelOrderParams.marketType, cancelOrderParams.marketIndex, cancelOrderParams.direction), txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits, txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice);
1530
+ for (const placeOrderParam of placeOrderParams) {
1531
+ const marketType = placeOrderParam.marketType;
1532
+ if (!marketType) {
1533
+ throw new Error('marketType must be set on placeOrderParams');
1534
+ }
1535
+ let ix;
1536
+ if ((0, types_1.isVariant)(marketType, 'perp')) {
1537
+ ix = this.getPlacePerpOrderIx(placeOrderParam);
1538
+ }
1539
+ else {
1540
+ ix = this.getPlaceSpotOrderIx(placeOrderParam);
1541
+ }
1542
+ tx.add(ix);
1543
+ }
1544
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
1545
+ return txSig;
1546
+ }
1528
1547
  async fillPerpOrder(userAccountPublicKey, user, order, makerInfo, referrerInfo, txParams) {
1529
1548
  const { txSig } = await this.sendTransaction((0, utils_1.wrapInTx)(await this.getFillPerpOrderIx(userAccountPublicKey, user, order, makerInfo, referrerInfo), txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits, txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice), [], this.opts);
1530
1549
  return txSig;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.28.0-beta.1",
2
+ "version": "2.28.0-beta.3",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/lib/index.d.ts CHANGED
@@ -67,6 +67,7 @@ export * from './dlob/DLOBNode';
67
67
  export * from './dlob/DLOBOrders';
68
68
  export * from './dlob/NodeList';
69
69
  export * from './dlob/DLOBSubscriber';
70
+ export * from './dlob/DLOBApiClient';
70
71
  export * from './dlob/types';
71
72
  export * from './dlob/orderBookLevels';
72
73
  export * from './userMap/userMap';
package/lib/index.js CHANGED
@@ -91,6 +91,7 @@ __exportStar(require("./dlob/DLOBNode"), exports);
91
91
  __exportStar(require("./dlob/DLOBOrders"), exports);
92
92
  __exportStar(require("./dlob/NodeList"), exports);
93
93
  __exportStar(require("./dlob/DLOBSubscriber"), exports);
94
+ __exportStar(require("./dlob/DLOBApiClient"), exports);
94
95
  __exportStar(require("./dlob/types"), exports);
95
96
  __exportStar(require("./dlob/orderBookLevels"), exports);
96
97
  __exportStar(require("./userMap/userMap"), exports);
@@ -1,6 +1,6 @@
1
1
  import { Connection, PublicKey } from '@solana/web3.js';
2
2
  import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
3
- import { MarketData, Client } from '@ellipsis-labs/phoenix-sdk';
3
+ import { Client, Market } from '@ellipsis-labs/phoenix-sdk';
4
4
  import { BN } from '@coral-xyz/anchor';
5
5
  import { L2Level, L2OrderBookGenerator } from '../dlob/orderBookLevels';
6
6
  export type PhoenixMarketSubscriberConfig = {
@@ -21,7 +21,7 @@ export declare class PhoenixSubscriber implements L2OrderBookGenerator {
21
21
  marketAddress: PublicKey;
22
22
  subscriptionType: 'polling' | 'websocket';
23
23
  accountLoader: BulkAccountLoader | undefined;
24
- market: MarketData;
24
+ market: Market;
25
25
  marketCallbackId: string | number;
26
26
  clockCallbackId: string | number;
27
27
  subscribed: boolean;
@@ -29,8 +29,8 @@ export declare class PhoenixSubscriber implements L2OrderBookGenerator {
29
29
  lastUnixTimestamp: number;
30
30
  constructor(config: PhoenixMarketSubscriberConfig);
31
31
  subscribe(): Promise<void>;
32
- getBestBid(): BN;
33
- getBestAsk(): BN;
32
+ getBestBid(): BN | undefined;
33
+ getBestAsk(): BN | undefined;
34
34
  getL2Bids(): Generator<L2Level>;
35
35
  getL2Asks(): Generator<L2Level>;
36
36
  getL2Levels(side: 'bids' | 'asks'): Generator<L2Level>;
@@ -24,41 +24,73 @@ class PhoenixSubscriber {
24
24
  if (this.subscribed) {
25
25
  return;
26
26
  }
27
- this.market = (0, phoenix_sdk_1.deserializeMarketData)((await this.connection.getAccountInfo(this.marketAddress, 'confirmed'))
28
- .data);
27
+ this.market = await phoenix_sdk_1.Market.loadFromAddress({
28
+ connection: this.connection,
29
+ address: this.marketAddress,
30
+ });
29
31
  const clock = (0, phoenix_sdk_1.deserializeClockData)((await this.connection.getAccountInfo(web3_js_1.SYSVAR_CLOCK_PUBKEY, 'confirmed'))
30
32
  .data);
31
33
  this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
32
34
  if (this.subscriptionType === 'websocket') {
33
35
  this.marketCallbackId = this.connection.onAccountChange(this.marketAddress, (accountInfo, _ctx) => {
34
- this.market = (0, phoenix_sdk_1.deserializeMarketData)(accountInfo.data);
36
+ try {
37
+ this.market = this.market.reload(accountInfo.data);
38
+ }
39
+ catch {
40
+ console.error('Failed to reload Phoenix market data');
41
+ }
35
42
  });
36
43
  this.clockCallbackId = this.connection.onAccountChange(web3_js_1.SYSVAR_CLOCK_PUBKEY, (accountInfo, ctx) => {
37
- this.lastSlot = ctx.slot;
38
- const clock = (0, phoenix_sdk_1.deserializeClockData)(accountInfo.data);
39
- this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
44
+ try {
45
+ this.lastSlot = ctx.slot;
46
+ const clock = (0, phoenix_sdk_1.deserializeClockData)(accountInfo.data);
47
+ this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
48
+ }
49
+ catch {
50
+ console.error('Failed to reload clock data');
51
+ }
40
52
  });
41
53
  }
42
54
  else {
43
55
  this.marketCallbackId = await this.accountLoader.addAccount(this.marketAddress, (buffer, slot) => {
44
- this.lastSlot = slot;
45
- this.market = (0, phoenix_sdk_1.deserializeMarketData)(buffer);
56
+ try {
57
+ this.lastSlot = slot;
58
+ if (buffer) {
59
+ this.market = this.market.reload(buffer);
60
+ }
61
+ }
62
+ catch {
63
+ console.error('Failed to reload Phoenix market data');
64
+ }
46
65
  });
47
66
  this.clockCallbackId = await this.accountLoader.addAccount(web3_js_1.SYSVAR_CLOCK_PUBKEY, (buffer, slot) => {
48
- this.lastSlot = slot;
49
- const clock = (0, phoenix_sdk_1.deserializeClockData)(buffer);
50
- this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
67
+ try {
68
+ this.lastSlot = slot;
69
+ const clock = (0, phoenix_sdk_1.deserializeClockData)(buffer);
70
+ this.lastUnixTimestamp = (0, phoenix_sdk_1.toNum)(clock.unixTimestamp);
71
+ }
72
+ catch {
73
+ console.error('Failed to reload clock data');
74
+ }
51
75
  });
52
76
  }
53
77
  this.subscribed = true;
54
78
  }
55
79
  getBestBid() {
56
80
  const ladder = (0, phoenix_sdk_1.getMarketUiLadder)(this.market, this.lastSlot, this.lastUnixTimestamp, 1);
57
- return new anchor_1.BN(Math.floor(ladder.bids[0][0] * numericConstants_1.PRICE_PRECISION.toNumber()));
81
+ const bestBid = ladder.bids[0];
82
+ if (!bestBid) {
83
+ return undefined;
84
+ }
85
+ return new anchor_1.BN(Math.floor(bestBid.price * numericConstants_1.PRICE_PRECISION.toNumber()));
58
86
  }
59
87
  getBestAsk() {
60
88
  const ladder = (0, phoenix_sdk_1.getMarketUiLadder)(this.market, this.lastSlot, this.lastUnixTimestamp, 1);
61
- return new anchor_1.BN(Math.floor(ladder.asks[0][0] * numericConstants_1.PRICE_PRECISION.toNumber()));
89
+ const bestAsk = ladder.asks[0];
90
+ if (!bestAsk) {
91
+ return undefined;
92
+ }
93
+ return new anchor_1.BN(Math.floor(bestAsk.price * numericConstants_1.PRICE_PRECISION.toNumber()));
62
94
  }
63
95
  getL2Bids() {
64
96
  return this.getL2Levels('bids');
@@ -72,10 +104,10 @@ class PhoenixSubscriber {
72
104
  const pricePrecision = numericConstants_1.PRICE_PRECISION.toNumber();
73
105
  const ladder = (0, phoenix_sdk_1.getMarketUiLadder)(this.market, this.lastSlot, this.lastUnixTimestamp, 20);
74
106
  for (let i = 0; i < ladder[side].length; i++) {
75
- const [priceNum, sizeNum] = ladder[side][i];
76
- const size = new anchor_1.BN(Math.floor(sizeNum * basePrecision));
107
+ const { price, quantity } = ladder[side][i];
108
+ const size = new anchor_1.BN(Math.floor(quantity * basePrecision));
77
109
  yield {
78
- price: new anchor_1.BN(Math.floor(priceNum * pricePrecision)),
110
+ price: new anchor_1.BN(Math.floor(price * pricePrecision)),
79
111
  size,
80
112
  sources: {
81
113
  phoenix: size,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.28.0-beta.1",
3
+ "version": "2.28.0-beta.3",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@coral-xyz/anchor": "0.26.0",
37
- "@ellipsis-labs/phoenix-sdk": "^1.3.2",
37
+ "@ellipsis-labs/phoenix-sdk": "^1.4.2",
38
38
  "@project-serum/serum": "^0.13.38",
39
39
  "@pythnetwork/client": "2.5.3",
40
40
  "@solana/spl-token": "^0.1.6",
@@ -2664,6 +2664,43 @@ export class DriftClient {
2664
2664
  );
2665
2665
  }
2666
2666
 
2667
+ public async cancelAndPlaceOrders(
2668
+ cancelOrderParams: {
2669
+ marketType?: MarketType;
2670
+ marketIndex?: number;
2671
+ direction?: PositionDirection;
2672
+ },
2673
+ placeOrderParams: OrderParams[],
2674
+ txParams?: TxParams
2675
+ ): Promise<TransactionSignature> {
2676
+ const tx = wrapInTx(
2677
+ await this.getCancelOrdersIx(
2678
+ cancelOrderParams.marketType,
2679
+ cancelOrderParams.marketIndex,
2680
+ cancelOrderParams.direction
2681
+ ),
2682
+ txParams?.computeUnits,
2683
+ txParams?.computeUnitsPrice
2684
+ );
2685
+
2686
+ for (const placeOrderParam of placeOrderParams) {
2687
+ const marketType = placeOrderParam.marketType;
2688
+ if (!marketType) {
2689
+ throw new Error('marketType must be set on placeOrderParams');
2690
+ }
2691
+ let ix;
2692
+ if (isVariant(marketType, 'perp')) {
2693
+ ix = this.getPlacePerpOrderIx(placeOrderParam);
2694
+ } else {
2695
+ ix = this.getPlaceSpotOrderIx(placeOrderParam);
2696
+ }
2697
+ tx.add(ix);
2698
+ }
2699
+
2700
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
2701
+ return txSig;
2702
+ }
2703
+
2667
2704
  public async fillPerpOrder(
2668
2705
  userAccountPublicKey: PublicKey,
2669
2706
  user: UserAccount,
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.28.0-beta.1",
2
+ "version": "2.28.0-beta.3",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
package/src/index.ts CHANGED
@@ -69,6 +69,7 @@ export * from './dlob/DLOBNode';
69
69
  export * from './dlob/DLOBOrders';
70
70
  export * from './dlob/NodeList';
71
71
  export * from './dlob/DLOBSubscriber';
72
+ export * from './dlob/DLOBApiClient';
72
73
  export * from './dlob/types';
73
74
  export * from './dlob/orderBookLevels';
74
75
  export * from './userMap/userMap';
@@ -1,12 +1,11 @@
1
1
  import { Connection, PublicKey, SYSVAR_CLOCK_PUBKEY } from '@solana/web3.js';
2
2
  import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
3
3
  import {
4
- MarketData,
5
4
  Client,
6
- deserializeMarketData,
7
5
  deserializeClockData,
8
6
  toNum,
9
7
  getMarketUiLadder,
8
+ Market,
10
9
  } from '@ellipsis-labs/phoenix-sdk';
11
10
  import { PRICE_PRECISION } from '../constants/numericConstants';
12
11
  import { BN } from '@coral-xyz/anchor';
@@ -34,7 +33,7 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
34
33
  marketAddress: PublicKey;
35
34
  subscriptionType: 'polling' | 'websocket';
36
35
  accountLoader: BulkAccountLoader | undefined;
37
- market: MarketData;
36
+ market: Market;
38
37
  marketCallbackId: string | number;
39
38
  clockCallbackId: string | number;
40
39
 
@@ -61,10 +60,10 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
61
60
  return;
62
61
  }
63
62
 
64
- this.market = deserializeMarketData(
65
- (await this.connection.getAccountInfo(this.marketAddress, 'confirmed'))
66
- .data
67
- );
63
+ this.market = await Market.loadFromAddress({
64
+ connection: this.connection,
65
+ address: this.marketAddress,
66
+ });
68
67
 
69
68
  const clock = deserializeClockData(
70
69
  (await this.connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY, 'confirmed'))
@@ -76,31 +75,49 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
76
75
  this.marketCallbackId = this.connection.onAccountChange(
77
76
  this.marketAddress,
78
77
  (accountInfo, _ctx) => {
79
- this.market = deserializeMarketData(accountInfo.data);
78
+ try {
79
+ this.market = this.market.reload(accountInfo.data);
80
+ } catch {
81
+ console.error('Failed to reload Phoenix market data');
82
+ }
80
83
  }
81
84
  );
82
85
  this.clockCallbackId = this.connection.onAccountChange(
83
86
  SYSVAR_CLOCK_PUBKEY,
84
87
  (accountInfo, ctx) => {
85
- this.lastSlot = ctx.slot;
86
- const clock = deserializeClockData(accountInfo.data);
87
- this.lastUnixTimestamp = toNum(clock.unixTimestamp);
88
+ try {
89
+ this.lastSlot = ctx.slot;
90
+ const clock = deserializeClockData(accountInfo.data);
91
+ this.lastUnixTimestamp = toNum(clock.unixTimestamp);
92
+ } catch {
93
+ console.error('Failed to reload clock data');
94
+ }
88
95
  }
89
96
  );
90
97
  } else {
91
98
  this.marketCallbackId = await this.accountLoader.addAccount(
92
99
  this.marketAddress,
93
100
  (buffer, slot) => {
94
- this.lastSlot = slot;
95
- this.market = deserializeMarketData(buffer);
101
+ try {
102
+ this.lastSlot = slot;
103
+ if (buffer) {
104
+ this.market = this.market.reload(buffer);
105
+ }
106
+ } catch {
107
+ console.error('Failed to reload Phoenix market data');
108
+ }
96
109
  }
97
110
  );
98
111
  this.clockCallbackId = await this.accountLoader.addAccount(
99
112
  SYSVAR_CLOCK_PUBKEY,
100
113
  (buffer, slot) => {
101
- this.lastSlot = slot;
102
- const clock = deserializeClockData(buffer);
103
- this.lastUnixTimestamp = toNum(clock.unixTimestamp);
114
+ try {
115
+ this.lastSlot = slot;
116
+ const clock = deserializeClockData(buffer);
117
+ this.lastUnixTimestamp = toNum(clock.unixTimestamp);
118
+ } catch {
119
+ console.error('Failed to reload clock data');
120
+ }
104
121
  }
105
122
  );
106
123
  }
@@ -108,24 +125,33 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
108
125
  this.subscribed = true;
109
126
  }
110
127
 
111
- public getBestBid(): BN {
128
+ public getBestBid(): BN | undefined {
112
129
  const ladder = getMarketUiLadder(
113
130
  this.market,
114
131
  this.lastSlot,
115
132
  this.lastUnixTimestamp,
116
133
  1
117
134
  );
118
- return new BN(Math.floor(ladder.bids[0][0] * PRICE_PRECISION.toNumber()));
135
+ const bestBid = ladder.bids[0];
136
+ if (!bestBid) {
137
+ return undefined;
138
+ }
139
+ return new BN(Math.floor(bestBid.price * PRICE_PRECISION.toNumber()));
119
140
  }
120
141
 
121
- public getBestAsk(): BN {
142
+ public getBestAsk(): BN | undefined {
122
143
  const ladder = getMarketUiLadder(
123
144
  this.market,
124
145
  this.lastSlot,
125
146
  this.lastUnixTimestamp,
126
147
  1
127
148
  );
128
- return new BN(Math.floor(ladder.asks[0][0] * PRICE_PRECISION.toNumber()));
149
+
150
+ const bestAsk = ladder.asks[0];
151
+ if (!bestAsk) {
152
+ return undefined;
153
+ }
154
+ return new BN(Math.floor(bestAsk.price * PRICE_PRECISION.toNumber()));
129
155
  }
130
156
 
131
157
  public getL2Bids(): Generator<L2Level> {
@@ -149,10 +175,10 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
149
175
  );
150
176
 
151
177
  for (let i = 0; i < ladder[side].length; i++) {
152
- const [priceNum, sizeNum] = ladder[side][i];
153
- const size = new BN(Math.floor(sizeNum * basePrecision));
178
+ const { price, quantity } = ladder[side][i];
179
+ const size = new BN(Math.floor(quantity * basePrecision));
154
180
  yield {
155
- price: new BN(Math.floor(priceNum * pricePrecision)),
181
+ price: new BN(Math.floor(price * pricePrecision)),
156
182
  size,
157
183
  sources: {
158
184
  phoenix: size,