@drift-labs/sdk 2.31.1-beta.9 → 2.32.0

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 (42) hide show
  1. package/VERSION +1 -1
  2. package/lib/constants/perpMarkets.js +20 -0
  3. package/lib/dlob/orderBookLevels.js +2 -2
  4. package/lib/driftClient.d.ts +51 -4
  5. package/lib/driftClient.js +195 -194
  6. package/lib/idl/drift.json +31 -1
  7. package/lib/index.d.ts +3 -0
  8. package/lib/index.js +3 -0
  9. package/lib/marinade/index.d.ts +11 -0
  10. package/lib/marinade/index.js +36 -0
  11. package/lib/marinade/types.d.ts +1963 -0
  12. package/lib/marinade/types.js +1965 -0
  13. package/lib/math/spotBalance.d.ts +9 -2
  14. package/lib/math/spotBalance.js +54 -6
  15. package/lib/math/superStake.d.ts +22 -0
  16. package/lib/math/superStake.js +108 -0
  17. package/lib/math/utils.d.ts +1 -0
  18. package/lib/math/utils.js +5 -1
  19. package/lib/orderParams.d.ts +18 -5
  20. package/lib/orderParams.js +17 -1
  21. package/lib/user.d.ts +45 -1
  22. package/lib/user.js +227 -9
  23. package/package.json +1 -1
  24. package/src/assert/assert.js +9 -0
  25. package/src/constants/perpMarkets.ts +20 -0
  26. package/src/dlob/orderBookLevels.ts +3 -2
  27. package/src/driftClient.ts +373 -223
  28. package/src/idl/drift.json +31 -1
  29. package/src/index.ts +3 -0
  30. package/src/marinade/idl/idl.json +1962 -0
  31. package/src/marinade/index.ts +64 -0
  32. package/src/marinade/types.ts +3925 -0
  33. package/src/math/spotBalance.ts +83 -5
  34. package/src/math/superStake.ts +148 -0
  35. package/src/math/utils.ts +4 -0
  36. package/src/orderParams.ts +35 -5
  37. package/src/token/index.js +38 -0
  38. package/src/user.ts +453 -15
  39. package/src/util/computeUnits.js +27 -0
  40. package/src/util/promiseTimeout.js +14 -0
  41. package/src/util/tps.js +27 -0
  42. package/tests/spot/test.ts +156 -0
@@ -27,7 +27,6 @@ import {
27
27
  MakerInfo,
28
28
  TakerInfo,
29
29
  OptionalOrderParams,
30
- DefaultOrderParams,
31
30
  OrderType,
32
31
  ReferrerInfo,
33
32
  MarketType,
@@ -117,12 +116,14 @@ import { castNumberToSpotPrecision } from './math/spotMarket';
117
116
  import { JupiterClient, Route, SwapMode } from './jupiter/jupiterClient';
118
117
  import { getNonIdleUserFilter } from './memcmp';
119
118
  import { UserStatsSubscriptionConfig } from './userStatsConfig';
119
+ import { getMarinadeDepositIx, getMarinadeFinanceProgram } from './marinade';
120
+ import { getOrderParams } from './orderParams';
120
121
 
121
122
  type RemainingAccountParams = {
122
123
  userAccounts: UserAccount[];
123
124
  writablePerpMarketIndexes?: number[];
124
125
  writableSpotMarketIndexes?: number[];
125
- readablePerpMarketIndex?: number;
126
+ readablePerpMarketIndex?: number | number[];
126
127
  readableSpotMarketIndexes?: number[];
127
128
  useMarketLastSlotCache?: boolean;
128
129
  };
@@ -148,6 +149,8 @@ export class DriftClient {
148
149
  txSender: TxSender;
149
150
  perpMarketLastSlotCache = new Map<number, number>();
150
151
  spotMarketLastSlotCache = new Map<number, number>();
152
+ mustIncludePerpMarketIndexes = new Set<number>();
153
+ mustIncludeSpotMarketIndexes = new Set<number>();
151
154
  authority: PublicKey;
152
155
  marketLookupTable: PublicKey;
153
156
  lookupTableAccount: AddressLookupTableAccount;
@@ -860,6 +863,43 @@ export class DriftClient {
860
863
  return txSig;
861
864
  }
862
865
 
866
+ public async getUpdateUserMarginTradingEnabledIx(
867
+ marginTradingEnabled: boolean,
868
+ subAccountId = 0,
869
+ userAccountPublicKey?: PublicKey
870
+ ): Promise<TransactionInstruction> {
871
+ const userAccountPublicKeyToUse =
872
+ userAccountPublicKey ||
873
+ getUserAccountPublicKeySync(
874
+ this.program.programId,
875
+ this.wallet.publicKey,
876
+ subAccountId
877
+ );
878
+
879
+ await this.addUser(subAccountId, this.wallet.publicKey);
880
+
881
+ let remainingAccounts;
882
+ try {
883
+ remainingAccounts = this.getRemainingAccounts({
884
+ userAccounts: [this.getUserAccount(subAccountId)],
885
+ });
886
+ } catch (err) {
887
+ remainingAccounts = [];
888
+ }
889
+
890
+ return await this.program.instruction.updateUserMarginTradingEnabled(
891
+ subAccountId,
892
+ marginTradingEnabled,
893
+ {
894
+ accounts: {
895
+ user: userAccountPublicKeyToUse,
896
+ authority: this.wallet.publicKey,
897
+ },
898
+ remainingAccounts,
899
+ }
900
+ );
901
+ }
902
+
863
903
  public async updateUserMarginTradingEnabled(
864
904
  marginTradingEnabled: boolean,
865
905
  subAccountId = 0
@@ -1197,6 +1237,29 @@ export class DriftClient {
1197
1237
  return amount.mul(PRICE_PRECISION);
1198
1238
  }
1199
1239
 
1240
+ /**
1241
+ * Each drift instruction must include perp and sport market accounts in the ix remaining accounts.
1242
+ * Use this function to force a subset of markets to be included in the remaining accounts for every ix
1243
+ *
1244
+ * @param perpMarketIndexes
1245
+ * @param spotMarketIndexes
1246
+ */
1247
+ public mustIncludeMarketsInIx({
1248
+ perpMarketIndexes,
1249
+ spotMarketIndexes,
1250
+ }: {
1251
+ perpMarketIndexes: number[];
1252
+ spotMarketIndexes: number[];
1253
+ }): void {
1254
+ perpMarketIndexes.forEach((perpMarketIndex) => {
1255
+ this.mustIncludePerpMarketIndexes.add(perpMarketIndex);
1256
+ });
1257
+
1258
+ spotMarketIndexes.forEach((spotMarketIndex) => {
1259
+ this.mustIncludeSpotMarketIndexes.add(spotMarketIndex);
1260
+ });
1261
+ }
1262
+
1200
1263
  getRemainingAccounts(params: RemainingAccountParams): AccountMeta[] {
1201
1264
  const { oracleAccountMap, spotMarketAccountMap, perpMarketAccountMap } =
1202
1265
  this.getRemainingAccountMapsForUsers(params.userAccounts);
@@ -1210,32 +1273,13 @@ export class DriftClient {
1210
1273
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
1211
1274
  // otherwise remove from slot
1212
1275
  if (slot > lastUserSlot) {
1213
- const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
1214
- perpMarketAccountMap.set(marketIndex, {
1215
- pubkey: perpMarketAccount.pubkey,
1216
- isSigner: false,
1217
- isWritable: false,
1218
- });
1219
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1220
- pubkey: perpMarketAccount.amm.oracle,
1221
- isSigner: false,
1222
- isWritable: false,
1223
- });
1224
- const spotMarketAccount = this.getSpotMarketAccount(
1225
- perpMarketAccount.quoteSpotMarketIndex
1276
+ this.addPerpMarketToRemainingAccountMaps(
1277
+ marketIndex,
1278
+ false,
1279
+ oracleAccountMap,
1280
+ spotMarketAccountMap,
1281
+ perpMarketAccountMap
1226
1282
  );
1227
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1228
- pubkey: spotMarketAccount.pubkey,
1229
- isSigner: false,
1230
- isWritable: false,
1231
- });
1232
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1233
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1234
- pubkey: spotMarketAccount.oracle,
1235
- isSigner: false,
1236
- isWritable: false,
1237
- });
1238
- }
1239
1283
  } else {
1240
1284
  this.perpMarketLastSlotCache.delete(marketIndex);
1241
1285
  }
@@ -1248,19 +1292,12 @@ export class DriftClient {
1248
1292
  // if cache has more recent slot than user positions account slot, add market to remaining accounts
1249
1293
  // otherwise remove from slot
1250
1294
  if (slot > lastUserSlot) {
1251
- const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1252
- spotMarketAccountMap.set(marketIndex, {
1253
- pubkey: spotMarketAccount.pubkey,
1254
- isSigner: false,
1255
- isWritable: false,
1256
- });
1257
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1258
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1259
- pubkey: spotMarketAccount.oracle,
1260
- isSigner: false,
1261
- isWritable: false,
1262
- });
1263
- }
1295
+ this.addSpotMarketToRemainingAccountMaps(
1296
+ marketIndex,
1297
+ false,
1298
+ oracleAccountMap,
1299
+ spotMarketAccountMap
1300
+ );
1264
1301
  } else {
1265
1302
  this.spotMarketLastSlotCache.delete(marketIndex);
1266
1303
  }
@@ -1268,106 +1305,72 @@ export class DriftClient {
1268
1305
  }
1269
1306
 
1270
1307
  if (params.readablePerpMarketIndex !== undefined) {
1271
- const perpMarketAccount = this.getPerpMarketAccount(
1308
+ const readablePerpMarketIndexes = Array.isArray(
1272
1309
  params.readablePerpMarketIndex
1273
- );
1274
- perpMarketAccountMap.set(params.readablePerpMarketIndex, {
1275
- pubkey: perpMarketAccount.pubkey,
1276
- isSigner: false,
1277
- isWritable: false,
1278
- });
1279
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1280
- pubkey: perpMarketAccount.amm.oracle,
1281
- isSigner: false,
1282
- isWritable: false,
1283
- });
1284
- const spotMarketAccount = this.getSpotMarketAccount(
1285
- perpMarketAccount.quoteSpotMarketIndex
1286
- );
1287
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1288
- pubkey: spotMarketAccount.pubkey,
1289
- isSigner: false,
1290
- isWritable: false,
1291
- });
1292
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1293
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1294
- pubkey: spotMarketAccount.oracle,
1295
- isSigner: false,
1296
- isWritable: false,
1297
- });
1310
+ )
1311
+ ? params.readablePerpMarketIndex
1312
+ : [params.readablePerpMarketIndex];
1313
+ for (const marketIndex of readablePerpMarketIndexes) {
1314
+ this.addPerpMarketToRemainingAccountMaps(
1315
+ marketIndex,
1316
+ false,
1317
+ oracleAccountMap,
1318
+ spotMarketAccountMap,
1319
+ perpMarketAccountMap
1320
+ );
1298
1321
  }
1299
1322
  }
1300
1323
 
1324
+ for (const perpMarketIndex of this.mustIncludePerpMarketIndexes.values()) {
1325
+ this.addPerpMarketToRemainingAccountMaps(
1326
+ perpMarketIndex,
1327
+ false,
1328
+ oracleAccountMap,
1329
+ spotMarketAccountMap,
1330
+ perpMarketAccountMap
1331
+ );
1332
+ }
1333
+
1301
1334
  if (params.readableSpotMarketIndexes !== undefined) {
1302
1335
  for (const readableSpotMarketIndex of params.readableSpotMarketIndexes) {
1303
- const spotMarketAccount = this.getSpotMarketAccount(
1304
- readableSpotMarketIndex
1336
+ this.addSpotMarketToRemainingAccountMaps(
1337
+ readableSpotMarketIndex,
1338
+ false,
1339
+ oracleAccountMap,
1340
+ spotMarketAccountMap
1305
1341
  );
1306
- spotMarketAccountMap.set(readableSpotMarketIndex, {
1307
- pubkey: spotMarketAccount.pubkey,
1308
- isSigner: false,
1309
- isWritable: false,
1310
- });
1311
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1312
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1313
- pubkey: spotMarketAccount.oracle,
1314
- isSigner: false,
1315
- isWritable: false,
1316
- });
1317
- }
1318
1342
  }
1319
1343
  }
1320
1344
 
1345
+ for (const spotMarketIndex of this.mustIncludeSpotMarketIndexes.values()) {
1346
+ this.addSpotMarketToRemainingAccountMaps(
1347
+ spotMarketIndex,
1348
+ false,
1349
+ oracleAccountMap,
1350
+ spotMarketAccountMap
1351
+ );
1352
+ }
1353
+
1321
1354
  if (params.writablePerpMarketIndexes !== undefined) {
1322
1355
  for (const writablePerpMarketIndex of params.writablePerpMarketIndexes) {
1323
- const perpMarketAccount = this.getPerpMarketAccount(
1324
- writablePerpMarketIndex
1356
+ this.addPerpMarketToRemainingAccountMaps(
1357
+ writablePerpMarketIndex,
1358
+ true,
1359
+ oracleAccountMap,
1360
+ spotMarketAccountMap,
1361
+ perpMarketAccountMap
1325
1362
  );
1326
- perpMarketAccountMap.set(writablePerpMarketIndex, {
1327
- pubkey: perpMarketAccount.pubkey,
1328
- isSigner: false,
1329
- isWritable: true,
1330
- });
1331
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1332
- pubkey: perpMarketAccount.amm.oracle,
1333
- isSigner: false,
1334
- isWritable: false,
1335
- });
1336
- const spotMarketAccount = this.getSpotMarketAccount(
1337
- perpMarketAccount.quoteSpotMarketIndex
1338
- );
1339
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1340
- pubkey: spotMarketAccount.pubkey,
1341
- isSigner: false,
1342
- isWritable: false,
1343
- });
1344
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1345
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1346
- pubkey: spotMarketAccount.oracle,
1347
- isSigner: false,
1348
- isWritable: false,
1349
- });
1350
- }
1351
1363
  }
1352
1364
  }
1353
1365
 
1354
1366
  if (params.writableSpotMarketIndexes !== undefined) {
1355
1367
  for (const writableSpotMarketIndex of params.writableSpotMarketIndexes) {
1356
- const spotMarketAccount = this.getSpotMarketAccount(
1357
- writableSpotMarketIndex
1368
+ this.addSpotMarketToRemainingAccountMaps(
1369
+ writableSpotMarketIndex,
1370
+ true,
1371
+ oracleAccountMap,
1372
+ spotMarketAccountMap
1358
1373
  );
1359
- spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
1360
- pubkey: spotMarketAccount.pubkey,
1361
- isSigner: false,
1362
- isWritable: true,
1363
- });
1364
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1365
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1366
- pubkey: spotMarketAccount.oracle,
1367
- isSigner: false,
1368
- isWritable: false,
1369
- });
1370
- }
1371
1374
  }
1372
1375
  }
1373
1376
 
@@ -1378,6 +1381,53 @@ export class DriftClient {
1378
1381
  ];
1379
1382
  }
1380
1383
 
1384
+ addPerpMarketToRemainingAccountMaps(
1385
+ marketIndex: number,
1386
+ writable: boolean,
1387
+ oracleAccountMap: Map<string, AccountMeta>,
1388
+ spotMarketAccountMap: Map<number, AccountMeta>,
1389
+ perpMarketAccountMap: Map<number, AccountMeta>
1390
+ ): void {
1391
+ const perpMarketAccount = this.getPerpMarketAccount(marketIndex);
1392
+ perpMarketAccountMap.set(marketIndex, {
1393
+ pubkey: perpMarketAccount.pubkey,
1394
+ isSigner: false,
1395
+ isWritable: writable,
1396
+ });
1397
+ oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1398
+ pubkey: perpMarketAccount.amm.oracle,
1399
+ isSigner: false,
1400
+ isWritable: false,
1401
+ });
1402
+ this.addSpotMarketToRemainingAccountMaps(
1403
+ perpMarketAccount.quoteSpotMarketIndex,
1404
+ false,
1405
+ oracleAccountMap,
1406
+ spotMarketAccountMap
1407
+ );
1408
+ }
1409
+
1410
+ addSpotMarketToRemainingAccountMaps(
1411
+ marketIndex: number,
1412
+ writable: boolean,
1413
+ oracleAccountMap: Map<string, AccountMeta>,
1414
+ spotMarketAccountMap: Map<number, AccountMeta>
1415
+ ): void {
1416
+ const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
1417
+ spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
1418
+ pubkey: spotMarketAccount.pubkey,
1419
+ isSigner: false,
1420
+ isWritable: writable,
1421
+ });
1422
+ if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1423
+ oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1424
+ pubkey: spotMarketAccount.oracle,
1425
+ isSigner: false,
1426
+ isWritable: false,
1427
+ });
1428
+ }
1429
+ }
1430
+
1381
1431
  getRemainingAccountMapsForUsers(userAccounts: UserAccount[]): {
1382
1432
  oracleAccountMap: Map<string, AccountMeta>;
1383
1433
  spotMarketAccountMap: Map<number, AccountMeta>;
@@ -1390,73 +1440,35 @@ export class DriftClient {
1390
1440
  for (const userAccount of userAccounts) {
1391
1441
  for (const spotPosition of userAccount.spotPositions) {
1392
1442
  if (!isSpotPositionAvailable(spotPosition)) {
1393
- const spotMarket = this.getSpotMarketAccount(
1394
- spotPosition.marketIndex
1443
+ this.addSpotMarketToRemainingAccountMaps(
1444
+ spotPosition.marketIndex,
1445
+ false,
1446
+ oracleAccountMap,
1447
+ spotMarketAccountMap
1395
1448
  );
1396
- spotMarketAccountMap.set(spotPosition.marketIndex, {
1397
- pubkey: spotMarket.pubkey,
1398
- isSigner: false,
1399
- isWritable: false,
1400
- });
1401
-
1402
- if (!spotMarket.oracle.equals(PublicKey.default)) {
1403
- oracleAccountMap.set(spotMarket.oracle.toString(), {
1404
- pubkey: spotMarket.oracle,
1405
- isSigner: false,
1406
- isWritable: false,
1407
- });
1408
- }
1409
1449
 
1410
1450
  if (
1411
1451
  !spotPosition.openAsks.eq(ZERO) ||
1412
1452
  !spotPosition.openBids.eq(ZERO)
1413
1453
  ) {
1414
- const quoteSpotMarket = this.getQuoteSpotMarketAccount();
1415
- spotMarketAccountMap.set(QUOTE_SPOT_MARKET_INDEX, {
1416
- pubkey: quoteSpotMarket.pubkey,
1417
- isSigner: false,
1418
- isWritable: false,
1419
- });
1420
- if (!quoteSpotMarket.oracle.equals(PublicKey.default)) {
1421
- oracleAccountMap.set(quoteSpotMarket.oracle.toString(), {
1422
- pubkey: quoteSpotMarket.oracle,
1423
- isSigner: false,
1424
- isWritable: false,
1425
- });
1426
- }
1454
+ this.addSpotMarketToRemainingAccountMaps(
1455
+ QUOTE_SPOT_MARKET_INDEX,
1456
+ false,
1457
+ oracleAccountMap,
1458
+ spotMarketAccountMap
1459
+ );
1427
1460
  }
1428
1461
  }
1429
1462
  }
1430
1463
  for (const position of userAccount.perpPositions) {
1431
1464
  if (!positionIsAvailable(position)) {
1432
- const perpMarketAccount = this.getPerpMarketAccount(
1433
- position.marketIndex
1434
- );
1435
- perpMarketAccountMap.set(position.marketIndex, {
1436
- pubkey: perpMarketAccount.pubkey,
1437
- isWritable: false,
1438
- isSigner: false,
1439
- });
1440
- oracleAccountMap.set(perpMarketAccount.amm.oracle.toString(), {
1441
- pubkey: perpMarketAccount.amm.oracle,
1442
- isWritable: false,
1443
- isSigner: false,
1444
- });
1445
- const spotMarketAccount = this.getSpotMarketAccount(
1446
- perpMarketAccount.quoteSpotMarketIndex
1465
+ this.addPerpMarketToRemainingAccountMaps(
1466
+ position.marketIndex,
1467
+ false,
1468
+ oracleAccountMap,
1469
+ spotMarketAccountMap,
1470
+ perpMarketAccountMap
1447
1471
  );
1448
- spotMarketAccountMap.set(perpMarketAccount.quoteSpotMarketIndex, {
1449
- pubkey: spotMarketAccount.pubkey,
1450
- isSigner: false,
1451
- isWritable: false,
1452
- });
1453
- if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
1454
- oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
1455
- pubkey: spotMarketAccount.oracle,
1456
- isSigner: false,
1457
- isWritable: false,
1458
- });
1459
- }
1460
1472
  }
1461
1473
  }
1462
1474
  }
@@ -1660,7 +1672,7 @@ export class DriftClient {
1660
1672
  }
1661
1673
  }
1662
1674
 
1663
- private async getWrappedSolAccountCreationIxs(
1675
+ public async getWrappedSolAccountCreationIxs(
1664
1676
  amount: BN,
1665
1677
  includeRent?: boolean
1666
1678
  ): Promise<{
@@ -2510,19 +2522,10 @@ export class DriftClient {
2510
2522
  return txSig;
2511
2523
  }
2512
2524
 
2513
- getOrderParams(
2514
- optionalOrderParams: OptionalOrderParams,
2515
- marketType: MarketType
2516
- ): OrderParams {
2517
- return Object.assign({}, DefaultOrderParams, optionalOrderParams, {
2518
- marketType,
2519
- });
2520
- }
2521
-
2522
2525
  public async getPlacePerpOrderIx(
2523
2526
  orderParams: OptionalOrderParams
2524
2527
  ): Promise<TransactionInstruction> {
2525
- orderParams = this.getOrderParams(orderParams, MarketType.PERP);
2528
+ orderParams = getOrderParams(orderParams, { marketType: MarketType.PERP });
2526
2529
  const userAccountPublicKey = await this.getUserAccountPublicKey();
2527
2530
 
2528
2531
  const remainingAccounts = this.getRemainingAccounts({
@@ -2815,32 +2818,68 @@ export class DriftClient {
2815
2818
  placeOrderParams: OrderParams[],
2816
2819
  txParams?: TxParams
2817
2820
  ): Promise<TransactionSignature> {
2818
- const tx = wrapInTx(
2821
+ const ixs = [
2819
2822
  await this.getCancelOrdersIx(
2820
2823
  cancelOrderParams.marketType,
2821
2824
  cancelOrderParams.marketIndex,
2822
2825
  cancelOrderParams.direction
2823
2826
  ),
2824
- txParams?.computeUnits,
2825
- txParams?.computeUnitsPrice
2827
+ await this.getPlaceOrdersIx(placeOrderParams),
2828
+ ];
2829
+ const tx = await this.buildTransaction(ixs, txParams);
2830
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
2831
+ return txSig;
2832
+ }
2833
+
2834
+ public async placeOrders(
2835
+ params: OrderParams[],
2836
+ txParams?: TxParams
2837
+ ): Promise<TransactionSignature> {
2838
+ const { txSig } = await this.sendTransaction(
2839
+ await this.buildTransaction(
2840
+ await this.getPlaceOrdersIx(params),
2841
+ txParams
2842
+ ),
2843
+ [],
2844
+ this.opts
2826
2845
  );
2846
+ return txSig;
2847
+ }
2848
+
2849
+ public async getPlaceOrdersIx(
2850
+ params: OrderParams[]
2851
+ ): Promise<TransactionInstruction> {
2852
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
2827
2853
 
2828
- for (const placeOrderParam of placeOrderParams) {
2829
- const marketType = placeOrderParam.marketType;
2830
- if (!marketType) {
2831
- throw new Error('marketType must be set on placeOrderParams');
2854
+ const readablePerpMarketIndex: number[] = [];
2855
+ const readableSpotMarketIndexes: number[] = [];
2856
+ for (const param of params) {
2857
+ if (!param.marketType) {
2858
+ throw new Error('must set param.marketType');
2832
2859
  }
2833
- let ix;
2834
- if (isVariant(marketType, 'perp')) {
2835
- ix = this.getPlacePerpOrderIx(placeOrderParam);
2860
+ if (isVariant(param.marketType, 'perp')) {
2861
+ readablePerpMarketIndex.push(param.marketIndex);
2836
2862
  } else {
2837
- ix = this.getPlaceSpotOrderIx(placeOrderParam);
2863
+ readableSpotMarketIndexes.push(param.marketIndex);
2838
2864
  }
2839
- tx.add(ix);
2840
2865
  }
2841
2866
 
2842
- const { txSig } = await this.sendTransaction(tx, [], this.opts);
2843
- return txSig;
2867
+ const remainingAccounts = this.getRemainingAccounts({
2868
+ userAccounts: [this.getUserAccount()],
2869
+ readablePerpMarketIndex,
2870
+ readableSpotMarketIndexes,
2871
+ useMarketLastSlotCache: true,
2872
+ });
2873
+
2874
+ return await this.program.instruction.placeOrders(params, {
2875
+ accounts: {
2876
+ state: await this.getStatePublicKey(),
2877
+ user: userAccountPublicKey,
2878
+ userStats: this.getUserStatsAccountPublicKey(),
2879
+ authority: this.wallet.publicKey,
2880
+ },
2881
+ remainingAccounts,
2882
+ });
2844
2883
  }
2845
2884
 
2846
2885
  public async fillPerpOrder(
@@ -2983,7 +3022,7 @@ export class DriftClient {
2983
3022
  public async getPlaceSpotOrderIx(
2984
3023
  orderParams: OptionalOrderParams
2985
3024
  ): Promise<TransactionInstruction> {
2986
- orderParams = this.getOrderParams(orderParams, MarketType.SPOT);
3025
+ orderParams = getOrderParams(orderParams, { marketType: MarketType.SPOT });
2987
3026
  const userAccountPublicKey = await this.getUserAccountPublicKey();
2988
3027
 
2989
3028
  const remainingAccounts = this.getRemainingAccounts({
@@ -3343,6 +3382,61 @@ export class DriftClient {
3343
3382
  reduceOnly?: SwapReduceOnly;
3344
3383
  txParams?: TxParams;
3345
3384
  }): Promise<TransactionSignature> {
3385
+ const { ixs, lookupTables } = await this.getJupiterSwapIx({
3386
+ jupiterClient,
3387
+ outMarketIndex,
3388
+ inMarketIndex,
3389
+ outAssociatedTokenAccount,
3390
+ inAssociatedTokenAccount,
3391
+ amount,
3392
+ slippageBps,
3393
+ swapMode,
3394
+ route,
3395
+ reduceOnly,
3396
+ });
3397
+
3398
+ const tx = (await this.buildTransaction(
3399
+ ixs,
3400
+ txParams,
3401
+ 0,
3402
+ lookupTables
3403
+ )) as VersionedTransaction;
3404
+
3405
+ const { txSig, slot } = await this.sendTransaction(tx);
3406
+ this.spotMarketLastSlotCache.set(outMarketIndex, slot);
3407
+ this.spotMarketLastSlotCache.set(inMarketIndex, slot);
3408
+
3409
+ return txSig;
3410
+ }
3411
+
3412
+ public async getJupiterSwapIx({
3413
+ jupiterClient,
3414
+ outMarketIndex,
3415
+ inMarketIndex,
3416
+ outAssociatedTokenAccount,
3417
+ inAssociatedTokenAccount,
3418
+ amount,
3419
+ slippageBps,
3420
+ swapMode,
3421
+ route,
3422
+ reduceOnly,
3423
+ userAccountPublicKey,
3424
+ }: {
3425
+ jupiterClient: JupiterClient;
3426
+ outMarketIndex: number;
3427
+ inMarketIndex: number;
3428
+ outAssociatedTokenAccount?: PublicKey;
3429
+ inAssociatedTokenAccount?: PublicKey;
3430
+ amount: BN;
3431
+ slippageBps?: number;
3432
+ swapMode?: SwapMode;
3433
+ route?: Route;
3434
+ reduceOnly?: SwapReduceOnly;
3435
+ userAccountPublicKey?: PublicKey;
3436
+ }): Promise<{
3437
+ ixs: TransactionInstruction[];
3438
+ lookupTables: AddressLookupTableAccount[];
3439
+ }> {
3346
3440
  const outMarket = this.getSpotMarketAccount(outMarketIndex);
3347
3441
  const inMarket = this.getSpotMarketAccount(inMarketIndex);
3348
3442
 
@@ -3429,27 +3523,17 @@ export class DriftClient {
3429
3523
  inTokenAccount: inAssociatedTokenAccount,
3430
3524
  outTokenAccount: outAssociatedTokenAccount,
3431
3525
  reduceOnly,
3526
+ userAccountPublicKey,
3432
3527
  });
3433
3528
 
3434
- const instructions = [
3529
+ const ixs = [
3435
3530
  ...preInstructions,
3436
3531
  beginSwapIx,
3437
3532
  ...jupiterInstructions,
3438
3533
  endSwapIx,
3439
3534
  ];
3440
3535
 
3441
- const tx = (await this.buildTransaction(
3442
- instructions,
3443
- txParams,
3444
- 0,
3445
- lookupTables
3446
- )) as VersionedTransaction;
3447
-
3448
- const { txSig, slot } = await this.sendTransaction(tx);
3449
- this.spotMarketLastSlotCache.set(outMarketIndex, slot);
3450
- this.spotMarketLastSlotCache.set(inMarketIndex, slot);
3451
-
3452
- return txSig;
3536
+ return { ixs, lookupTables };
3453
3537
  }
3454
3538
 
3455
3539
  /**
@@ -3461,6 +3545,8 @@ export class DriftClient {
3461
3545
  * @param inTokenAccount the token account to move the tokens being sold
3462
3546
  * @param outTokenAccount the token account to receive the tokens being bought
3463
3547
  * @param limitPrice the limit price of the swap
3548
+ * @param reduceOnly
3549
+ * @param userAccountPublicKey optional, specify a custom userAccountPublicKey to use instead of getting the current user account; can be helpful if the account is being created within the current tx
3464
3550
  */
3465
3551
  public async getSwapIx({
3466
3552
  outMarketIndex,
@@ -3470,6 +3556,7 @@ export class DriftClient {
3470
3556
  outTokenAccount,
3471
3557
  limitPrice,
3472
3558
  reduceOnly,
3559
+ userAccountPublicKey,
3473
3560
  }: {
3474
3561
  outMarketIndex: number;
3475
3562
  inMarketIndex: number;
@@ -3478,14 +3565,17 @@ export class DriftClient {
3478
3565
  outTokenAccount: PublicKey;
3479
3566
  limitPrice?: BN;
3480
3567
  reduceOnly?: SwapReduceOnly;
3568
+ userAccountPublicKey?: PublicKey;
3481
3569
  }): Promise<{
3482
3570
  beginSwapIx: TransactionInstruction;
3483
3571
  endSwapIx: TransactionInstruction;
3484
3572
  }> {
3485
- const userAccountPublicKey = await this.getUserAccountPublicKey();
3573
+ const userAccountPublicKeyToUse =
3574
+ userAccountPublicKey || (await this.getUserAccountPublicKey());
3486
3575
 
3576
+ const userAccounts = this.hasUser() ? [this.getUserAccount()] : [];
3487
3577
  const remainingAccounts = this.getRemainingAccounts({
3488
- userAccounts: [this.getUserAccount()],
3578
+ userAccounts,
3489
3579
  writableSpotMarketIndexes: [outMarketIndex, inMarketIndex],
3490
3580
  });
3491
3581
 
@@ -3499,7 +3589,7 @@ export class DriftClient {
3499
3589
  {
3500
3590
  accounts: {
3501
3591
  state: await this.getStatePublicKey(),
3502
- user: userAccountPublicKey,
3592
+ user: userAccountPublicKeyToUse,
3503
3593
  userStats: this.getUserStatsAccountPublicKey(),
3504
3594
  authority: this.authority,
3505
3595
  outSpotMarketVault: outSpotMarket.vault,
@@ -3522,7 +3612,7 @@ export class DriftClient {
3522
3612
  {
3523
3613
  accounts: {
3524
3614
  state: await this.getStatePublicKey(),
3525
- user: userAccountPublicKey,
3615
+ user: userAccountPublicKeyToUse,
3526
3616
  userStats: this.getUserStatsAccountPublicKey(),
3527
3617
  authority: this.authority,
3528
3618
  outSpotMarketVault: outSpotMarket.vault,
@@ -3540,6 +3630,66 @@ export class DriftClient {
3540
3630
  return { beginSwapIx, endSwapIx };
3541
3631
  }
3542
3632
 
3633
+ public async stakeForMSOL({ amount }: { amount: BN }): Promise<TxSigAndSlot> {
3634
+ const ixs = await this.getStakeForMSOLIx({ amount });
3635
+ const tx = await this.buildTransaction(ixs);
3636
+ return this.sendTransaction(tx);
3637
+ }
3638
+
3639
+ public async getStakeForMSOLIx({
3640
+ amount,
3641
+ userAccountPublicKey,
3642
+ }: {
3643
+ amount: BN;
3644
+ userAccountPublicKey?: PublicKey;
3645
+ }): Promise<TransactionInstruction[]> {
3646
+ const wSOLMint = this.getSpotMarketAccount(1).mint;
3647
+ const mSOLAccount = await this.getAssociatedTokenAccount(2);
3648
+ const wSOLAccount = await this.getAssociatedTokenAccount(1, false);
3649
+
3650
+ const wSOLAccountExists = await this.checkIfAccountExists(wSOLAccount);
3651
+
3652
+ const closeWSOLIx = createCloseAccountInstruction(
3653
+ wSOLAccount,
3654
+ this.wallet.publicKey,
3655
+ this.wallet.publicKey
3656
+ );
3657
+
3658
+ const createWSOLIx =
3659
+ await this.createAssociatedTokenAccountIdempotentInstruction(
3660
+ wSOLAccount,
3661
+ this.wallet.publicKey,
3662
+ this.wallet.publicKey,
3663
+ wSOLMint
3664
+ );
3665
+
3666
+ const { beginSwapIx, endSwapIx } = await this.getSwapIx({
3667
+ inMarketIndex: 1,
3668
+ outMarketIndex: 2,
3669
+ amountIn: amount,
3670
+ inTokenAccount: wSOLAccount,
3671
+ outTokenAccount: mSOLAccount,
3672
+ userAccountPublicKey,
3673
+ });
3674
+
3675
+ const program = getMarinadeFinanceProgram(this.provider);
3676
+ const depositIx = await getMarinadeDepositIx({
3677
+ program,
3678
+ mSOLAccount: mSOLAccount,
3679
+ transferFrom: this.wallet.publicKey,
3680
+ amount,
3681
+ });
3682
+
3683
+ const ixs = [];
3684
+
3685
+ if (!wSOLAccountExists) {
3686
+ ixs.push(createWSOLIx);
3687
+ }
3688
+ ixs.push(beginSwapIx, closeWSOLIx, depositIx, createWSOLIx, endSwapIx);
3689
+
3690
+ return ixs;
3691
+ }
3692
+
3543
3693
  public async triggerOrder(
3544
3694
  userAccountPublicKey: PublicKey,
3545
3695
  user: UserAccount,
@@ -3732,7 +3882,7 @@ export class DriftClient {
3732
3882
  makerInfo?: MakerInfo | MakerInfo[],
3733
3883
  referrerInfo?: ReferrerInfo
3734
3884
  ): Promise<TransactionInstruction> {
3735
- orderParams = this.getOrderParams(orderParams, MarketType.PERP);
3885
+ orderParams = getOrderParams(orderParams, { marketType: MarketType.PERP });
3736
3886
  const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
3737
3887
  const userAccountPublicKey = await this.getUserAccountPublicKey();
3738
3888
 
@@ -3828,7 +3978,7 @@ export class DriftClient {
3828
3978
  takerInfo: TakerInfo,
3829
3979
  referrerInfo?: ReferrerInfo
3830
3980
  ): Promise<TransactionInstruction> {
3831
- orderParams = this.getOrderParams(orderParams, MarketType.PERP);
3981
+ orderParams = getOrderParams(orderParams, { marketType: MarketType.PERP });
3832
3982
  const userStatsPublicKey = this.getUserStatsAccountPublicKey();
3833
3983
  const userAccountPublicKey = await this.getUserAccountPublicKey();
3834
3984
 
@@ -3900,7 +4050,7 @@ export class DriftClient {
3900
4050
  makerInfo?: MakerInfo,
3901
4051
  referrerInfo?: ReferrerInfo
3902
4052
  ): Promise<TransactionInstruction> {
3903
- orderParams = this.getOrderParams(orderParams, MarketType.SPOT);
4053
+ orderParams = getOrderParams(orderParams, { marketType: MarketType.SPOT });
3904
4054
  const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
3905
4055
  const userAccountPublicKey = await this.getUserAccountPublicKey();
3906
4056
 
@@ -3998,7 +4148,7 @@ export class DriftClient {
3998
4148
  fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
3999
4149
  referrerInfo?: ReferrerInfo
4000
4150
  ): Promise<TransactionInstruction> {
4001
- orderParams = this.getOrderParams(orderParams, MarketType.SPOT);
4151
+ orderParams = getOrderParams(orderParams, { marketType: MarketType.SPOT });
4002
4152
  const userStatsPublicKey = this.getUserStatsAccountPublicKey();
4003
4153
  const userAccountPublicKey = await this.getUserAccountPublicKey();
4004
4154