@drift-labs/sdk 2.25.4 → 2.26.0-beta.1

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 (69) hide show
  1. package/examples/phoenix.ts +40 -0
  2. package/lib/accounts/pollingUserAccountSubscriber.d.ts +5 -4
  3. package/lib/accounts/pollingUserAccountSubscriber.js +35 -48
  4. package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +4 -4
  5. package/lib/accounts/pollingUserStatsAccountSubscriber.js +30 -47
  6. package/lib/accounts/types.d.ts +2 -1
  7. package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
  8. package/lib/accounts/webSocketAccountSubscriber.js +4 -3
  9. package/lib/accounts/webSocketUserAccountSubscriber.d.ts +1 -0
  10. package/lib/accounts/webSocketUserAccountSubscriber.js +9 -0
  11. package/lib/addresses/pda.d.ts +1 -0
  12. package/lib/addresses/pda.js +8 -1
  13. package/lib/adminClient.d.ts +1 -0
  14. package/lib/adminClient.js +20 -0
  15. package/lib/dlob/DLOBApiClient.d.ts +14 -0
  16. package/lib/dlob/DLOBApiClient.js +34 -0
  17. package/lib/dlob/DLOBSubscriber.d.ts +19 -0
  18. package/lib/dlob/DLOBSubscriber.js +42 -0
  19. package/lib/dlob/types.d.ts +16 -0
  20. package/lib/dlob/types.js +2 -0
  21. package/lib/driftClient.d.ts +13 -10
  22. package/lib/driftClient.js +124 -28
  23. package/lib/examples/loadDlob.js +2 -4
  24. package/lib/idl/drift.json +264 -82
  25. package/lib/index.d.ts +4 -0
  26. package/lib/index.js +4 -0
  27. package/lib/phoenix/phoenixFulfillmentConfigMap.d.ts +10 -0
  28. package/lib/phoenix/phoenixFulfillmentConfigMap.js +17 -0
  29. package/lib/phoenix/phoenixSubscriber.d.ts +34 -0
  30. package/lib/phoenix/phoenixSubscriber.js +79 -0
  31. package/lib/slot/SlotSubscriber.js +3 -0
  32. package/lib/tx/retryTxSender.d.ts +2 -1
  33. package/lib/tx/retryTxSender.js +5 -1
  34. package/lib/tx/types.d.ts +4 -1
  35. package/lib/types.d.ts +11 -0
  36. package/lib/userMap/userMap.d.ts +17 -6
  37. package/lib/userMap/userMap.js +74 -46
  38. package/lib/userMap/userStatsMap.d.ts +6 -3
  39. package/lib/userMap/userStatsMap.js +30 -30
  40. package/package.json +2 -1
  41. package/src/accounts/pollingUserAccountSubscriber.ts +51 -63
  42. package/src/accounts/pollingUserStatsAccountSubscriber.ts +46 -62
  43. package/src/accounts/types.ts +2 -1
  44. package/src/accounts/webSocketAccountSubscriber.ts +4 -3
  45. package/src/accounts/webSocketUserAccountSubscriber.ts +10 -0
  46. package/src/addresses/pda.ts +13 -0
  47. package/src/adminClient.ts +34 -0
  48. package/src/dlob/DLOBApiClient.ts +37 -0
  49. package/src/dlob/DLOBSubscriber.ts +57 -0
  50. package/src/dlob/types.ts +20 -0
  51. package/src/driftClient.ts +216 -59
  52. package/src/examples/loadDlob.ts +2 -4
  53. package/src/idl/drift.json +264 -82
  54. package/src/index.ts +4 -0
  55. package/src/phoenix/phoenixFulfillmentConfigMap.ts +26 -0
  56. package/src/phoenix/phoenixSubscriber.ts +156 -0
  57. package/src/slot/SlotSubscriber.ts +4 -0
  58. package/src/tx/retryTxSender.ts +19 -2
  59. package/src/tx/types.ts +13 -0
  60. package/src/types.ts +12 -0
  61. package/src/userMap/userMap.ts +111 -60
  62. package/src/userMap/userStatsMap.ts +43 -44
  63. package/tests/dlob/helpers.ts +3 -1
  64. package/src/assert/assert.js +0 -9
  65. package/src/token/index.js +0 -38
  66. package/src/util/computeUnits.js +0 -27
  67. package/src/util/getTokenAddress.js +0 -9
  68. package/src/util/promiseTimeout.js +0 -14
  69. package/src/util/tps.js +0 -27
@@ -37,6 +37,7 @@ import {
37
37
  PerpMarketExtendedInfo,
38
38
  UserStatsAccount,
39
39
  ModifyOrderParams,
40
+ PhoenixV1FulfillmentConfigAccount,
40
41
  } from './types';
41
42
  import * as anchor from '@coral-xyz/anchor';
42
43
  import driftIDL from './idl/drift.json';
@@ -65,6 +66,7 @@ import {
65
66
  getDriftStateAccountPublicKey,
66
67
  getInsuranceFundStakeAccountPublicKey,
67
68
  getPerpMarketPublicKey,
69
+ getPhoenixFulfillmentConfigPublicKey,
68
70
  getReferrerNamePublicKeySync,
69
71
  getSerumFulfillmentConfigPublicKey,
70
72
  getSerumSignerPublicKey,
@@ -128,6 +130,7 @@ export class DriftClient {
128
130
  spotMarketLastSlotCache = new Map<number, number>();
129
131
  authority: PublicKey;
130
132
  marketLookupTable: PublicKey;
133
+ lookupTableAccount: AddressLookupTableAccount;
131
134
 
132
135
  public get isSubscribed() {
133
136
  return this._isSubscribed && this.accountSubscriber.isSubscribed;
@@ -412,13 +415,32 @@ export class DriftClient {
412
415
  )) as SerumV3FulfillmentConfigAccount;
413
416
  }
414
417
 
418
+ public async getPhoenixV1FulfillmentConfig(
419
+ phoenixMarket: PublicKey
420
+ ): Promise<PhoenixV1FulfillmentConfigAccount> {
421
+ const address = await getPhoenixFulfillmentConfigPublicKey(
422
+ this.program.programId,
423
+ phoenixMarket
424
+ );
425
+ return (await this.program.account.phoenixV1FulfillmentConfig.fetch(
426
+ address
427
+ )) as PhoenixV1FulfillmentConfigAccount;
428
+ }
429
+
415
430
  public async fetchMarketLookupTableAccount(): Promise<AddressLookupTableAccount> {
431
+ if (this.lookupTableAccount) return this.lookupTableAccount;
432
+
416
433
  if (!this.marketLookupTable) {
417
- throw Error('Market lookup table address not set');
434
+ console.log('Market lookup table address not set');
435
+ return;
418
436
  }
419
437
 
420
- return (await this.connection.getAddressLookupTable(this.marketLookupTable))
421
- .value;
438
+ const lookupTableAccount = (
439
+ await this.connection.getAddressLookupTable(this.marketLookupTable)
440
+ ).value;
441
+ this.lookupTableAccount = lookupTableAccount;
442
+
443
+ return lookupTableAccount;
422
444
  }
423
445
 
424
446
  /**
@@ -1382,7 +1404,7 @@ export class DriftClient {
1382
1404
 
1383
1405
  private async getWrappedSolAccountCreationIxs(
1384
1406
  amount: BN,
1385
- isDeposit?: boolean
1407
+ includeRent?: boolean
1386
1408
  ): Promise<{
1387
1409
  ixs: anchor.web3.TransactionInstruction[];
1388
1410
  signers: Signer[];
@@ -1398,7 +1420,7 @@ export class DriftClient {
1398
1420
 
1399
1421
  const rentSpaceLamports = new BN(LAMPORTS_PER_SOL / 100);
1400
1422
 
1401
- const lamports = isDeposit
1423
+ const lamports = includeRent
1402
1424
  ? amount.add(rentSpaceLamports)
1403
1425
  : rentSpaceLamports;
1404
1426
 
@@ -2076,54 +2098,102 @@ export class DriftClient {
2076
2098
  ): Promise<{ txSig: TransactionSignature; signedFillTx: Transaction }> {
2077
2099
  const marketIndex = orderParams.marketIndex;
2078
2100
  const orderId = userAccount.nextOrderId;
2101
+ const bracketOrderIxs = [];
2102
+
2103
+ const placePerpOrderIx = await this.getPlacePerpOrderIx(orderParams);
2079
2104
 
2080
- const marketOrderTx = wrapInTx(
2081
- await this.getPlacePerpOrderIx(orderParams),
2082
- txParams?.computeUnits,
2083
- txParams?.computeUnitsPrice
2084
- );
2085
2105
  for (const bracketOrderParams of bracketOrdersParams) {
2086
- marketOrderTx.add(await this.getPlacePerpOrderIx(bracketOrderParams));
2106
+ const placeBracketOrderIx = await this.getPlacePerpOrderIx(
2107
+ bracketOrderParams
2108
+ );
2109
+ bracketOrderIxs.push(placeBracketOrderIx);
2087
2110
  }
2088
2111
 
2089
- const fillTx = wrapInTx(
2090
- await this.getFillPerpOrderIx(
2091
- userAccountPublicKey,
2092
- userAccount,
2093
- {
2094
- orderId,
2095
- marketIndex,
2096
- },
2097
- makerInfo,
2098
- referrerInfo
2099
- ),
2100
- txParams?.computeUnits,
2101
- txParams?.computeUnitsPrice
2112
+ const fillPerpOrderIx = await this.getFillPerpOrderIx(
2113
+ userAccountPublicKey,
2114
+ userAccount,
2115
+ {
2116
+ orderId,
2117
+ marketIndex,
2118
+ },
2119
+ makerInfo,
2120
+ referrerInfo
2102
2121
  );
2103
2122
 
2104
- // Apply the latest blockhash to the txs so that we can sign before sending them
2105
- const currentBlockHash = (
2106
- await this.connection.getLatestBlockhash('finalized')
2107
- ).blockhash;
2108
- marketOrderTx.recentBlockhash = currentBlockHash;
2109
- fillTx.recentBlockhash = currentBlockHash;
2123
+ const lookupTableAccount = await this.fetchMarketLookupTableAccount();
2110
2124
 
2111
- marketOrderTx.feePayer = userAccount.authority;
2112
- fillTx.feePayer = userAccount.authority;
2125
+ const walletSupportsVersionedTxns =
2126
+ //@ts-ignore
2127
+ this.wallet.supportedTransactionVersions?.size ?? 0 > 1;
2113
2128
 
2114
- const [signedMarketOrderTx, signedFillTx] =
2115
- await this.provider.wallet.signAllTransactions([marketOrderTx, fillTx]);
2129
+ // use versioned transactions if there is a lookup table account and wallet is compatible
2130
+ if (walletSupportsVersionedTxns && lookupTableAccount) {
2131
+ const versionedMarketOrderTx =
2132
+ await this.txSender.getVersionedTransaction(
2133
+ [placePerpOrderIx].concat(bracketOrderIxs),
2134
+ [lookupTableAccount],
2135
+ [],
2136
+ this.opts
2137
+ );
2138
+ const versionedFillTx = await this.txSender.getVersionedTransaction(
2139
+ [fillPerpOrderIx],
2140
+ [lookupTableAccount],
2141
+ [],
2142
+ this.opts
2143
+ );
2144
+ const [signedVersionedMarketOrderTx, signedVersionedFillTx] =
2145
+ await this.provider.wallet.signAllTransactions([
2146
+ //@ts-ignore
2147
+ versionedMarketOrderTx,
2148
+ //@ts-ignore
2149
+ versionedFillTx,
2150
+ ]);
2151
+ const { txSig, slot } = await this.txSender.sendRawTransaction(
2152
+ signedVersionedMarketOrderTx.serialize(),
2153
+ this.opts
2154
+ );
2155
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2116
2156
 
2117
- const { txSig, slot } = await this.sendTransaction(
2118
- signedMarketOrderTx,
2119
- [],
2120
- this.opts,
2121
- true
2122
- );
2157
+ return { txSig, signedFillTx: signedVersionedFillTx };
2158
+ } else {
2159
+ const marketOrderTx = wrapInTx(
2160
+ placePerpOrderIx,
2161
+ txParams?.computeUnits,
2162
+ txParams?.computeUnitsPrice
2163
+ );
2123
2164
 
2124
- this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2165
+ if (bracketOrderIxs.length > 0) {
2166
+ marketOrderTx.add(...bracketOrderIxs);
2167
+ }
2168
+
2169
+ const fillTx = wrapInTx(
2170
+ fillPerpOrderIx,
2171
+ txParams?.computeUnits,
2172
+ txParams?.computeUnitsPrice
2173
+ );
2125
2174
 
2126
- return { txSig, signedFillTx };
2175
+ // Apply the latest blockhash to the txs so that we can sign before sending them
2176
+ const currentBlockHash = (
2177
+ await this.connection.getLatestBlockhash('finalized')
2178
+ ).blockhash;
2179
+ marketOrderTx.recentBlockhash = currentBlockHash;
2180
+ fillTx.recentBlockhash = currentBlockHash;
2181
+
2182
+ marketOrderTx.feePayer = userAccount.authority;
2183
+ fillTx.feePayer = userAccount.authority;
2184
+
2185
+ const [signedMarketOrderTx, signedFillTx] =
2186
+ await this.provider.wallet.signAllTransactions([marketOrderTx, fillTx]);
2187
+ const { txSig, slot } = await this.sendTransaction(
2188
+ signedMarketOrderTx,
2189
+ [],
2190
+ this.opts,
2191
+ true
2192
+ );
2193
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2194
+
2195
+ return { txSig, signedFillTx };
2196
+ }
2127
2197
  }
2128
2198
 
2129
2199
  public async placePerpOrder(
@@ -2613,7 +2683,9 @@ export class DriftClient {
2613
2683
  userAccountPublicKey: PublicKey,
2614
2684
  user: UserAccount,
2615
2685
  order?: Order,
2616
- fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
2686
+ fulfillmentConfig?:
2687
+ | SerumV3FulfillmentConfigAccount
2688
+ | PhoenixV1FulfillmentConfigAccount,
2617
2689
  makerInfo?: MakerInfo,
2618
2690
  referrerInfo?: ReferrerInfo,
2619
2691
  txParams?: TxParams
@@ -2641,7 +2713,9 @@ export class DriftClient {
2641
2713
  userAccountPublicKey: PublicKey,
2642
2714
  userAccount: UserAccount,
2643
2715
  order?: Order,
2644
- fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
2716
+ fulfillmentConfig?:
2717
+ | SerumV3FulfillmentConfigAccount
2718
+ | PhoenixV1FulfillmentConfigAccount,
2645
2719
  makerInfo?: MakerInfo,
2646
2720
  referrerInfo?: ReferrerInfo
2647
2721
  ): Promise<TransactionInstruction> {
@@ -2724,14 +2798,26 @@ export class DriftClient {
2724
2798
  addSpotFulfillmentAccounts(
2725
2799
  marketIndex: number,
2726
2800
  remainingAccounts: AccountMeta[],
2727
- fulfillmentConfig?: SerumV3FulfillmentConfigAccount
2728
- ) {
2801
+ fulfillmentConfig?:
2802
+ | SerumV3FulfillmentConfigAccount
2803
+ | PhoenixV1FulfillmentConfigAccount
2804
+ ): void {
2729
2805
  if (fulfillmentConfig) {
2730
- this.addSerumRemainingAccounts(
2731
- marketIndex,
2732
- remainingAccounts,
2733
- fulfillmentConfig
2734
- );
2806
+ if ('serumProgramId' in fulfillmentConfig) {
2807
+ this.addSerumRemainingAccounts(
2808
+ marketIndex,
2809
+ remainingAccounts,
2810
+ fulfillmentConfig
2811
+ );
2812
+ } else if ('phoenixProgramId' in fulfillmentConfig) {
2813
+ this.addPhoenixRemainingAccounts(
2814
+ marketIndex,
2815
+ remainingAccounts,
2816
+ fulfillmentConfig
2817
+ );
2818
+ } else {
2819
+ throw Error('Invalid fulfillment config type');
2820
+ }
2735
2821
  } else {
2736
2822
  remainingAccounts.push({
2737
2823
  pubkey: this.getSpotMarketAccount(marketIndex).vault,
@@ -2750,7 +2836,7 @@ export class DriftClient {
2750
2836
  marketIndex: number,
2751
2837
  remainingAccounts: AccountMeta[],
2752
2838
  fulfillmentConfig: SerumV3FulfillmentConfigAccount
2753
- ) {
2839
+ ): void {
2754
2840
  remainingAccounts.push({
2755
2841
  pubkey: fulfillmentConfig.pubkey,
2756
2842
  isWritable: false,
@@ -2837,6 +2923,63 @@ export class DriftClient {
2837
2923
  });
2838
2924
  }
2839
2925
 
2926
+ addPhoenixRemainingAccounts(
2927
+ marketIndex: number,
2928
+ remainingAccounts: AccountMeta[],
2929
+ fulfillmentConfig: PhoenixV1FulfillmentConfigAccount
2930
+ ): void {
2931
+ remainingAccounts.push({
2932
+ pubkey: fulfillmentConfig.pubkey,
2933
+ isWritable: false,
2934
+ isSigner: false,
2935
+ });
2936
+ remainingAccounts.push({
2937
+ pubkey: fulfillmentConfig.phoenixProgramId,
2938
+ isWritable: false,
2939
+ isSigner: false,
2940
+ });
2941
+ remainingAccounts.push({
2942
+ pubkey: fulfillmentConfig.phoenixLogAuthority,
2943
+ isWritable: false,
2944
+ isSigner: false,
2945
+ });
2946
+ remainingAccounts.push({
2947
+ pubkey: fulfillmentConfig.phoenixMarket,
2948
+ isWritable: true,
2949
+ isSigner: false,
2950
+ });
2951
+ remainingAccounts.push({
2952
+ pubkey: this.getSignerPublicKey(),
2953
+ isWritable: false,
2954
+ isSigner: false,
2955
+ });
2956
+ remainingAccounts.push({
2957
+ pubkey: fulfillmentConfig.phoenixBaseVault,
2958
+ isWritable: true,
2959
+ isSigner: false,
2960
+ });
2961
+ remainingAccounts.push({
2962
+ pubkey: fulfillmentConfig.phoenixQuoteVault,
2963
+ isWritable: true,
2964
+ isSigner: false,
2965
+ });
2966
+ remainingAccounts.push({
2967
+ pubkey: this.getSpotMarketAccount(marketIndex).vault,
2968
+ isWritable: true,
2969
+ isSigner: false,
2970
+ });
2971
+ remainingAccounts.push({
2972
+ pubkey: this.getQuoteSpotMarketAccount().vault,
2973
+ isWritable: true,
2974
+ isSigner: false,
2975
+ });
2976
+ remainingAccounts.push({
2977
+ pubkey: TOKEN_PROGRAM_ID,
2978
+ isWritable: false,
2979
+ isSigner: false,
2980
+ });
2981
+ }
2982
+
2840
2983
  public async triggerOrder(
2841
2984
  userAccountPublicKey: PublicKey,
2842
2985
  user: UserAccount,
@@ -4255,6 +4398,7 @@ export class DriftClient {
4255
4398
  amount,
4256
4399
  collateralAccountPublicKey,
4257
4400
  initializeStakeAccount,
4401
+ fromSubaccount,
4258
4402
  }: {
4259
4403
  /**
4260
4404
  * Spot market index
@@ -4269,6 +4413,10 @@ export class DriftClient {
4269
4413
  * Add instructions to initialize the staking account -- required if its the first time the currrent authority has staked in this market
4270
4414
  */
4271
4415
  initializeStakeAccount?: boolean;
4416
+ /**
4417
+ * Optional -- withdraw from current subaccount to fund stake amount, instead of wallet balance
4418
+ */
4419
+ fromSubaccount?: boolean;
4272
4420
  }): Promise<TransactionSignature> {
4273
4421
  const tx = new Transaction();
4274
4422
 
@@ -4293,6 +4441,15 @@ export class DriftClient {
4293
4441
  tokenAccount = collateralAccountPublicKey;
4294
4442
  }
4295
4443
 
4444
+ if (fromSubaccount) {
4445
+ const withdrawIx = await this.getWithdrawIx(
4446
+ amount,
4447
+ marketIndex,
4448
+ tokenAccount
4449
+ );
4450
+ tx.add(withdrawIx);
4451
+ }
4452
+
4296
4453
  if (initializeStakeAccount) {
4297
4454
  const initializeIx = await this.getInitializeInsuranceFundStakeIx(
4298
4455
  marketIndex
@@ -4404,11 +4561,7 @@ export class DriftClient {
4404
4561
 
4405
4562
  public async removeInsuranceFundStake(
4406
4563
  marketIndex: number,
4407
- collateralAccountPublicKey: PublicKey,
4408
- /**
4409
- * If unstaking SOL, it's required to pass in the amount
4410
- */
4411
- amount?: BN
4564
+ collateralAccountPublicKey: PublicKey
4412
4565
  ): Promise<TransactionSignature> {
4413
4566
  const tx = new Transaction();
4414
4567
  const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
@@ -4427,7 +4580,7 @@ export class DriftClient {
4427
4580
 
4428
4581
  if (createWSOLTokenAccount) {
4429
4582
  const { ixs, signers, pubkey } =
4430
- await this.getWrappedSolAccountCreationIxs(amount, true);
4583
+ await this.getWrappedSolAccountCreationIxs(ZERO, true);
4431
4584
  tokenAccount = pubkey;
4432
4585
  ixs.forEach((ix) => {
4433
4586
  tx.add(ix);
@@ -4475,7 +4628,11 @@ export class DriftClient {
4475
4628
  );
4476
4629
  }
4477
4630
 
4478
- const { txSig } = await this.sendTransaction(tx, [], this.opts);
4631
+ const { txSig } = await this.sendTransaction(
4632
+ tx,
4633
+ additionalSigners,
4634
+ this.opts
4635
+ );
4479
4636
  return txSig;
4480
4637
  }
4481
4638
 
@@ -60,7 +60,7 @@ const main = async () => {
60
60
  });
61
61
 
62
62
  // fetches all users and subscribes for updates
63
- await userMap.fetchAllUsers();
63
+ await userMap.subscribe();
64
64
 
65
65
  console.log('Loading dlob from user map...');
66
66
  const dlob = new DLOB();
@@ -71,9 +71,7 @@ const main = async () => {
71
71
  dlob.clear();
72
72
 
73
73
  console.log('Unsubscribing users...');
74
- for (const user of userMap.values()) {
75
- await user.unsubscribe();
76
- }
74
+ await userMap.unsubscribe();
77
75
 
78
76
  console.log('Unsubscribing drift client...');
79
77
  await driftClient.unsubscribe();