@drift-labs/sdk 2.30.0-beta.0 → 2.30.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 (55) hide show
  1. package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
  2. package/lib/accounts/pollingTokenAccountSubscriber.js +5 -2
  3. package/lib/accounts/types.d.ts +3 -3
  4. package/lib/constants/spotMarkets.js +10 -0
  5. package/lib/dlob/DLOB.d.ts +20 -1
  6. package/lib/dlob/DLOB.js +39 -0
  7. package/lib/driftClient.d.ts +51 -2
  8. package/lib/driftClient.js +162 -13
  9. package/lib/events/types.d.ts +3 -2
  10. package/lib/events/types.js +1 -0
  11. package/lib/examples/makeTradeExample.js +1 -1
  12. package/lib/idl/drift.json +279 -2
  13. package/lib/index.d.ts +1 -0
  14. package/lib/index.js +1 -0
  15. package/lib/jupiter/jupiterClient.d.ts +86 -0
  16. package/lib/jupiter/jupiterClient.js +109 -0
  17. package/lib/math/spotBalance.d.ts +41 -0
  18. package/lib/math/spotBalance.js +41 -0
  19. package/lib/token/index.d.ts +3 -2
  20. package/lib/token/index.js +9 -32
  21. package/lib/tokenFaucet.d.ts +3 -3
  22. package/lib/tokenFaucet.js +4 -9
  23. package/lib/tx/retryTxSender.js +3 -0
  24. package/lib/types.d.ts +29 -1
  25. package/lib/types.js +6 -1
  26. package/lib/wallet.d.ts +5 -3
  27. package/lib/wallet.js +19 -7
  28. package/package.json +2 -2
  29. package/src/accounts/pollingTokenAccountSubscriber.ts +8 -5
  30. package/src/accounts/types.ts +3 -3
  31. package/src/assert/assert.js +9 -0
  32. package/src/constants/spotMarkets.ts +11 -0
  33. package/src/dlob/DLOB.ts +75 -0
  34. package/src/driftClient.ts +288 -37
  35. package/src/events/types.ts +5 -1
  36. package/src/examples/makeTradeExample.ts +2 -4
  37. package/src/idl/drift.json +279 -2
  38. package/src/index.ts +1 -0
  39. package/src/jupiter/jupiterClient.ts +214 -0
  40. package/src/math/spotBalance.ts +41 -0
  41. package/src/token/index.js +38 -0
  42. package/src/token/index.ts +12 -36
  43. package/src/tokenFaucet.ts +15 -34
  44. package/src/tx/retryTxSender.ts +4 -0
  45. package/src/types.ts +32 -1
  46. package/src/util/computeUnits.js +27 -0
  47. package/src/util/promiseTimeout.js +14 -0
  48. package/src/util/tps.js +27 -0
  49. package/src/wallet.ts +34 -12
  50. package/tests/dlob/helpers.ts +9 -0
  51. package/tests/dlob/test.ts +218 -40
  52. package/dlob_read.ts +0 -155
  53. package/lib/util/getTokenAddress.d.ts +0 -2
  54. package/lib/util/getTokenAddress.js +0 -9
  55. package/src/util/getTokenAddress.ts +0 -18
@@ -5,7 +5,7 @@ import StrictEventEmitter from 'strict-event-emitter-types';
5
5
  import { EventEmitter } from 'events';
6
6
  import { PublicKey } from '@solana/web3.js';
7
7
  import { BulkAccountLoader } from './bulkAccountLoader';
8
- import { AccountInfo } from '@solana/spl-token';
8
+ import { Account } from '@solana/spl-token';
9
9
  export declare class PollingTokenAccountSubscriber implements TokenAccountSubscriber {
10
10
  isSubscribed: boolean;
11
11
  program: Program;
@@ -14,13 +14,13 @@ export declare class PollingTokenAccountSubscriber implements TokenAccountSubscr
14
14
  accountLoader: BulkAccountLoader;
15
15
  callbackId?: string;
16
16
  errorCallbackId?: string;
17
- tokenAccountAndSlot?: DataAndSlot<AccountInfo>;
17
+ tokenAccountAndSlot?: DataAndSlot<Account>;
18
18
  constructor(publicKey: PublicKey, accountLoader: BulkAccountLoader);
19
19
  subscribe(): Promise<boolean>;
20
20
  addToAccountLoader(): Promise<void>;
21
21
  fetch(): Promise<void>;
22
22
  unsubscribe(): Promise<void>;
23
23
  assertIsSubscribed(): void;
24
- getTokenAccountAndSlot(): DataAndSlot<AccountInfo>;
24
+ getTokenAccountAndSlot(): DataAndSlot<Account>;
25
25
  didSubscriptionSucceed(): boolean;
26
26
  }
@@ -34,7 +34,7 @@ class PollingTokenAccountSubscriber {
34
34
  return;
35
35
  }
36
36
  this.callbackId = await this.accountLoader.addAccount(this.publicKey, (buffer, slot) => {
37
- const tokenAccount = (0, token_1.parseTokenAccount)(buffer);
37
+ const tokenAccount = (0, token_1.parseTokenAccount)(buffer, this.publicKey);
38
38
  this.tokenAccountAndSlot = { data: tokenAccount, slot };
39
39
  // @ts-ignore
40
40
  this.eventEmitter.emit('tokenAccountUpdate', tokenAccount);
@@ -47,7 +47,10 @@ class PollingTokenAccountSubscriber {
47
47
  async fetch() {
48
48
  await this.accountLoader.load();
49
49
  const { buffer, slot } = this.accountLoader.getBufferAndSlot(this.publicKey);
50
- this.tokenAccountAndSlot = { data: (0, token_1.parseTokenAccount)(buffer), slot };
50
+ this.tokenAccountAndSlot = {
51
+ data: (0, token_1.parseTokenAccount)(buffer, this.publicKey),
52
+ slot,
53
+ };
51
54
  }
52
55
  async unsubscribe() {
53
56
  if (!this.isSubscribed) {
@@ -4,7 +4,7 @@ import { SpotMarketAccount, PerpMarketAccount, OracleSource, StateAccount, UserA
4
4
  import StrictEventEmitter from 'strict-event-emitter-types';
5
5
  import { EventEmitter } from 'events';
6
6
  import { PublicKey } from '@solana/web3.js';
7
- import { AccountInfo } from '@solana/spl-token';
7
+ import { Account } from '@solana/spl-token';
8
8
  import { OracleInfo, OraclePriceData } from '..';
9
9
  export interface AccountSubscriber<T> {
10
10
  dataAndSlot?: DataAndSlot<T>;
@@ -57,7 +57,7 @@ export interface UserAccountSubscriber {
57
57
  getUserAccountAndSlot(): DataAndSlot<UserAccount>;
58
58
  }
59
59
  export interface TokenAccountEvents {
60
- tokenAccountUpdate: (payload: AccountInfo) => void;
60
+ tokenAccountUpdate: (payload: Account) => void;
61
61
  update: void;
62
62
  error: (e: Error) => void;
63
63
  }
@@ -67,7 +67,7 @@ export interface TokenAccountSubscriber {
67
67
  subscribe(): Promise<boolean>;
68
68
  fetch(): Promise<void>;
69
69
  unsubscribe(): Promise<void>;
70
- getTokenAccountAndSlot(): DataAndSlot<AccountInfo>;
70
+ getTokenAccountAndSlot(): DataAndSlot<Account>;
71
71
  }
72
72
  export interface OracleEvents {
73
73
  oracleUpdate: (payload: OraclePriceData) => void;
@@ -58,6 +58,16 @@ exports.MainnetSpotMarkets = [
58
58
  serumMarket: new web3_js_1.PublicKey('8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'),
59
59
  phoenixMarket: new web3_js_1.PublicKey('4DoNfFBfF7UokCC2FQzriy7yHK6DY6NVdYpuekQ5pRgg'),
60
60
  },
61
+ {
62
+ symbol: 'mSOL',
63
+ marketIndex: 2,
64
+ oracle: new web3_js_1.PublicKey('E4v1BBgoso9s64TQvmyownAVJbhbEPGyzA3qn4n46qj9'),
65
+ oracleSource: __1.OracleSource.PYTH,
66
+ mint: new web3_js_1.PublicKey('mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So'),
67
+ precision: new __1.BN(10).pow(numericConstants_1.NINE),
68
+ precisionExp: numericConstants_1.NINE,
69
+ serumMarket: new web3_js_1.PublicKey('9Lyhks5bQQxb9EyyX55NtgKQzpM4WK7JCmeaWuQ5MoXD'),
70
+ },
61
71
  ];
62
72
  exports.SpotMarkets = {
63
73
  devnet: exports.DevnetSpotMarkets,
@@ -1,5 +1,5 @@
1
1
  import { NodeList } from './NodeList';
2
- import { BN, DLOBNode, DLOBNodeType, DriftClient, MarketType, MarketTypeStr, OraclePriceData, Order, OrderActionRecord, OrderRecord, PerpMarketAccount, SlotSubscriber, SpotMarketAccount, StateAccount, TriggerOrderNode, UserMap } from '..';
2
+ import { BN, DLOBNode, DLOBNodeType, DriftClient, MarketType, MarketTypeStr, OraclePriceData, Order, OrderActionRecord, OrderRecord, PerpMarketAccount, PositionDirection, SlotSubscriber, SpotMarketAccount, StateAccount, TriggerOrderNode, UserMap } from '..';
3
3
  import { PublicKey } from '@solana/web3.js';
4
4
  import { DLOBOrders } from './DLOBOrders';
5
5
  import { L2OrderBook, L2OrderBookGenerator, L3OrderBook } from './orderBookLevels';
@@ -135,5 +135,24 @@ export declare class DLOB {
135
135
  slot: number;
136
136
  oraclePriceData: OraclePriceData;
137
137
  }): L3OrderBook;
138
+ private estimateFillExactBaseAmountInForSide;
139
+ /**
140
+ *
141
+ * @param param.marketIndex the index of the market
142
+ * @param param.marketType the type of the market
143
+ * @param param.baseAmount the base amount in to estimate
144
+ * @param param.orderDirection the direction of the trade
145
+ * @param param.slot current slot for estimating dlob node price
146
+ * @param param.oraclePriceData the oracle price data
147
+ * @returns the estimated quote amount filled: QUOTE_PRECISION
148
+ */
149
+ estimateFillWithExactBaseAmount({ marketIndex, marketType, baseAmount, orderDirection, slot, oraclePriceData, }: {
150
+ marketIndex: number;
151
+ marketType: MarketType;
152
+ baseAmount: BN;
153
+ orderDirection: PositionDirection;
154
+ slot: number;
155
+ oraclePriceData: OraclePriceData;
156
+ }): BN;
138
157
  }
139
158
  export {};
package/lib/dlob/DLOB.js CHANGED
@@ -1023,5 +1023,44 @@ class DLOB {
1023
1023
  asks,
1024
1024
  };
1025
1025
  }
1026
+ estimateFillExactBaseAmountInForSide(baseAmountIn, oraclePriceData, slot, dlobSide) {
1027
+ let runningSumQuote = __1.ZERO;
1028
+ let runningSumBase = __1.ZERO;
1029
+ for (const side of dlobSide) {
1030
+ const price = side.getPrice(oraclePriceData, slot); //side.order.quoteAssetAmount.div(side.order.baseAssetAmount);
1031
+ const baseAmountRemaining = side.order.baseAssetAmount.sub(side.order.baseAssetAmountFilled);
1032
+ if (runningSumBase.add(baseAmountRemaining).gt(baseAmountIn)) {
1033
+ const remainingBase = baseAmountIn.sub(runningSumBase);
1034
+ runningSumBase = runningSumBase.add(remainingBase);
1035
+ runningSumQuote = runningSumQuote.add(remainingBase.mul(price));
1036
+ break;
1037
+ }
1038
+ else {
1039
+ runningSumBase = runningSumBase.add(baseAmountRemaining);
1040
+ runningSumQuote = runningSumQuote.add(baseAmountRemaining.mul(price));
1041
+ }
1042
+ }
1043
+ return runningSumQuote
1044
+ .mul(__1.QUOTE_PRECISION)
1045
+ .div(__1.BASE_PRECISION.mul(__1.PRICE_PRECISION));
1046
+ }
1047
+ /**
1048
+ *
1049
+ * @param param.marketIndex the index of the market
1050
+ * @param param.marketType the type of the market
1051
+ * @param param.baseAmount the base amount in to estimate
1052
+ * @param param.orderDirection the direction of the trade
1053
+ * @param param.slot current slot for estimating dlob node price
1054
+ * @param param.oraclePriceData the oracle price data
1055
+ * @returns the estimated quote amount filled: QUOTE_PRECISION
1056
+ */
1057
+ estimateFillWithExactBaseAmount({ marketIndex, marketType, baseAmount, orderDirection, slot, oraclePriceData, }) {
1058
+ if ((0, __1.isVariant)(orderDirection, 'long')) {
1059
+ return this.estimateFillExactBaseAmountInForSide(baseAmount, oraclePriceData, slot, this.getRestingLimitAsks(marketIndex, slot, marketType, oraclePriceData));
1060
+ }
1061
+ else if ((0, __1.isVariant)(orderDirection, 'short')) {
1062
+ return this.estimateFillExactBaseAmountInForSide(baseAmount, oraclePriceData, slot, this.getRestingLimitBids(marketIndex, slot, marketType, oraclePriceData));
1063
+ }
1064
+ }
1026
1065
  }
1027
1066
  exports.DLOB = DLOB;
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { AnchorProvider, BN, Program, ProgramAccount } from '@coral-xyz/anchor';
3
- import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo, UserStatsAccount, PhoenixV1FulfillmentConfigAccount, ModifyOrderPolicy } from './types';
3
+ import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo, UserStatsAccount, PhoenixV1FulfillmentConfigAccount, ModifyOrderPolicy, SwapReduceOnly } from './types';
4
4
  import * as anchor from '@coral-xyz/anchor';
5
5
  import { Connection, PublicKey, TransactionSignature, ConfirmOptions, Transaction, TransactionInstruction, AccountMeta, Signer, AddressLookupTableAccount, TransactionVersion, VersionedTransaction } from '@solana/web3.js';
6
6
  import { TokenFaucet } from './tokenFaucet';
@@ -13,6 +13,7 @@ import { DriftClientConfig } from './driftClientConfig';
13
13
  import { User } from './user';
14
14
  import { UserSubscriptionConfig } from './userConfig';
15
15
  import { UserStats } from './userStats';
16
+ import { JupiterClient, Route, SwapMode } from './jupiter/jupiterClient';
16
17
  type RemainingAccountParams = {
17
18
  userAccounts: UserAccount[];
18
19
  writablePerpMarketIndexes?: number[];
@@ -171,6 +172,7 @@ export declare class DriftClient {
171
172
  * @param useNative
172
173
  */
173
174
  getAssociatedTokenAccount(marketIndex: number, useNative?: boolean): Promise<PublicKey>;
175
+ createAssociatedTokenAccountIdempotentInstruction(account: PublicKey, payer: PublicKey, owner: PublicKey, mint: PublicKey): TransactionInstruction;
174
176
  /**
175
177
  * Deposit funds into the given spot market
176
178
  *
@@ -274,6 +276,53 @@ export declare class DriftClient {
274
276
  addSpotFulfillmentAccounts(marketIndex: number, remainingAccounts: AccountMeta[], fulfillmentConfig?: SerumV3FulfillmentConfigAccount | PhoenixV1FulfillmentConfigAccount): void;
275
277
  addSerumRemainingAccounts(marketIndex: number, remainingAccounts: AccountMeta[], fulfillmentConfig: SerumV3FulfillmentConfigAccount): void;
276
278
  addPhoenixRemainingAccounts(marketIndex: number, remainingAccounts: AccountMeta[], fulfillmentConfig: PhoenixV1FulfillmentConfigAccount): void;
279
+ /**
280
+ * Swap tokens in drift account using jupiter
281
+ * @param jupiterClient jupiter client to find routes and jupiter instructions
282
+ * @param outMarketIndex the market index of the token you're buying
283
+ * @param inMarketIndex the market index of the token you're selling
284
+ * @param outAssociatedTokenAccount the token account to receive the token being sold on jupiter
285
+ * @param inAssociatedTokenAccount the token account to
286
+ * @param amount the amount of the token to sell
287
+ * @param slippageBps the max slippage passed to jupiter api
288
+ * @param route the jupiter route to use for the swap
289
+ * @param txParams
290
+ */
291
+ swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, route, reduceOnly, txParams, }: {
292
+ jupiterClient: JupiterClient;
293
+ outMarketIndex: number;
294
+ inMarketIndex: number;
295
+ outAssociatedTokenAccount?: PublicKey;
296
+ inAssociatedTokenAccount?: PublicKey;
297
+ amount: BN;
298
+ slippageBps?: number;
299
+ swapMode?: SwapMode;
300
+ route?: Route;
301
+ reduceOnly?: SwapReduceOnly;
302
+ txParams?: TxParams;
303
+ }): Promise<TransactionSignature>;
304
+ /**
305
+ * Get the drift begin_swap and end_swap instructions
306
+ *
307
+ * @param outMarketIndex the market index of the token you're buying
308
+ * @param inMarketIndex the market index of the token you're selling
309
+ * @param amountIn the amount of the token to sell
310
+ * @param inTokenAccount the token account to move the tokens being sold
311
+ * @param outTokenAccount the token account to receive the tokens being bought
312
+ * @param limitPrice the limit price of the swap
313
+ */
314
+ getSwapIx({ outMarketIndex, inMarketIndex, amountIn, inTokenAccount, outTokenAccount, limitPrice, reduceOnly, }: {
315
+ outMarketIndex: number;
316
+ inMarketIndex: number;
317
+ amountIn: BN;
318
+ inTokenAccount: PublicKey;
319
+ outTokenAccount: PublicKey;
320
+ limitPrice?: BN;
321
+ reduceOnly?: SwapReduceOnly;
322
+ }): Promise<{
323
+ beginSwapIx: TransactionInstruction;
324
+ endSwapIx: TransactionInstruction;
325
+ }>;
277
326
  triggerOrder(userAccountPublicKey: PublicKey, user: UserAccount, order: Order, txParams?: TxParams): Promise<TransactionSignature>;
278
327
  getTriggerOrderIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, order: Order): Promise<TransactionInstruction>;
279
328
  forceCancelOrders(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams): Promise<TransactionSignature>;
@@ -485,6 +534,6 @@ export declare class DriftClient {
485
534
  marketType: MarketType;
486
535
  } | undefined;
487
536
  sendTransaction(tx: Transaction | VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
488
- buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams): Promise<Transaction | VersionedTransaction>;
537
+ buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[]): Promise<Transaction | VersionedTransaction>;
489
538
  }
490
539
  export {};
@@ -411,7 +411,7 @@ class DriftClient {
411
411
  }
412
412
  const state = this.getStateAccount();
413
413
  if (!state.whitelistMint.equals(web3_js_1.PublicKey.default)) {
414
- const associatedTokenPublicKey = await spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, state.whitelistMint, this.wallet.publicKey);
414
+ const associatedTokenPublicKey = await (0, spl_token_1.getAssociatedTokenAddress)(state.whitelistMint, this.wallet.publicKey);
415
415
  remainingAccounts.push({
416
416
  pubkey: associatedTokenPublicKey,
417
417
  isWritable: false,
@@ -955,7 +955,25 @@ class DriftClient {
955
955
  return this.wallet.publicKey;
956
956
  }
957
957
  const mint = spotMarket.mint;
958
- return await spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, mint, this.wallet.publicKey);
958
+ return await (0, spl_token_1.getAssociatedTokenAddress)(mint, this.wallet.publicKey);
959
+ }
960
+ createAssociatedTokenAccountIdempotentInstruction(account, payer, owner, mint) {
961
+ return new web3_js_1.TransactionInstruction({
962
+ keys: [
963
+ { pubkey: payer, isSigner: true, isWritable: true },
964
+ { pubkey: account, isSigner: false, isWritable: true },
965
+ { pubkey: owner, isSigner: false, isWritable: false },
966
+ { pubkey: mint, isSigner: false, isWritable: false },
967
+ {
968
+ pubkey: anchor.web3.SystemProgram.programId,
969
+ isSigner: false,
970
+ isWritable: false,
971
+ },
972
+ { pubkey: spl_token_1.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
973
+ ],
974
+ programId: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
975
+ data: Buffer.from([0x1]),
976
+ });
959
977
  }
960
978
  /**
961
979
  * Deposit funds into the given spot market
@@ -988,7 +1006,7 @@ class DriftClient {
988
1006
  tx.add(depositCollateralIx);
989
1007
  // Close the wrapped sol account at the end of the transaction
990
1008
  if (createWSOLTokenAccount) {
991
- tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, associatedTokenAccount, signerAuthority, signerAuthority, []));
1009
+ tx.add((0, spl_token_1.createCloseAccountInstruction)(associatedTokenAccount, signerAuthority, signerAuthority, []));
992
1010
  }
993
1011
  const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
994
1012
  this.spotMarketLastSlotCache.set(marketIndex, slot);
@@ -1054,13 +1072,12 @@ class DriftClient {
1054
1072
  space: 165,
1055
1073
  programId: spl_token_1.TOKEN_PROGRAM_ID,
1056
1074
  }));
1057
- result.ixs.push(spl_token_1.Token.createInitAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, spotMarkets_1.WRAPPED_SOL_MINT, wrappedSolAccount.publicKey, authority));
1075
+ result.ixs.push((0, spl_token_1.createInitializeAccountInstruction)(wrappedSolAccount.publicKey, spotMarkets_1.WRAPPED_SOL_MINT, authority));
1058
1076
  result.signers.push(wrappedSolAccount);
1059
1077
  return result;
1060
1078
  }
1061
1079
  getAssociatedTokenAccountCreationIx(tokenMintAddress, associatedTokenAddress) {
1062
- const createAssociatedAccountIx = spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, tokenMintAddress, associatedTokenAddress, this.wallet.publicKey, this.wallet.publicKey);
1063
- return createAssociatedAccountIx;
1080
+ return (0, spl_token_1.createAssociatedTokenAccountInstruction)(this.wallet.publicKey, associatedTokenAddress, this.wallet.publicKey, tokenMintAddress);
1064
1081
  }
1065
1082
  /**
1066
1083
  * Creates the Clearing House User account for a user, and deposits some initial collateral
@@ -1108,7 +1125,7 @@ class DriftClient {
1108
1125
  tx.add(initializeUserAccountIx).add(depositCollateralIx);
1109
1126
  // Close the wrapped sol account at the end of the transaction
1110
1127
  if (createWSOLTokenAccount) {
1111
- tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
1128
+ tx.add((0, spl_token_1.createCloseAccountInstruction)(userTokenAccount, authority, authority, []));
1112
1129
  }
1113
1130
  const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
1114
1131
  this.spotMarketLastSlotCache.set(marketIndex, slot);
@@ -1166,7 +1183,7 @@ class DriftClient {
1166
1183
  tx.add(withdrawCollateral);
1167
1184
  // Close the wrapped sol account at the end of the transaction
1168
1185
  if (createWSOLTokenAccount) {
1169
- tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, associatedTokenAddress, authority, authority, []));
1186
+ tx.add((0, spl_token_1.createCloseAccountInstruction)(associatedTokenAddress, authority, authority, []));
1170
1187
  }
1171
1188
  const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
1172
1189
  this.spotMarketLastSlotCache.set(marketIndex, slot);
@@ -1947,6 +1964,134 @@ class DriftClient {
1947
1964
  isSigner: false,
1948
1965
  });
1949
1966
  }
1967
+ /**
1968
+ * Swap tokens in drift account using jupiter
1969
+ * @param jupiterClient jupiter client to find routes and jupiter instructions
1970
+ * @param outMarketIndex the market index of the token you're buying
1971
+ * @param inMarketIndex the market index of the token you're selling
1972
+ * @param outAssociatedTokenAccount the token account to receive the token being sold on jupiter
1973
+ * @param inAssociatedTokenAccount the token account to
1974
+ * @param amount the amount of the token to sell
1975
+ * @param slippageBps the max slippage passed to jupiter api
1976
+ * @param route the jupiter route to use for the swap
1977
+ * @param txParams
1978
+ */
1979
+ async swap({ jupiterClient, outMarketIndex, inMarketIndex, outAssociatedTokenAccount, inAssociatedTokenAccount, amount, slippageBps, swapMode, route, reduceOnly, txParams, }) {
1980
+ const outMarket = this.getSpotMarketAccount(outMarketIndex);
1981
+ const inMarket = this.getSpotMarketAccount(inMarketIndex);
1982
+ if (!route) {
1983
+ const routes = await jupiterClient.getRoutes({
1984
+ inputMint: inMarket.mint,
1985
+ outputMint: outMarket.mint,
1986
+ amount,
1987
+ slippageBps,
1988
+ swapMode,
1989
+ });
1990
+ if (!routes || routes.length === 0) {
1991
+ throw new Error('No jupiter routes found');
1992
+ }
1993
+ route = routes[0];
1994
+ }
1995
+ const transaction = await jupiterClient.getSwapTransaction({
1996
+ route,
1997
+ userPublicKey: this.provider.wallet.publicKey,
1998
+ slippageBps,
1999
+ });
2000
+ const { transactionMessage, lookupTables } = await jupiterClient.getTransactionMessageAndLookupTables({
2001
+ transaction,
2002
+ });
2003
+ const jupiterInstructions = jupiterClient.getJupiterInstructions({
2004
+ transactionMessage,
2005
+ inputMint: inMarket.mint,
2006
+ outputMint: outMarket.mint,
2007
+ });
2008
+ const preInstructions = [];
2009
+ if (!outAssociatedTokenAccount) {
2010
+ outAssociatedTokenAccount = await this.getAssociatedTokenAccount(outMarket.marketIndex, false);
2011
+ const accountInfo = await this.connection.getAccountInfo(outAssociatedTokenAccount);
2012
+ if (!accountInfo) {
2013
+ preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(outAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, outMarket.mint));
2014
+ }
2015
+ }
2016
+ if (!inAssociatedTokenAccount) {
2017
+ inAssociatedTokenAccount = await this.getAssociatedTokenAccount(inMarket.marketIndex, false);
2018
+ const accountInfo = await this.connection.getAccountInfo(inAssociatedTokenAccount);
2019
+ if (!accountInfo) {
2020
+ preInstructions.push(this.createAssociatedTokenAccountIdempotentInstruction(inAssociatedTokenAccount, this.provider.wallet.publicKey, this.provider.wallet.publicKey, inMarket.mint));
2021
+ }
2022
+ }
2023
+ const { beginSwapIx, endSwapIx } = await this.getSwapIx({
2024
+ outMarketIndex,
2025
+ inMarketIndex,
2026
+ amountIn: amount,
2027
+ inTokenAccount: inAssociatedTokenAccount,
2028
+ outTokenAccount: outAssociatedTokenAccount,
2029
+ reduceOnly,
2030
+ });
2031
+ const instructions = [
2032
+ ...preInstructions,
2033
+ beginSwapIx,
2034
+ ...jupiterInstructions,
2035
+ endSwapIx,
2036
+ ];
2037
+ const tx = await this.buildTransaction(instructions, txParams, 0, lookupTables);
2038
+ const { txSig, slot } = await this.sendTransaction(tx);
2039
+ this.spotMarketLastSlotCache.set(outMarketIndex, slot);
2040
+ this.spotMarketLastSlotCache.set(inMarketIndex, slot);
2041
+ return txSig;
2042
+ }
2043
+ /**
2044
+ * Get the drift begin_swap and end_swap instructions
2045
+ *
2046
+ * @param outMarketIndex the market index of the token you're buying
2047
+ * @param inMarketIndex the market index of the token you're selling
2048
+ * @param amountIn the amount of the token to sell
2049
+ * @param inTokenAccount the token account to move the tokens being sold
2050
+ * @param outTokenAccount the token account to receive the tokens being bought
2051
+ * @param limitPrice the limit price of the swap
2052
+ */
2053
+ async getSwapIx({ outMarketIndex, inMarketIndex, amountIn, inTokenAccount, outTokenAccount, limitPrice, reduceOnly, }) {
2054
+ const userAccountPublicKey = await this.getUserAccountPublicKey();
2055
+ const remainingAccounts = this.getRemainingAccounts({
2056
+ userAccounts: [this.getUserAccount()],
2057
+ writableSpotMarketIndexes: [outMarketIndex, inMarketIndex],
2058
+ });
2059
+ const outSpotMarket = this.getSpotMarketAccount(outMarketIndex);
2060
+ const inSpotMarket = this.getSpotMarketAccount(inMarketIndex);
2061
+ const beginSwapIx = await this.program.instruction.beginSwap(inMarketIndex, outMarketIndex, amountIn, {
2062
+ accounts: {
2063
+ state: await this.getStatePublicKey(),
2064
+ user: userAccountPublicKey,
2065
+ userStats: this.getUserStatsAccountPublicKey(),
2066
+ authority: this.authority,
2067
+ outSpotMarketVault: outSpotMarket.vault,
2068
+ inSpotMarketVault: inSpotMarket.vault,
2069
+ inTokenAccount,
2070
+ outTokenAccount,
2071
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
2072
+ driftSigner: this.getStateAccount().signer,
2073
+ instructions: anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY,
2074
+ },
2075
+ remainingAccounts,
2076
+ });
2077
+ const endSwapIx = await this.program.instruction.endSwap(inMarketIndex, outMarketIndex, limitPrice !== null && limitPrice !== void 0 ? limitPrice : null, reduceOnly !== null && reduceOnly !== void 0 ? reduceOnly : null, {
2078
+ accounts: {
2079
+ state: await this.getStatePublicKey(),
2080
+ user: userAccountPublicKey,
2081
+ userStats: this.getUserStatsAccountPublicKey(),
2082
+ authority: this.authority,
2083
+ outSpotMarketVault: outSpotMarket.vault,
2084
+ inSpotMarketVault: inSpotMarket.vault,
2085
+ inTokenAccount,
2086
+ outTokenAccount,
2087
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
2088
+ driftSigner: this.getStateAccount().signer,
2089
+ instructions: anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY,
2090
+ },
2091
+ remainingAccounts,
2092
+ });
2093
+ return { beginSwapIx, endSwapIx };
2094
+ }
1950
2095
  async triggerOrder(userAccountPublicKey, user, order, txParams) {
1951
2096
  const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getTriggerOrderIx(userAccountPublicKey, user, order), txParams), [], this.opts);
1952
2097
  return txSig;
@@ -2707,7 +2852,7 @@ class DriftClient {
2707
2852
  const addFundsIx = await this.getAddInsuranceFundStakeIx(marketIndex, amount, tokenAccount);
2708
2853
  tx.add(addFundsIx);
2709
2854
  if (createWSOLTokenAccount) {
2710
- tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, tokenAccount, this.wallet.publicKey, this.wallet.publicKey, []));
2855
+ tx.add((0, spl_token_1.createCloseAccountInstruction)(tokenAccount, this.wallet.publicKey, this.wallet.publicKey, []));
2711
2856
  }
2712
2857
  const { txSig } = await this.sendTransaction(tx, additionalSigners, this.opts);
2713
2858
  return txSig;
@@ -2797,7 +2942,7 @@ class DriftClient {
2797
2942
  tx.add(removeStakeIx);
2798
2943
  // Close the wrapped sol account at the end of the transaction
2799
2944
  if (createWSOLTokenAccount) {
2800
- tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, tokenAccount, this.wallet.publicKey, this.wallet.publicKey, []));
2945
+ tx.add((0, spl_token_1.createCloseAccountInstruction)(tokenAccount, this.wallet.publicKey, this.wallet.publicKey, []));
2801
2946
  }
2802
2947
  const { txSig } = await this.sendTransaction(tx, additionalSigners, this.opts);
2803
2948
  return txSig;
@@ -2895,7 +3040,7 @@ class DriftClient {
2895
3040
  return this.txSender.sendVersionedTransaction(tx, additionalSigners, opts);
2896
3041
  }
2897
3042
  }
2898
- async buildTransaction(instructions, txParams) {
3043
+ async buildTransaction(instructions, txParams, txVersion, lookupTables) {
2899
3044
  var _a, _b;
2900
3045
  const allIx = [];
2901
3046
  const computeUnits = (_a = txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits) !== null && _a !== void 0 ? _a : 600000;
@@ -2916,16 +3061,20 @@ class DriftClient {
2916
3061
  else {
2917
3062
  allIx.push(instructions);
2918
3063
  }
2919
- if (this.txVersion === 'legacy') {
3064
+ txVersion = txVersion !== null && txVersion !== void 0 ? txVersion : this.txVersion;
3065
+ if (txVersion === 'legacy') {
2920
3066
  return new web3_js_1.Transaction().add(...allIx);
2921
3067
  }
2922
3068
  else {
2923
3069
  const marketLookupTable = await this.fetchMarketLookupTableAccount();
3070
+ lookupTables = lookupTables
3071
+ ? [...lookupTables, marketLookupTable]
3072
+ : [marketLookupTable];
2924
3073
  const message = new web3_js_1.TransactionMessage({
2925
3074
  payerKey: this.provider.wallet.publicKey,
2926
3075
  recentBlockhash: (await this.provider.connection.getRecentBlockhash(this.opts.preflightCommitment)).blockhash,
2927
3076
  instructions: allIx,
2928
- }).compileToV0Message([marketLookupTable]);
3077
+ }).compileToV0Message(lookupTables);
2929
3078
  return new web3_js_1.VersionedTransaction(message);
2930
3079
  }
2931
3080
  }
@@ -1,5 +1,5 @@
1
1
  import { Commitment, TransactionSignature } from '@solana/web3.js';
2
- import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, NewUserRecord, OrderActionRecord, OrderRecord, SettlePnlRecord, LPRecord, InsuranceFundRecord, SpotInterestRecord, InsuranceFundStakeRecord, CurveRecord } from '../index';
2
+ import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, NewUserRecord, OrderActionRecord, OrderRecord, SettlePnlRecord, LPRecord, InsuranceFundRecord, SpotInterestRecord, InsuranceFundStakeRecord, CurveRecord, SwapRecord } from '../index';
3
3
  export type EventSubscriptionOptions = {
4
4
  eventTypes?: EventType[];
5
5
  maxEventsPerType?: number;
@@ -35,9 +35,10 @@ export type EventMap = {
35
35
  SpotInterestRecord: Event<SpotInterestRecord>;
36
36
  InsuranceFundStakeRecord: Event<InsuranceFundStakeRecord>;
37
37
  CurveRecord: Event<CurveRecord>;
38
+ SwapRecord: Event<SwapRecord>;
38
39
  };
39
40
  export type EventType = keyof EventMap;
40
- export type DriftEvent = Event<DepositRecord> | Event<FundingPaymentRecord> | Event<LiquidationRecord> | Event<FundingRateRecord> | Event<OrderRecord> | Event<OrderActionRecord> | Event<SettlePnlRecord> | Event<NewUserRecord> | Event<LPRecord> | Event<InsuranceFundRecord> | Event<SpotInterestRecord> | Event<InsuranceFundStakeRecord> | Event<CurveRecord>;
41
+ export type DriftEvent = Event<DepositRecord> | Event<FundingPaymentRecord> | Event<LiquidationRecord> | Event<FundingRateRecord> | Event<OrderRecord> | Event<OrderActionRecord> | Event<SettlePnlRecord> | Event<NewUserRecord> | Event<LPRecord> | Event<InsuranceFundRecord> | Event<SpotInterestRecord> | Event<InsuranceFundStakeRecord> | Event<CurveRecord> | Event<SwapRecord>;
41
42
  export interface EventSubscriberEvents {
42
43
  newEvent: (event: WrappedEvent<EventType>) => void;
43
44
  }
@@ -16,6 +16,7 @@ exports.DefaultEventSubscriptionOptions = {
16
16
  'SpotInterestRecord',
17
17
  'InsuranceFundStakeRecord',
18
18
  'CurveRecord',
19
+ 'SwapRecord',
19
20
  ],
20
21
  maxEventsPerType: 4096,
21
22
  orderBy: 'blockchain',
@@ -8,7 +8,7 @@ const web3_js_1 = require("@solana/web3.js");
8
8
  const __2 = require("..");
9
9
  const spotMarkets_1 = require("../constants/spotMarkets");
10
10
  const getTokenAddress = (mintAddress, userPubKey) => {
11
- return spl_token_1.Token.getAssociatedTokenAddress(new web3_js_1.PublicKey(`ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`), spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
11
+ return (0, spl_token_1.getAssociatedTokenAddress)(new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
12
12
  };
13
13
  exports.getTokenAddress = getTokenAddress;
14
14
  const env = 'devnet';