@drift-labs/sdk 2.31.1-beta.11 → 2.31.1-beta.12

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.31.1-beta.11
1
+ 2.31.1-beta.12
@@ -19,7 +19,7 @@ type RemainingAccountParams = {
19
19
  userAccounts: UserAccount[];
20
20
  writablePerpMarketIndexes?: number[];
21
21
  writableSpotMarketIndexes?: number[];
22
- readablePerpMarketIndex?: number;
22
+ readablePerpMarketIndex?: number | number[];
23
23
  readableSpotMarketIndexes?: number[];
24
24
  useMarketLastSlotCache?: boolean;
25
25
  };
@@ -44,6 +44,8 @@ export declare class DriftClient {
44
44
  txSender: TxSender;
45
45
  perpMarketLastSlotCache: Map<number, number>;
46
46
  spotMarketLastSlotCache: Map<number, number>;
47
+ mustIncludePerpMarketIndexes: Set<number>;
48
+ mustIncludeSpotMarketIndexes: Set<number>;
47
49
  authority: PublicKey;
48
50
  marketLookupTable: PublicKey;
49
51
  lookupTableAccount: AddressLookupTableAccount;
@@ -162,7 +164,20 @@ export declare class DriftClient {
162
164
  * @param amount
163
165
  */
164
166
  convertToPricePrecision(amount: BN | number): BN;
167
+ /**
168
+ * Each drift instruction must include perp and sport market accounts in the ix remaining accounts.
169
+ * Use this function to force a subset of markets to be included in the remaining accounts for every ix
170
+ *
171
+ * @param perpMarketIndexes
172
+ * @param spotMarketIndexes
173
+ */
174
+ mustIncludeMarketsInIx({ perpMarketIndexes, spotMarketIndexes, }: {
175
+ perpMarketIndexes: number[];
176
+ spotMarketIndexes: number[];
177
+ }): void;
165
178
  getRemainingAccounts(params: RemainingAccountParams): AccountMeta[];
179
+ addPerpMarketToRemainingAccountMaps(marketIndex: number, writable: boolean, oracleAccountMap: Map<string, AccountMeta>, spotMarketAccountMap: Map<number, AccountMeta>, perpMarketAccountMap: Map<number, AccountMeta>): void;
180
+ addSpotMarketToRemainingAccountMaps(marketIndex: number, writable: boolean, oracleAccountMap: Map<string, AccountMeta>, spotMarketAccountMap: Map<number, AccountMeta>): void;
166
181
  getRemainingAccountMapsForUsers(userAccounts: UserAccount[]): {
167
182
  oracleAccountMap: Map<string, AccountMeta>;
168
183
  spotMarketAccountMap: Map<number, AccountMeta>;
@@ -271,6 +286,8 @@ export declare class DriftClient {
271
286
  marketIndex?: number;
272
287
  direction?: PositionDirection;
273
288
  }, placeOrderParams: OrderParams[], txParams?: TxParams): Promise<TransactionSignature>;
289
+ placeOrders(params: OrderParams[], txParams?: TxParams): Promise<TransactionSignature>;
290
+ getPlaceOrdersIx(params: OrderParams[]): Promise<TransactionInstruction>;
274
291
  fillPerpOrder(userAccountPublicKey: PublicKey, user: UserAccount, order?: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<TransactionSignature>;
275
292
  getFillPerpOrderIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, order: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo): Promise<TransactionInstruction>;
276
293
  getRevertFillIx(): Promise<TransactionInstruction>;
@@ -70,6 +70,8 @@ class DriftClient {
70
70
  this._isSubscribed = false;
71
71
  this.perpMarketLastSlotCache = new Map();
72
72
  this.spotMarketLastSlotCache = new Map();
73
+ this.mustIncludePerpMarketIndexes = new Set();
74
+ this.mustIncludeSpotMarketIndexes = new Set();
73
75
  this.connection = config.connection;
74
76
  this.wallet = config.wallet;
75
77
  this.opts = config.opts || anchor_1.AnchorProvider.defaultOptions();
@@ -717,6 +719,21 @@ class DriftClient {
717
719
  amount = typeof amount === 'number' ? new anchor_1.BN(amount) : amount;
718
720
  return amount.mul(numericConstants_1.PRICE_PRECISION);
719
721
  }
722
+ /**
723
+ * Each drift instruction must include perp and sport market accounts in the ix remaining accounts.
724
+ * Use this function to force a subset of markets to be included in the remaining accounts for every ix
725
+ *
726
+ * @param perpMarketIndexes
727
+ * @param spotMarketIndexes
728
+ */
729
+ mustIncludeMarketsInIx({ perpMarketIndexes, spotMarketIndexes, }) {
730
+ perpMarketIndexes.forEach((perpMarketIndex) => {
731
+ this.mustIncludePerpMarketIndexes.add(perpMarketIndex);
732
+ });
733
+ spotMarketIndexes.forEach((spotMarketIndex) => {
734
+ this.mustIncludeSpotMarketIndexes.add(spotMarketIndex);
735
+ });
736
+ }
720
737
  getRemainingAccounts(params) {
721
738
  var _a;
722
739
  const { oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap } = this.getRemainingAccountMapsForUsers(params.userAccounts);
@@ -726,30 +743,7 @@ class DriftClient {
726
743
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
727
744
  // otherwise remove from slot
728
745
  if (slot > lastUserSlot) {
729
- const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
730
- perpMarketAccountMap.set(marketIndex, {
731
- pubkey: perpMarketAccount.pubkey,
732
- isSigner: false,
733
- isWritable: false,
734
- });
735
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
736
- pubkey: perpMarketAccount.amm.oracle,
737
- isSigner: false,
738
- isWritable: false,
739
- });
740
- const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
741
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
742
- pubkey: spotMarketAccount.pubkey,
743
- isSigner: false,
744
- isWritable: false,
745
- });
746
- if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
747
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
748
- pubkey: spotMarketAccount.oracle,
749
- isSigner: false,
750
- isWritable: false,
751
- });
752
- }
746
+ this.addPerpMarketToRemainingAccountMaps(marketIndex, false, oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap);
753
747
  }
754
748
  else {
755
749
  this.perpMarketLastSlotCache.delete(marketIndex);
@@ -759,19 +753,7 @@ class DriftClient {
759
753
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
760
754
  // otherwise remove from slot
761
755
  if (slot > lastUserSlot) {
762
- const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
763
- spotMarketAccountMap.set(marketIndex, {
764
- pubkey: spotMarketAccount.pubkey,
765
- isSigner: false,
766
- isWritable: false,
767
- });
768
- if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
769
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
770
- pubkey: spotMarketAccount.oracle,
771
- isSigner: false,
772
- isWritable: false,
773
- });
774
- }
756
+ this.addSpotMarketToRemainingAccountMaps(marketIndex, false, oracleAccountMap, spotMarketAccountMap);
775
757
  }
776
758
  else {
777
759
  this.spotMarketLastSlotCache.delete(marketIndex);
@@ -779,91 +761,32 @@ class DriftClient {
779
761
  }
780
762
  }
781
763
  if (params.readablePerpMarketIndex !== undefined) {
782
- const perpMarketAccount = this.getPerpMarketAccount(params.readablePerpMarketIndex);
783
- perpMarketAccountMap.set(params.readablePerpMarketIndex, {
784
- pubkey: perpMarketAccount.pubkey,
785
- isSigner: false,
786
- isWritable: false,
787
- });
788
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
789
- pubkey: perpMarketAccount.amm.oracle,
790
- isSigner: false,
791
- isWritable: false,
792
- });
793
- const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
794
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
795
- pubkey: spotMarketAccount.pubkey,
796
- isSigner: false,
797
- isWritable: false,
798
- });
799
- if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
800
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
801
- pubkey: spotMarketAccount.oracle,
802
- isSigner: false,
803
- isWritable: false,
804
- });
764
+ const readablePerpMarketIndexes = Array.isArray(params.readablePerpMarketIndex)
765
+ ? params.readablePerpMarketIndex
766
+ : [params.readablePerpMarketIndex];
767
+ for (const marketIndex of readablePerpMarketIndexes) {
768
+ this.addPerpMarketToRemainingAccountMaps(marketIndex, false, oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap);
805
769
  }
806
770
  }
771
+ for (const perpMarketIndex of this.mustIncludePerpMarketIndexes.values()) {
772
+ this.addPerpMarketToRemainingAccountMaps(perpMarketIndex, false, oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap);
773
+ }
807
774
  if (params.readableSpotMarketIndexes !== undefined) {
808
775
  for (const readableSpotMarketIndex of params.readableSpotMarketIndexes) {
809
- const spotMarketAccount = this.getSpotMarketAccount(readableSpotMarketIndex);
810
- spotMarketAccountMap.set(readableSpotMarketIndex, {
811
- pubkey: spotMarketAccount.pubkey,
812
- isSigner: false,
813
- isWritable: false,
814
- });
815
- if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
816
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
817
- pubkey: spotMarketAccount.oracle,
818
- isSigner: false,
819
- isWritable: false,
820
- });
821
- }
776
+ this.addSpotMarketToRemainingAccountMaps(readableSpotMarketIndex, false, oracleAccountMap, spotMarketAccountMap);
822
777
  }
823
778
  }
779
+ for (const spotMarketIndex of this.mustIncludeSpotMarketIndexes.values()) {
780
+ this.addSpotMarketToRemainingAccountMaps(spotMarketIndex, false, oracleAccountMap, spotMarketAccountMap);
781
+ }
824
782
  if (params.writablePerpMarketIndexes !== undefined) {
825
783
  for (const writablePerpMarketIndex of params.writablePerpMarketIndexes) {
826
- const perpMarketAccount = this.getPerpMarketAccount(writablePerpMarketIndex);
827
- perpMarketAccountMap.set(writablePerpMarketIndex, {
828
- pubkey: perpMarketAccount.pubkey,
829
- isSigner: false,
830
- isWritable: true,
831
- });
832
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
833
- pubkey: perpMarketAccount.amm.oracle,
834
- isSigner: false,
835
- isWritable: false,
836
- });
837
- const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
838
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
839
- pubkey: spotMarketAccount.pubkey,
840
- isSigner: false,
841
- isWritable: false,
842
- });
843
- if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
844
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
845
- pubkey: spotMarketAccount.oracle,
846
- isSigner: false,
847
- isWritable: false,
848
- });
849
- }
784
+ this.addPerpMarketToRemainingAccountMaps(writablePerpMarketIndex, true, oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap);
850
785
  }
851
786
  }
852
787
  if (params.writableSpotMarketIndexes !== undefined) {
853
788
  for (const writableSpotMarketIndex of params.writableSpotMarketIndexes) {
854
- const spotMarketAccount = this.getSpotMarketAccount(writableSpotMarketIndex);
855
- spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
856
- pubkey: spotMarketAccount.pubkey,
857
- isSigner: false,
858
- isWritable: true,
859
- });
860
- if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
861
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
862
- pubkey: spotMarketAccount.oracle,
863
- isSigner: false,
864
- isWritable: false,
865
- });
866
- }
789
+ this.addSpotMarketToRemainingAccountMaps(writableSpotMarketIndex, true, oracleAccountMap, spotMarketAccountMap);
867
790
  }
868
791
  }
869
792
  return [
@@ -872,6 +795,35 @@ class DriftClient {
872
795
  ...perpMarketAccountMap.values(),
873
796
  ];
874
797
  }
798
+ addPerpMarketToRemainingAccountMaps(marketIndex, writable, oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap) {
799
+ const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
800
+ perpMarketAccountMap.set(marketIndex, {
801
+ pubkey: perpMarketAccount.pubkey,
802
+ isSigner: false,
803
+ isWritable: writable,
804
+ });
805
+ oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
806
+ pubkey: perpMarketAccount.amm.oracle,
807
+ isSigner: false,
808
+ isWritable: false,
809
+ });
810
+ this.addSpotMarketToRemainingAccountMaps(perpMarketAccount.quoteSpotMarketIndex, false, oracleAccountMap, spotMarketAccountMap);
811
+ }
812
+ addSpotMarketToRemainingAccountMaps(marketIndex, writable, oracleAccountMap, spotMarketAccountMap) {
813
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
814
+ spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
815
+ pubkey: spotMarketAccount.pubkey,
816
+ isSigner: false,
817
+ isWritable: writable,
818
+ });
819
+ if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
820
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
821
+ pubkey: spotMarketAccount.oracle,
822
+ isSigner: false,
823
+ isWritable: false,
824
+ });
825
+ }
826
+ }
875
827
  getRemainingAccountMapsForUsers(userAccounts) {
876
828
  const oracleAccountMap = new Map();
877
829
  const spotMarketAccountMap = new Map();
@@ -879,63 +831,16 @@ class DriftClient {
879
831
  for (const userAccount of userAccounts) {
880
832
  for (const spotPosition of userAccount.spotPositions) {
881
833
  if (!(0, spotPosition_1.isSpotPositionAvailable)(spotPosition)) {
882
- const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
883
- spotMarketAccountMap.set(spotPosition.marketIndex, {
884
- pubkey: spotMarket.pubkey,
885
- isSigner: false,
886
- isWritable: false,
887
- });
888
- if (!spotMarket.oracle.equals(web3_js_1.PublicKey.default)) {
889
- oracleAccountMap.set(spotMarket.oracle.toString(), {
890
- pubkey: spotMarket.oracle,
891
- isSigner: false,
892
- isWritable: false,
893
- });
894
- }
834
+ this.addSpotMarketToRemainingAccountMaps(spotPosition.marketIndex, false, oracleAccountMap, spotMarketAccountMap);
895
835
  if (!spotPosition.openAsks.eq(numericConstants_1.ZERO) ||
896
836
  !spotPosition.openBids.eq(numericConstants_1.ZERO)) {
897
- const quoteSpotMarket = this.getQuoteSpotMarketAccount();
898
- spotMarketAccountMap.set(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, {
899
- pubkey: quoteSpotMarket.pubkey,
900
- isSigner: false,
901
- isWritable: false,
902
- });
903
- if (!quoteSpotMarket.oracle.equals(web3_js_1.PublicKey.default)) {
904
- oracleAccountMap.set(quoteSpotMarket.oracle.toString(), {
905
- pubkey: quoteSpotMarket.oracle,
906
- isSigner: false,
907
- isWritable: false,
908
- });
909
- }
837
+ this.addSpotMarketToRemainingAccountMaps(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, false, oracleAccountMap, spotMarketAccountMap);
910
838
  }
911
839
  }
912
840
  }
913
841
  for (const position of userAccount.perpPositions) {
914
842
  if (!(0, position_1.positionIsAvailable)(position)) {
915
- const perpMarketAccount = this.getPerpMarketAccount(position.marketIndex);
916
- perpMarketAccountMap.set(position.marketIndex, {
917
- pubkey: perpMarketAccount.pubkey,
918
- isWritable: false,
919
- isSigner: false,
920
- });
921
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
922
- pubkey: perpMarketAccount.amm.oracle,
923
- isWritable: false,
924
- isSigner: false,
925
- });
926
- const spotMarketAccount = this.getSpotMarketAccount(perpMarketAccount.quoteSpotMarketIndex);
927
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
928
- pubkey: spotMarketAccount.pubkey,
929
- isSigner: false,
930
- isWritable: false,
931
- });
932
- if (!spotMarketAccount.oracle.equals(web3_js_1.PublicKey.default)) {
933
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
934
- pubkey: spotMarketAccount.oracle,
935
- isSigner: false,
936
- isWritable: false,
937
- });
938
- }
843
+ this.addPerpMarketToRemainingAccountMaps(position.marketIndex, false, oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap);
939
844
  }
940
845
  }
941
846
  }
@@ -1646,23 +1551,45 @@ class DriftClient {
1646
1551
  });
1647
1552
  }
1648
1553
  async cancelAndPlaceOrders(cancelOrderParams, placeOrderParams, txParams) {
1649
- 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);
1650
- for (const placeOrderParam of placeOrderParams) {
1651
- const marketType = placeOrderParam.marketType;
1652
- if (!marketType) {
1653
- throw new Error('marketType must be set on placeOrderParams');
1654
- }
1655
- let ix;
1656
- if ((0, types_1.isVariant)(marketType, 'perp')) {
1657
- ix = this.getPlacePerpOrderIx(placeOrderParam);
1554
+ const ixs = [
1555
+ await this.getCancelOrdersIx(cancelOrderParams.marketType, cancelOrderParams.marketIndex, cancelOrderParams.direction),
1556
+ await this.getPlaceOrdersIx(placeOrderParams),
1557
+ ];
1558
+ const tx = await this.buildTransaction(ixs, txParams);
1559
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
1560
+ return txSig;
1561
+ }
1562
+ async placeOrders(params, txParams) {
1563
+ const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getPlaceOrdersIx(params), txParams), [], this.opts);
1564
+ return txSig;
1565
+ }
1566
+ async getPlaceOrdersIx(params) {
1567
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
1568
+ const readablePerpMarketIndex = [];
1569
+ const readableSpotMarketIndexes = [];
1570
+ for (const param of params) {
1571
+ if ((0, types_1.isVariant)(param.marketType, 'perp')) {
1572
+ readablePerpMarketIndex.push(param.marketIndex);
1658
1573
  }
1659
1574
  else {
1660
- ix = this.getPlaceSpotOrderIx(placeOrderParam);
1575
+ readableSpotMarketIndexes.push(param.marketIndex);
1661
1576
  }
1662
- tx.add(ix);
1663
1577
  }
1664
- const { txSig } = await this.sendTransaction(tx, [], this.opts);
1665
- return txSig;
1578
+ const remainingAccounts = this.getRemainingAccounts({
1579
+ userAccounts: [this.getUserAccount()],
1580
+ readablePerpMarketIndex,
1581
+ readableSpotMarketIndexes,
1582
+ useMarketLastSlotCache: true,
1583
+ });
1584
+ return await this.program.instruction.placeOrders(params, {
1585
+ accounts: {
1586
+ state: await this.getStatePublicKey(),
1587
+ user: userAccountPublicKey,
1588
+ userStats: this.getUserStatsAccountPublicKey(),
1589
+ authority: this.wallet.publicKey,
1590
+ },
1591
+ remainingAccounts,
1592
+ });
1666
1593
  }
1667
1594
  async fillPerpOrder(userAccountPublicKey, user, order, makerInfo, referrerInfo, txParams) {
1668
1595
  const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getFillPerpOrderIx(userAccountPublicKey, user, order, makerInfo, referrerInfo), txParams), [], this.opts);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.31.1-beta.10",
2
+ "version": "2.31.1-beta.11",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -710,6 +710,36 @@
710
710
  }
711
711
  ]
712
712
  },
713
+ {
714
+ "name": "placeOrders",
715
+ "accounts": [
716
+ {
717
+ "name": "state",
718
+ "isMut": false,
719
+ "isSigner": false
720
+ },
721
+ {
722
+ "name": "user",
723
+ "isMut": true,
724
+ "isSigner": false
725
+ },
726
+ {
727
+ "name": "authority",
728
+ "isMut": false,
729
+ "isSigner": true
730
+ }
731
+ ],
732
+ "args": [
733
+ {
734
+ "name": "params",
735
+ "type": {
736
+ "vec": {
737
+ "defined": "OrderParams"
738
+ }
739
+ }
740
+ }
741
+ ]
742
+ },
713
743
  {
714
744
  "name": "beginSwap",
715
745
  "accounts": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.31.1-beta.11",
3
+ "version": "2.31.1-beta.12",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -123,7 +123,7 @@ type RemainingAccountParams = {
123
123
  userAccounts: UserAccount[];
124
124
  writablePerpMarketIndexes?: number[];
125
125
  writableSpotMarketIndexes?: number[];
126
- readablePerpMarketIndex?: number;
126
+ readablePerpMarketIndex?: number | number[];
127
127
  readableSpotMarketIndexes?: number[];
128
128
  useMarketLastSlotCache?: boolean;
129
129
  };
@@ -149,6 +149,8 @@ export class DriftClient {
149
149
  txSender: TxSender;
150
150
  perpMarketLastSlotCache = new Map<number, number>();
151
151
  spotMarketLastSlotCache = new Map<number, number>();
152
+ mustIncludePerpMarketIndexes = new Set<number>();
153
+ mustIncludeSpotMarketIndexes = new Set<number>();
152
154
  authority: PublicKey;
153
155
  marketLookupTable: PublicKey;
154
156
  lookupTableAccount: AddressLookupTableAccount;
@@ -1198,6 +1200,29 @@ export class DriftClient {
1198
1200
  return amount.mul(PRICE_PRECISION);
1199
1201
  }
1200
1202
 
1203
+ /**
1204
+ * Each drift instruction must include perp and sport market accounts in the ix remaining accounts.
1205
+ * Use this function to force a subset of markets to be included in the remaining accounts for every ix
1206
+ *
1207
+ * @param perpMarketIndexes
1208
+ * @param spotMarketIndexes
1209
+ */
1210
+ public mustIncludeMarketsInIx({
1211
+ perpMarketIndexes,
1212
+ spotMarketIndexes,
1213
+ }: {
1214
+ perpMarketIndexes: number[];
1215
+ spotMarketIndexes: number[];
1216
+ }): void {
1217
+ perpMarketIndexes.forEach((perpMarketIndex) => {
1218
+ this.mustIncludePerpMarketIndexes.add(perpMarketIndex);
1219
+ });
1220
+
1221
+ spotMarketIndexes.forEach((spotMarketIndex) => {
1222
+ this.mustIncludeSpotMarketIndexes.add(spotMarketIndex);
1223
+ });
1224
+ }
1225
+
1201
1226
  getRemainingAccounts(params: RemainingAccountParams): AccountMeta[] {
1202
1227
  const { oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap } =
1203
1228
  this.getRemainingAccountMapsForUsers(params.userAccounts);
@@ -1211,32 +1236,13 @@ export class DriftClient {
1211
1236
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
1212
1237
  // otherwise remove from slot
1213
1238
  if (slot > lastUserSlot) {
1214
- const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
1215
- perpMarketAccountMap.set(marketIndex, {
1216
- pubkey: perpMarketAccount.pubkey,
1217
- isSigner: false,
1218
- isWritable: false,
1219
- });
1220
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1221
- pubkey: perpMarketAccount.amm.oracle,
1222
- isSigner: false,
1223
- isWritable: false,
1224
- });
1225
- const spotMarketAccount = this.getSpotMarketAccount(
1226
- perpMarketAccount.quoteSpotMarketIndex
1239
+ this.addPerpMarketToRemainingAccountMaps(
1240
+ marketIndex,
1241
+ false,
1242
+ oracleAccountMap,
1243
+ spotMarketAccountMap,
1244
+ perpMarketAccountMap
1227
1245
  );
1228
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1229
- pubkey: spotMarketAccount.pubkey,
1230
- isSigner: false,
1231
- isWritable: false,
1232
- });
1233
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1234
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1235
- pubkey: spotMarketAccount.oracle,
1236
- isSigner: false,
1237
- isWritable: false,
1238
- });
1239
- }
1240
1246
  } else {
1241
1247
  this.perpMarketLastSlotCache.delete(marketIndex);
1242
1248
  }
@@ -1249,19 +1255,12 @@ export class DriftClient {
1249
1255
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
1250
1256
  // otherwise remove from slot
1251
1257
  if (slot > lastUserSlot) {
1252
- const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1253
- spotMarketAccountMap.set(marketIndex, {
1254
- pubkey: spotMarketAccount.pubkey,
1255
- isSigner: false,
1256
- isWritable: false,
1257
- });
1258
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1259
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1260
- pubkey: spotMarketAccount.oracle,
1261
- isSigner: false,
1262
- isWritable: false,
1263
- });
1264
- }
1258
+ this.addSpotMarketToRemainingAccountMaps(
1259
+ marketIndex,
1260
+ false,
1261
+ oracleAccountMap,
1262
+ spotMarketAccountMap
1263
+ );
1265
1264
  } else {
1266
1265
  this.spotMarketLastSlotCache.delete(marketIndex);
1267
1266
  }
@@ -1269,106 +1268,72 @@ export class DriftClient {
1269
1268
  }
1270
1269
 
1271
1270
  if (params.readablePerpMarketIndex !== undefined) {
1272
- const perpMarketAccount = this.getPerpMarketAccount(
1271
+ const readablePerpMarketIndexes = Array.isArray(
1273
1272
  params.readablePerpMarketIndex
1274
- );
1275
- perpMarketAccountMap.set(params.readablePerpMarketIndex, {
1276
- pubkey: perpMarketAccount.pubkey,
1277
- isSigner: false,
1278
- isWritable: false,
1279
- });
1280
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1281
- pubkey: perpMarketAccount.amm.oracle,
1282
- isSigner: false,
1283
- isWritable: false,
1284
- });
1285
- const spotMarketAccount = this.getSpotMarketAccount(
1286
- perpMarketAccount.quoteSpotMarketIndex
1287
- );
1288
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1289
- pubkey: spotMarketAccount.pubkey,
1290
- isSigner: false,
1291
- isWritable: false,
1292
- });
1293
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1294
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1295
- pubkey: spotMarketAccount.oracle,
1296
- isSigner: false,
1297
- isWritable: false,
1298
- });
1273
+ )
1274
+ ? params.readablePerpMarketIndex
1275
+ : [params.readablePerpMarketIndex];
1276
+ for (const marketIndex of readablePerpMarketIndexes) {
1277
+ this.addPerpMarketToRemainingAccountMaps(
1278
+ marketIndex,
1279
+ false,
1280
+ oracleAccountMap,
1281
+ spotMarketAccountMap,
1282
+ perpMarketAccountMap
1283
+ );
1299
1284
  }
1300
1285
  }
1301
1286
 
1287
+ for (const perpMarketIndex of this.mustIncludePerpMarketIndexes.values()) {
1288
+ this.addPerpMarketToRemainingAccountMaps(
1289
+ perpMarketIndex,
1290
+ false,
1291
+ oracleAccountMap,
1292
+ spotMarketAccountMap,
1293
+ perpMarketAccountMap
1294
+ );
1295
+ }
1296
+
1302
1297
  if (params.readableSpotMarketIndexes !== undefined) {
1303
1298
  for (const readableSpotMarketIndex of params.readableSpotMarketIndexes) {
1304
- const spotMarketAccount = this.getSpotMarketAccount(
1305
- readableSpotMarketIndex
1299
+ this.addSpotMarketToRemainingAccountMaps(
1300
+ readableSpotMarketIndex,
1301
+ false,
1302
+ oracleAccountMap,
1303
+ spotMarketAccountMap
1306
1304
  );
1307
- spotMarketAccountMap.set(readableSpotMarketIndex, {
1308
- pubkey: spotMarketAccount.pubkey,
1309
- isSigner: false,
1310
- isWritable: false,
1311
- });
1312
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1313
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1314
- pubkey: spotMarketAccount.oracle,
1315
- isSigner: false,
1316
- isWritable: false,
1317
- });
1318
- }
1319
1305
  }
1320
1306
  }
1321
1307
 
1308
+ for (const spotMarketIndex of this.mustIncludeSpotMarketIndexes.values()) {
1309
+ this.addSpotMarketToRemainingAccountMaps(
1310
+ spotMarketIndex,
1311
+ false,
1312
+ oracleAccountMap,
1313
+ spotMarketAccountMap
1314
+ );
1315
+ }
1316
+
1322
1317
  if (params.writablePerpMarketIndexes !== undefined) {
1323
1318
  for (const writablePerpMarketIndex of params.writablePerpMarketIndexes) {
1324
- const perpMarketAccount = this.getPerpMarketAccount(
1325
- writablePerpMarketIndex
1319
+ this.addPerpMarketToRemainingAccountMaps(
1320
+ writablePerpMarketIndex,
1321
+ true,
1322
+ oracleAccountMap,
1323
+ spotMarketAccountMap,
1324
+ perpMarketAccountMap
1326
1325
  );
1327
- perpMarketAccountMap.set(writablePerpMarketIndex, {
1328
- pubkey: perpMarketAccount.pubkey,
1329
- isSigner: false,
1330
- isWritable: true,
1331
- });
1332
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1333
- pubkey: perpMarketAccount.amm.oracle,
1334
- isSigner: false,
1335
- isWritable: false,
1336
- });
1337
- const spotMarketAccount = this.getSpotMarketAccount(
1338
- perpMarketAccount.quoteSpotMarketIndex
1339
- );
1340
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1341
- pubkey: spotMarketAccount.pubkey,
1342
- isSigner: false,
1343
- isWritable: false,
1344
- });
1345
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1346
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1347
- pubkey: spotMarketAccount.oracle,
1348
- isSigner: false,
1349
- isWritable: false,
1350
- });
1351
- }
1352
1326
  }
1353
1327
  }
1354
1328
 
1355
1329
  if (params.writableSpotMarketIndexes !== undefined) {
1356
1330
  for (const writableSpotMarketIndex of params.writableSpotMarketIndexes) {
1357
- const spotMarketAccount = this.getSpotMarketAccount(
1358
- writableSpotMarketIndex
1331
+ this.addSpotMarketToRemainingAccountMaps(
1332
+ writableSpotMarketIndex,
1333
+ true,
1334
+ oracleAccountMap,
1335
+ spotMarketAccountMap
1359
1336
  );
1360
- spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
1361
- pubkey: spotMarketAccount.pubkey,
1362
- isSigner: false,
1363
- isWritable: true,
1364
- });
1365
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1366
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1367
- pubkey: spotMarketAccount.oracle,
1368
- isSigner: false,
1369
- isWritable: false,
1370
- });
1371
- }
1372
1337
  }
1373
1338
  }
1374
1339
 
@@ -1379,6 +1344,53 @@ export class DriftClient {
1379
1344
  ];
1380
1345
  }
1381
1346
 
1347
+ addPerpMarketToRemainingAccountMaps(
1348
+ marketIndex: number,
1349
+ writable: boolean,
1350
+ oracleAccountMap: Map<string, AccountMeta>,
1351
+ spotMarketAccountMap: Map<number, AccountMeta>,
1352
+ perpMarketAccountMap: Map<number, AccountMeta>
1353
+ ): void {
1354
+ const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
1355
+ perpMarketAccountMap.set(marketIndex, {
1356
+ pubkey: perpMarketAccount.pubkey,
1357
+ isSigner: false,
1358
+ isWritable: writable,
1359
+ });
1360
+ oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1361
+ pubkey: perpMarketAccount.amm.oracle,
1362
+ isSigner: false,
1363
+ isWritable: false,
1364
+ });
1365
+ this.addSpotMarketToRemainingAccountMaps(
1366
+ perpMarketAccount.quoteSpotMarketIndex,
1367
+ false,
1368
+ oracleAccountMap,
1369
+ spotMarketAccountMap
1370
+ );
1371
+ }
1372
+
1373
+ addSpotMarketToRemainingAccountMaps(
1374
+ marketIndex: number,
1375
+ writable: boolean,
1376
+ oracleAccountMap: Map<string, AccountMeta>,
1377
+ spotMarketAccountMap: Map<number, AccountMeta>
1378
+ ): void {
1379
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1380
+ spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
1381
+ pubkey: spotMarketAccount.pubkey,
1382
+ isSigner: false,
1383
+ isWritable: writable,
1384
+ });
1385
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1386
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1387
+ pubkey: spotMarketAccount.oracle,
1388
+ isSigner: false,
1389
+ isWritable: false,
1390
+ });
1391
+ }
1392
+ }
1393
+
1382
1394
  getRemainingAccountMapsForUsers(userAccounts: UserAccount[]): {
1383
1395
  oracleAccountMap: Map<string, AccountMeta>;
1384
1396
  spotMarketAccountMap: Map<number, AccountMeta>;
@@ -1391,73 +1403,35 @@ export class DriftClient {
1391
1403
  for (const userAccount of userAccounts) {
1392
1404
  for (const spotPosition of userAccount.spotPositions) {
1393
1405
  if (!isSpotPositionAvailable(spotPosition)) {
1394
- const spotMarket = this.getSpotMarketAccount(
1395
- spotPosition.marketIndex
1406
+ this.addSpotMarketToRemainingAccountMaps(
1407
+ spotPosition.marketIndex,
1408
+ false,
1409
+ oracleAccountMap,
1410
+ spotMarketAccountMap
1396
1411
  );
1397
- spotMarketAccountMap.set(spotPosition.marketIndex, {
1398
- pubkey: spotMarket.pubkey,
1399
- isSigner: false,
1400
- isWritable: false,
1401
- });
1402
-
1403
- if (!spotMarket.oracle.equals(PublicKey.default)) {
1404
- oracleAccountMap.set(spotMarket.oracle.toString(), {
1405
- pubkey: spotMarket.oracle,
1406
- isSigner: false,
1407
- isWritable: false,
1408
- });
1409
- }
1410
1412
 
1411
1413
  if (
1412
1414
  !spotPosition.openAsks.eq(ZERO) ||
1413
1415
  !spotPosition.openBids.eq(ZERO)
1414
1416
  ) {
1415
- const quoteSpotMarket = this.getQuoteSpotMarketAccount();
1416
- spotMarketAccountMap.set(QUOTE_SPOT_MARKET_INDEX, {
1417
- pubkey: quoteSpotMarket.pubkey,
1418
- isSigner: false,
1419
- isWritable: false,
1420
- });
1421
- if (!quoteSpotMarket.oracle.equals(PublicKey.default)) {
1422
- oracleAccountMap.set(quoteSpotMarket.oracle.toString(), {
1423
- pubkey: quoteSpotMarket.oracle,
1424
- isSigner: false,
1425
- isWritable: false,
1426
- });
1427
- }
1417
+ this.addSpotMarketToRemainingAccountMaps(
1418
+ QUOTE_SPOT_MARKET_INDEX,
1419
+ false,
1420
+ oracleAccountMap,
1421
+ spotMarketAccountMap
1422
+ );
1428
1423
  }
1429
1424
  }
1430
1425
  }
1431
1426
  for (const position of userAccount.perpPositions) {
1432
1427
  if (!positionIsAvailable(position)) {
1433
- const perpMarketAccount = this.getPerpMarketAccount(
1434
- position.marketIndex
1435
- );
1436
- perpMarketAccountMap.set(position.marketIndex, {
1437
- pubkey: perpMarketAccount.pubkey,
1438
- isWritable: false,
1439
- isSigner: false,
1440
- });
1441
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1442
- pubkey: perpMarketAccount.amm.oracle,
1443
- isWritable: false,
1444
- isSigner: false,
1445
- });
1446
- const spotMarketAccount = this.getSpotMarketAccount(
1447
- perpMarketAccount.quoteSpotMarketIndex
1428
+ this.addPerpMarketToRemainingAccountMaps(
1429
+ position.marketIndex,
1430
+ false,
1431
+ oracleAccountMap,
1432
+ spotMarketAccountMap,
1433
+ perpMarketAccountMap
1448
1434
  );
1449
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1450
- pubkey: spotMarketAccount.pubkey,
1451
- isSigner: false,
1452
- isWritable: false,
1453
- });
1454
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1455
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1456
- pubkey: spotMarketAccount.oracle,
1457
- isSigner: false,
1458
- isWritable: false,
1459
- });
1460
- }
1461
1435
  }
1462
1436
  }
1463
1437
  }
@@ -2816,32 +2790,65 @@ export class DriftClient {
2816
2790
  placeOrderParams: OrderParams[],
2817
2791
  txParams?: TxParams
2818
2792
  ): Promise<TransactionSignature> {
2819
- const tx = wrapInTx(
2793
+ const ixs = [
2820
2794
  await this.getCancelOrdersIx(
2821
2795
  cancelOrderParams.marketType,
2822
2796
  cancelOrderParams.marketIndex,
2823
2797
  cancelOrderParams.direction
2824
2798
  ),
2825
- txParams?.computeUnits,
2826
- txParams?.computeUnitsPrice
2799
+ await this.getPlaceOrdersIx(placeOrderParams),
2800
+ ];
2801
+ const tx = await this.buildTransaction(ixs, txParams);
2802
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
2803
+ return txSig;
2804
+ }
2805
+
2806
+ public async placeOrders(
2807
+ params: OrderParams[],
2808
+ txParams?: TxParams
2809
+ ): Promise<TransactionSignature> {
2810
+ const { txSig } = await this.sendTransaction(
2811
+ await this.buildTransaction(
2812
+ await this.getPlaceOrdersIx(params),
2813
+ txParams
2814
+ ),
2815
+ [],
2816
+ this.opts
2827
2817
  );
2818
+ return txSig;
2819
+ }
2828
2820
 
2829
- for (const placeOrderParam of placeOrderParams) {
2830
- const marketType = placeOrderParam.marketType;
2831
- if (!marketType) {
2832
- throw new Error('marketType must be set on placeOrderParams');
2833
- }
2834
- let ix;
2835
- if (isVariant(marketType, 'perp')) {
2836
- ix = this.getPlacePerpOrderIx(placeOrderParam);
2821
+ public async getPlaceOrdersIx(
2822
+ params: OrderParams[]
2823
+ ): Promise<TransactionInstruction> {
2824
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
2825
+
2826
+ const readablePerpMarketIndex: number[] = [];
2827
+ const readableSpotMarketIndexes: number[] = [];
2828
+ for (const param of params) {
2829
+ if (isVariant(param.marketType, 'perp')) {
2830
+ readablePerpMarketIndex.push(param.marketIndex);
2837
2831
  } else {
2838
- ix = this.getPlaceSpotOrderIx(placeOrderParam);
2832
+ readableSpotMarketIndexes.push(param.marketIndex);
2839
2833
  }
2840
- tx.add(ix);
2841
2834
  }
2842
2835
 
2843
- const { txSig } = await this.sendTransaction(tx, [], this.opts);
2844
- return txSig;
2836
+ const remainingAccounts = this.getRemainingAccounts({
2837
+ userAccounts: [this.getUserAccount()],
2838
+ readablePerpMarketIndex,
2839
+ readableSpotMarketIndexes,
2840
+ useMarketLastSlotCache: true,
2841
+ });
2842
+
2843
+ return await this.program.instruction.placeOrders(params, {
2844
+ accounts: {
2845
+ state: await this.getStatePublicKey(),
2846
+ user: userAccountPublicKey,
2847
+ userStats: this.getUserStatsAccountPublicKey(),
2848
+ authority: this.wallet.publicKey,
2849
+ },
2850
+ remainingAccounts,
2851
+ });
2845
2852
  }
2846
2853
 
2847
2854
  public async fillPerpOrder(
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.31.1-beta.11",
2
+ "version": "2.31.1-beta.12",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -710,6 +710,36 @@
710
710
  }
711
711
  ]
712
712
  },
713
+ {
714
+ "name": "placeOrders",
715
+ "accounts": [
716
+ {
717
+ "name": "state",
718
+ "isMut": false,
719
+ "isSigner": false
720
+ },
721
+ {
722
+ "name": "user",
723
+ "isMut": true,
724
+ "isSigner": false
725
+ },
726
+ {
727
+ "name": "authority",
728
+ "isMut": false,
729
+ "isSigner": true
730
+ }
731
+ ],
732
+ "args": [
733
+ {
734
+ "name": "params",
735
+ "type": {
736
+ "vec": {
737
+ "defined": "OrderParams"
738
+ }
739
+ }
740
+ }
741
+ ]
742
+ },
713
743
  {
714
744
  "name": "beginSwap",
715
745
  "accounts": [