@drift-labs/sdk 2.85.0-beta.1 → 2.85.0-beta.10

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 (41) hide show
  1. package/VERSION +1 -1
  2. package/bun.lockb +0 -0
  3. package/lib/accounts/bulkAccountLoader.d.ts +3 -3
  4. package/lib/accounts/pollingDriftClientAccountSubscriber.js +10 -2
  5. package/lib/accounts/pollingUserAccountSubscriber.d.ts +4 -3
  6. package/lib/accounts/pollingUserAccountSubscriber.js +7 -6
  7. package/lib/accounts/testBulkAccountLoader.d.ts +4 -0
  8. package/lib/accounts/testBulkAccountLoader.js +45 -0
  9. package/lib/bankrun/bankrunConnection.d.ts +71 -0
  10. package/lib/bankrun/bankrunConnection.js +285 -0
  11. package/lib/blockhashSubscriber/BlockhashSubscriber.js +22 -15
  12. package/lib/constants/perpMarkets.js +10 -0
  13. package/lib/constants/spotMarkets.js +10 -0
  14. package/lib/driftClient.d.ts +1 -1
  15. package/lib/driftClient.js +8 -2
  16. package/lib/events/eventSubscriber.js +12 -4
  17. package/lib/idl/drift.json +28 -8
  18. package/lib/testClient.js +1 -2
  19. package/lib/tokenFaucet.d.ts +3 -1
  20. package/lib/tokenFaucet.js +41 -8
  21. package/lib/tx/txParamProcessor.d.ts +2 -1
  22. package/lib/tx/txParamProcessor.js +7 -3
  23. package/lib/types.d.ts +1 -0
  24. package/lib/user.js +1 -1
  25. package/package.json +3 -1
  26. package/src/accounts/bulkAccountLoader.ts +3 -2
  27. package/src/accounts/pollingDriftClientAccountSubscriber.ts +16 -3
  28. package/src/accounts/pollingUserAccountSubscriber.ts +13 -12
  29. package/src/accounts/testBulkAccountLoader.ts +53 -0
  30. package/src/bankrun/bankrunConnection.ts +466 -0
  31. package/src/blockhashSubscriber/BlockhashSubscriber.ts +24 -19
  32. package/src/constants/perpMarkets.ts +10 -0
  33. package/src/constants/spotMarkets.ts +10 -0
  34. package/src/driftClient.ts +12 -3
  35. package/src/events/eventSubscriber.ts +5 -0
  36. package/src/idl/drift.json +28 -8
  37. package/src/testClient.ts +1 -2
  38. package/src/tokenFaucet.ts +49 -12
  39. package/src/tx/txParamProcessor.ts +11 -2
  40. package/src/types.ts +1 -0
  41. package/src/user.ts +5 -2
@@ -0,0 +1,466 @@
1
+ import {
2
+ TransactionConfirmationStatus,
3
+ AccountInfo,
4
+ Keypair,
5
+ PublicKey,
6
+ Transaction,
7
+ RpcResponseAndContext,
8
+ Commitment,
9
+ TransactionSignature,
10
+ SignatureStatusConfig,
11
+ SignatureStatus,
12
+ GetVersionedTransactionConfig,
13
+ GetTransactionConfig,
14
+ VersionedTransaction,
15
+ SimulateTransactionConfig,
16
+ SimulatedTransactionResponse,
17
+ TransactionReturnData,
18
+ TransactionError,
19
+ SignatureResultCallback,
20
+ ClientSubscriptionId,
21
+ Connection as SolanaConnection,
22
+ SystemProgram,
23
+ Blockhash,
24
+ LogsFilter,
25
+ LogsCallback,
26
+ AccountChangeCallback,
27
+ LAMPORTS_PER_SOL,
28
+ } from '@solana/web3.js';
29
+ import {
30
+ ProgramTestContext,
31
+ BanksClient,
32
+ BanksTransactionResultWithMeta,
33
+ Clock,
34
+ } from 'solana-bankrun';
35
+ import { BankrunProvider } from 'anchor-bankrun';
36
+ import bs58 from 'bs58';
37
+ import { BN, Wallet } from '@coral-xyz/anchor';
38
+ import { Account, TOKEN_PROGRAM_ID, unpackAccount } from '@solana/spl-token';
39
+
40
+ export type Connection = SolanaConnection | BankrunConnection;
41
+
42
+ type BankrunTransactionMetaNormalized = {
43
+ logMessages: string[];
44
+ err: TransactionError;
45
+ };
46
+
47
+ type BankrunTransactionRespose = {
48
+ slot: number;
49
+ meta: BankrunTransactionMetaNormalized;
50
+ };
51
+
52
+ export class BankrunContextWrapper {
53
+ public readonly connection: BankrunConnection;
54
+ public readonly context: ProgramTestContext;
55
+ public readonly provider: BankrunProvider;
56
+ public readonly commitment: Commitment = 'confirmed';
57
+
58
+ constructor(context: ProgramTestContext) {
59
+ this.context = context;
60
+ this.provider = new BankrunProvider(context);
61
+ this.connection = new BankrunConnection(
62
+ this.context.banksClient,
63
+ this.context
64
+ );
65
+ }
66
+
67
+ async sendTransaction(
68
+ tx: Transaction,
69
+ additionalSigners?: Keypair[]
70
+ ): Promise<TransactionSignature> {
71
+ tx.recentBlockhash = (await this.getLatestBlockhash()).toString();
72
+ tx.feePayer = this.context.payer.publicKey;
73
+ if (!additionalSigners) {
74
+ additionalSigners = [];
75
+ }
76
+ tx.sign(this.context.payer, ...additionalSigners);
77
+ return await this.connection.sendTransaction(tx);
78
+ }
79
+
80
+ async getMinimumBalanceForRentExemption(_: number): Promise<number> {
81
+ return 10 * LAMPORTS_PER_SOL;
82
+ }
83
+
84
+ async fundKeypair(
85
+ keypair: Keypair | Wallet,
86
+ lamports: number | bigint
87
+ ): Promise<TransactionSignature> {
88
+ const ixs = [
89
+ SystemProgram.transfer({
90
+ fromPubkey: this.context.payer.publicKey,
91
+ toPubkey: keypair.publicKey,
92
+ lamports,
93
+ }),
94
+ ];
95
+ const tx = new Transaction().add(...ixs);
96
+ return await this.sendTransaction(tx);
97
+ }
98
+
99
+ async getLatestBlockhash(): Promise<Blockhash> {
100
+ const blockhash = await this.connection.getLatestBlockhash('finalized');
101
+
102
+ return blockhash.blockhash;
103
+ }
104
+
105
+ printTxLogs(signature: string): void {
106
+ this.connection.printTxLogs(signature);
107
+ }
108
+
109
+ async moveTimeForward(increment: number): Promise<void> {
110
+ const currentClock = await this.context.banksClient.getClock();
111
+ const newUnixTimestamp = currentClock.unixTimestamp + BigInt(increment);
112
+ const newClock = new Clock(
113
+ currentClock.slot,
114
+ currentClock.epochStartTimestamp,
115
+ currentClock.epoch,
116
+ currentClock.leaderScheduleEpoch,
117
+ newUnixTimestamp
118
+ );
119
+ await this.context.setClock(newClock);
120
+ }
121
+ }
122
+
123
+ export class BankrunConnection {
124
+ private readonly _banksClient: BanksClient;
125
+ private readonly context: ProgramTestContext;
126
+ private transactionToMeta: Map<
127
+ TransactionSignature,
128
+ BanksTransactionResultWithMeta
129
+ > = new Map();
130
+ private clock: Clock;
131
+
132
+ private nextClientSubscriptionId = 0;
133
+ private onLogCallbacks = new Map<number, LogsCallback>();
134
+ private onAccountChangeCallbacks = new Map<
135
+ number,
136
+ [PublicKey, AccountChangeCallback]
137
+ >();
138
+
139
+ constructor(banksClient: BanksClient, context: ProgramTestContext) {
140
+ this._banksClient = banksClient;
141
+ this.context = context;
142
+ }
143
+
144
+ getSlot(): Promise<bigint> {
145
+ return this._banksClient.getSlot();
146
+ }
147
+
148
+ toConnection(): SolanaConnection {
149
+ return this as unknown as SolanaConnection;
150
+ }
151
+
152
+ async getTokenAccount(publicKey: PublicKey): Promise<Account> {
153
+ const info = await this.getAccountInfo(publicKey);
154
+ return unpackAccount(publicKey, info, TOKEN_PROGRAM_ID);
155
+ }
156
+
157
+ async getMultipleAccountsInfo(
158
+ publicKeys: PublicKey[],
159
+ _commitmentOrConfig?: Commitment
160
+ ): Promise<AccountInfo<Buffer>[]> {
161
+ const accountInfos = [];
162
+
163
+ for (const publicKey of publicKeys) {
164
+ const accountInfo = await this.getAccountInfo(publicKey);
165
+ accountInfos.push(accountInfo);
166
+ }
167
+
168
+ return accountInfos;
169
+ }
170
+
171
+ async getAccountInfo(
172
+ publicKey: PublicKey
173
+ ): Promise<null | AccountInfo<Buffer>> {
174
+ const parsedAccountInfo = await this.getParsedAccountInfo(publicKey);
175
+ return parsedAccountInfo ? parsedAccountInfo.value : null;
176
+ }
177
+
178
+ async getAccountInfoAndContext(
179
+ publicKey: PublicKey,
180
+ _commitment?: Commitment
181
+ ): Promise<RpcResponseAndContext<null | AccountInfo<Buffer>>> {
182
+ return await this.getParsedAccountInfo(publicKey);
183
+ }
184
+ async sendRawTransaction(
185
+ rawTransaction: Buffer | Uint8Array | Array<number>,
186
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
187
+ _options?: any
188
+ ): Promise<TransactionSignature> {
189
+ const tx = Transaction.from(rawTransaction);
190
+ const signature = await this.sendTransaction(tx);
191
+ return signature;
192
+ }
193
+
194
+ async sendTransaction(tx: Transaction): Promise<TransactionSignature> {
195
+ const banksTransactionMeta = await this._banksClient.tryProcessTransaction(
196
+ tx
197
+ );
198
+ if (banksTransactionMeta.result) {
199
+ throw new Error(banksTransactionMeta.result);
200
+ }
201
+ const signature = bs58.encode(tx.signatures[0].signature);
202
+ this.transactionToMeta.set(signature, banksTransactionMeta);
203
+ let finalizedCount = 0;
204
+ while (finalizedCount < 10) {
205
+ const signatureStatus = (await this.getSignatureStatus(signature)).value
206
+ .confirmationStatus;
207
+ if (signatureStatus.toString() == '"finalized"') {
208
+ finalizedCount += 1;
209
+ }
210
+ }
211
+
212
+ // update the clock slot/timestamp
213
+ // sometimes race condition causes failures so we retry
214
+ try {
215
+ await this.updateSlotAndClock();
216
+ } catch (e) {
217
+ await this.updateSlotAndClock();
218
+ }
219
+
220
+ if (this.onLogCallbacks.size > 0) {
221
+ const transaction = await this.getTransaction(signature);
222
+
223
+ const context = { slot: transaction.slot };
224
+ const logs = {
225
+ logs: transaction.meta.logMessages,
226
+ err: transaction.meta.err,
227
+ signature,
228
+ };
229
+ for (const logCallback of this.onLogCallbacks.values()) {
230
+ logCallback(logs, context);
231
+ }
232
+ }
233
+
234
+ for (const [
235
+ publicKey,
236
+ callback,
237
+ ] of this.onAccountChangeCallbacks.values()) {
238
+ const accountInfo = await this.getParsedAccountInfo(publicKey);
239
+ callback(accountInfo.value, accountInfo.context);
240
+ }
241
+
242
+ return signature;
243
+ }
244
+
245
+ private async updateSlotAndClock() {
246
+ const currentSlot = await this.getSlot();
247
+ const nextSlot = currentSlot + BigInt(1);
248
+ this.context.warpToSlot(nextSlot);
249
+ const currentClock = await this._banksClient.getClock();
250
+ const newClock = new Clock(
251
+ nextSlot,
252
+ currentClock.epochStartTimestamp,
253
+ currentClock.epoch,
254
+ currentClock.leaderScheduleEpoch,
255
+ currentClock.unixTimestamp + BigInt(1)
256
+ );
257
+ this.context.setClock(newClock);
258
+ this.clock = newClock;
259
+ }
260
+
261
+ getTime(): number {
262
+ return Number(this.clock.unixTimestamp);
263
+ }
264
+
265
+ async getParsedAccountInfo(
266
+ publicKey: PublicKey
267
+ ): Promise<RpcResponseAndContext<AccountInfo<Buffer>>> {
268
+ const accountInfoBytes = await this._banksClient.getAccount(publicKey);
269
+ if (accountInfoBytes === null) {
270
+ return {
271
+ context: { slot: Number(await this._banksClient.getSlot()) },
272
+ value: null,
273
+ };
274
+ }
275
+ accountInfoBytes.data = Buffer.from(accountInfoBytes.data);
276
+ const accountInfoBuffer = accountInfoBytes as AccountInfo<Buffer>;
277
+ return {
278
+ context: { slot: Number(await this._banksClient.getSlot()) },
279
+ value: accountInfoBuffer,
280
+ };
281
+ }
282
+
283
+ async getLatestBlockhash(commitment?: Commitment): Promise<
284
+ Readonly<{
285
+ blockhash: string;
286
+ lastValidBlockHeight: number;
287
+ }>
288
+ > {
289
+ const blockhashAndBlockheight = await this._banksClient.getLatestBlockhash(
290
+ commitment
291
+ );
292
+ return {
293
+ blockhash: blockhashAndBlockheight[0],
294
+ lastValidBlockHeight: Number(blockhashAndBlockheight[1]),
295
+ };
296
+ }
297
+
298
+ async getSignatureStatus(
299
+ signature: string,
300
+ _config?: SignatureStatusConfig
301
+ ): Promise<RpcResponseAndContext<null | SignatureStatus>> {
302
+ const transactionStatus = await this._banksClient.getTransactionStatus(
303
+ signature
304
+ );
305
+ if (transactionStatus === null) {
306
+ return {
307
+ context: { slot: Number(await this._banksClient.getSlot()) },
308
+ value: null,
309
+ };
310
+ }
311
+ return {
312
+ context: { slot: Number(await this._banksClient.getSlot()) },
313
+ value: {
314
+ slot: Number(transactionStatus.slot),
315
+ confirmations: Number(transactionStatus.confirmations),
316
+ err: transactionStatus.err,
317
+ confirmationStatus:
318
+ transactionStatus.confirmationStatus as TransactionConfirmationStatus,
319
+ },
320
+ };
321
+ }
322
+
323
+ /**
324
+ * There's really no direct equivalent to getTransaction exposed by SolanaProgramTest, so we do the best that we can here - it's a little hacky.
325
+ */
326
+ async getTransaction(
327
+ signature: string,
328
+ _rawConfig?: GetTransactionConfig | GetVersionedTransactionConfig
329
+ ): Promise<BankrunTransactionRespose | null> {
330
+ const txMeta = this.transactionToMeta.get(
331
+ signature as TransactionSignature
332
+ );
333
+ if (txMeta === undefined) {
334
+ return null;
335
+ }
336
+ const transactionStatus = await this._banksClient.getTransactionStatus(
337
+ signature
338
+ );
339
+ const meta: BankrunTransactionMetaNormalized = {
340
+ logMessages: txMeta.meta.logMessages,
341
+ err: txMeta.result,
342
+ };
343
+ return {
344
+ slot: Number(transactionStatus.slot),
345
+ meta,
346
+ };
347
+ }
348
+
349
+ findComputeUnitConsumption(signature: string): bigint {
350
+ const txMeta = this.transactionToMeta.get(
351
+ signature as TransactionSignature
352
+ );
353
+ if (txMeta === undefined) {
354
+ throw new Error('Transaction not found');
355
+ }
356
+ return txMeta.meta.computeUnitsConsumed;
357
+ }
358
+
359
+ printTxLogs(signature: string): void {
360
+ const txMeta = this.transactionToMeta.get(
361
+ signature as TransactionSignature
362
+ );
363
+ if (txMeta === undefined) {
364
+ throw new Error('Transaction not found');
365
+ }
366
+ console.log(txMeta.meta.logMessages);
367
+ }
368
+
369
+ async simulateTransaction(
370
+ transaction: Transaction | VersionedTransaction,
371
+ _config?: SimulateTransactionConfig
372
+ ): Promise<RpcResponseAndContext<SimulatedTransactionResponse>> {
373
+ const simulationResult = await this._banksClient.simulateTransaction(
374
+ transaction
375
+ );
376
+ const returnDataProgramId =
377
+ simulationResult.meta?.returnData?.programId.toBase58();
378
+ const returnDataNormalized = Buffer.from(
379
+ simulationResult.meta?.returnData?.data
380
+ ).toString('base64');
381
+ const returnData: TransactionReturnData = {
382
+ programId: returnDataProgramId,
383
+ data: [returnDataNormalized, 'base64'],
384
+ };
385
+ return {
386
+ context: { slot: Number(await this._banksClient.getSlot()) },
387
+ value: {
388
+ err: simulationResult.result,
389
+ logs: simulationResult.meta.logMessages,
390
+ accounts: undefined,
391
+ unitsConsumed: Number(simulationResult.meta.computeUnitsConsumed),
392
+ returnData,
393
+ },
394
+ };
395
+ }
396
+
397
+ onSignature(
398
+ signature: string,
399
+ callback: SignatureResultCallback,
400
+ commitment?: Commitment
401
+ ): ClientSubscriptionId {
402
+ const txMeta = this.transactionToMeta.get(
403
+ signature as TransactionSignature
404
+ );
405
+ this._banksClient.getSlot(commitment).then((slot) => {
406
+ if (txMeta) {
407
+ callback({ err: txMeta.result }, { slot: Number(slot) });
408
+ }
409
+ });
410
+ return 0;
411
+ }
412
+
413
+ async removeSignatureListener(_clientSubscriptionId: number): Promise<void> {
414
+ // Nothing actually has to happen here! Pretty cool, huh?
415
+ // This function signature only exists to match the web3js interface
416
+ }
417
+
418
+ onLogs(
419
+ filter: LogsFilter,
420
+ callback: LogsCallback,
421
+ _commitment?: Commitment
422
+ ): ClientSubscriptionId {
423
+ const subscriptId = this.nextClientSubscriptionId;
424
+
425
+ this.onLogCallbacks.set(subscriptId, callback);
426
+
427
+ this.nextClientSubscriptionId += 1;
428
+
429
+ return subscriptId;
430
+ }
431
+
432
+ async removeOnLogsListener(
433
+ clientSubscriptionId: ClientSubscriptionId
434
+ ): Promise<void> {
435
+ this.onLogCallbacks.delete(clientSubscriptionId);
436
+ }
437
+
438
+ onAccountChange(
439
+ publicKey: PublicKey,
440
+ callback: AccountChangeCallback,
441
+ // @ts-ignore
442
+ _commitment?: Commitment
443
+ ): ClientSubscriptionId {
444
+ const subscriptId = this.nextClientSubscriptionId;
445
+
446
+ this.onAccountChangeCallbacks.set(subscriptId, [publicKey, callback]);
447
+
448
+ this.nextClientSubscriptionId += 1;
449
+
450
+ return subscriptId;
451
+ }
452
+
453
+ async removeAccountChangeListener(
454
+ clientSubscriptionId: ClientSubscriptionId
455
+ ): Promise<void> {
456
+ this.onAccountChangeCallbacks.delete(clientSubscriptionId);
457
+ }
458
+
459
+ async getMinimumBalanceForRentExemption(_: number): Promise<number> {
460
+ return 10 * LAMPORTS_PER_SOL;
461
+ }
462
+ }
463
+
464
+ export function asBN(value: number | bigint): BN {
465
+ return new BN(Number(value));
466
+ }
@@ -75,27 +75,32 @@ export class BlockhashSubscriber {
75
75
  }
76
76
 
77
77
  async updateBlockhash() {
78
- const [resp, lastConfirmedBlockHeight] = await Promise.all([
79
- this.connection.getLatestBlockhashAndContext({
80
- commitment: this.commitment,
81
- }),
82
- this.connection.getBlockHeight({ commitment: this.commitment }),
83
- ]);
84
- this.latestBlockHeight = lastConfirmedBlockHeight;
85
- this.latestBlockHeightContext = resp.context;
86
-
87
- // avoid caching duplicate blockhashes
88
- if (this.blockhashes.length > 0) {
89
- if (
90
- resp.value.blockhash ===
91
- this.blockhashes[this.blockhashes.length - 1].blockhash
92
- ) {
93
- return;
78
+ try {
79
+ const [resp, lastConfirmedBlockHeight] = await Promise.all([
80
+ this.connection.getLatestBlockhashAndContext({
81
+ commitment: this.commitment,
82
+ }),
83
+ this.connection.getBlockHeight({ commitment: this.commitment }),
84
+ ]);
85
+ this.latestBlockHeight = lastConfirmedBlockHeight;
86
+ this.latestBlockHeightContext = resp.context;
87
+
88
+ // avoid caching duplicate blockhashes
89
+ if (this.blockhashes.length > 0) {
90
+ if (
91
+ resp.value.blockhash ===
92
+ this.blockhashes[this.blockhashes.length - 1].blockhash
93
+ ) {
94
+ return;
95
+ }
94
96
  }
95
- }
96
97
 
97
- this.blockhashes.push(resp.value);
98
- this.pruneBlockhashes();
98
+ this.blockhashes.push(resp.value);
99
+ } catch (e) {
100
+ console.error('Error updating blockhash:\n', e);
101
+ } finally {
102
+ this.pruneBlockhashes();
103
+ }
99
104
  }
100
105
 
101
106
  async subscribe() {
@@ -597,6 +597,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
597
597
  launchTs: 1718021389000,
598
598
  oracleSource: OracleSource.SWITCHBOARD,
599
599
  },
600
+ {
601
+ fullName: 'ZEX',
602
+ category: ['DEX', 'Solana'],
603
+ symbol: 'ZEX-PERP',
604
+ baseAssetSymbol: 'ZEX',
605
+ marketIndex: 33,
606
+ oracle: new PublicKey('4gdbqxkMrF1bYVeEJKRmTqCCvJjRCZrRhxvriGY6SwLj'),
607
+ launchTs: 1719415157000,
608
+ oracleSource: OracleSource.SWITCHBOARD,
609
+ },
600
610
  ];
601
611
 
602
612
  export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
@@ -283,6 +283,16 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
283
283
  precisionExp: SIX,
284
284
  launchTs: 1718811089000,
285
285
  },
286
+ {
287
+ symbol: 'JLP',
288
+ marketIndex: 19,
289
+ oracle: new PublicKey('pmHEXBam7kbmCCg5ED5V7RNMN8e34sKu338KeuFAGof'),
290
+ oracleSource: OracleSource.SWITCHBOARD,
291
+ mint: new PublicKey('27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4'),
292
+ precision: new BN(10).pow(SIX),
293
+ precisionExp: SIX,
294
+ launchTs: 1719415157000,
295
+ },
286
296
  ];
287
297
 
288
298
  export const SpotMarkets: { [key in DriftEnv]: SpotMarketConfig[] } = {
@@ -2770,7 +2770,7 @@ export class DriftClient {
2770
2770
  }
2771
2771
 
2772
2772
  public async sendSignedTx(
2773
- tx: Transaction,
2773
+ tx: Transaction | VersionedTransaction,
2774
2774
  opts?: ConfirmOptions
2775
2775
  ): Promise<TransactionSignature> {
2776
2776
  const { txSig } = await this.sendTransaction(
@@ -4118,6 +4118,10 @@ export class DriftClient {
4118
4118
  const outMarket = this.getSpotMarketAccount(outMarketIndex);
4119
4119
  const inMarket = this.getSpotMarketAccount(inMarketIndex);
4120
4120
 
4121
+ const isExactOut = swapMode === 'ExactOut' || quote.swapMode === 'ExactOut';
4122
+ const amountIn = new BN(quote.inAmount);
4123
+ const exactOutBufferedAmountIn = amountIn.muln(1001).divn(1000); // Add 10bp buffer
4124
+
4121
4125
  if (!quote) {
4122
4126
  const fetchedQuote = await jupiterClient.getQuote({
4123
4127
  inputMint: inMarket.mint,
@@ -4198,7 +4202,7 @@ export class DriftClient {
4198
4202
  const { beginSwapIx, endSwapIx } = await this.getSwapIx({
4199
4203
  outMarketIndex,
4200
4204
  inMarketIndex,
4201
- amountIn: new BN(quote.inAmount),
4205
+ amountIn: isExactOut ? exactOutBufferedAmountIn : amountIn,
4202
4206
  inTokenAccount: inAssociatedTokenAccount,
4203
4207
  outTokenAccount: outAssociatedTokenAccount,
4204
4208
  reduceOnly,
@@ -4664,7 +4668,8 @@ export class DriftClient {
4664
4668
  await TransactionParamProcessor.getTxSimComputeUnits(
4665
4669
  placeAndTakeTxToSim,
4666
4670
  this.connection,
4667
- txParams.computeUnitsBufferMultiplier ?? 1.2
4671
+ txParams.computeUnitsBufferMultiplier ?? 1.2,
4672
+ txParams.lowerBoundCu
4668
4673
  );
4669
4674
 
4670
4675
  if (shouldExitIfSimulationFails && !simulationResult.success) {
@@ -4784,6 +4789,10 @@ export class DriftClient {
4784
4789
  exitEarlyIfSimFails
4785
4790
  );
4786
4791
 
4792
+ if (!txsToSign) {
4793
+ return null;
4794
+ }
4795
+
4787
4796
  const signedTxs = (
4788
4797
  await this.txHandler.getSignedTransactionMap(
4789
4798
  txsToSign,
@@ -45,6 +45,7 @@ export class EventSubscriber {
45
45
 
46
46
  if (this.options.logProviderConfig.type === 'websocket') {
47
47
  this.logProvider = new WebSocketLogProvider(
48
+ // @ts-ignore
48
49
  this.connection,
49
50
  this.address,
50
51
  this.options.commitment,
@@ -52,6 +53,7 @@ export class EventSubscriber {
52
53
  );
53
54
  } else {
54
55
  this.logProvider = new PollingLogProvider(
56
+ // @ts-ignore
55
57
  this.connection,
56
58
  this.address,
57
59
  options.commitment,
@@ -101,6 +103,7 @@ export class EventSubscriber {
101
103
  this.logProvider.eventEmitter.removeAllListeners('reconnect');
102
104
  this.unsubscribe().then(() => {
103
105
  this.logProvider = new PollingLogProvider(
106
+ // @ts-ignore
104
107
  this.connection,
105
108
  this.address,
106
109
  this.options.commitment,
@@ -148,6 +151,7 @@ export class EventSubscriber {
148
151
  }
149
152
 
150
153
  const wrappedEvents = this.parseEventsFromLogs(txSig, slot, logs);
154
+
151
155
  for (const wrappedEvent of wrappedEvents) {
152
156
  this.eventListMap.get(wrappedEvent.eventType).insert(wrappedEvent);
153
157
  }
@@ -188,6 +192,7 @@ export class EventSubscriber {
188
192
  const untilTx: TransactionSignature = this.options.untilTx;
189
193
  while (txFetched < this.options.maxTx) {
190
194
  const response = await fetchLogs(
195
+ // @ts-ignore
191
196
  this.connection,
192
197
  this.address,
193
198
  this.options.commitment === 'finalized' ? 'finalized' : 'confirmed',
@@ -3934,6 +3934,12 @@
3934
3934
  {
3935
3935
  "name": "maxBorrowRate",
3936
3936
  "type": "u32"
3937
+ },
3938
+ {
3939
+ "name": "minBorrowRate",
3940
+ "type": {
3941
+ "option": "u8"
3942
+ }
3937
3943
  }
3938
3944
  ]
3939
3945
  },
@@ -6198,13 +6204,13 @@
6198
6204
  "type": "i16"
6199
6205
  },
6200
6206
  {
6201
- "name": "padding1",
6202
- "type": {
6203
- "array": [
6204
- "u8",
6205
- 2
6206
- ]
6207
- }
6207
+ "name": "maxTokenBorrowsFraction",
6208
+ "docs": [
6209
+ "What fraction of max_token_deposits",
6210
+ "disabled when 0, 1 => 1/10000 => .01% of max_token_deposits",
6211
+ "precision: X/10000"
6212
+ ],
6213
+ "type": "u16"
6208
6214
  },
6209
6215
  {
6210
6216
  "name": "flashLoanAmount",
@@ -6240,12 +6246,21 @@
6240
6246
  ],
6241
6247
  "type": "u64"
6242
6248
  },
6249
+ {
6250
+ "name": "minBorrowRate",
6251
+ "docs": [
6252
+ "The min borrow rate for this market when the market regardless of utilization",
6253
+ "1 => 1/200 => .5%",
6254
+ "precision: X/200"
6255
+ ],
6256
+ "type": "u8"
6257
+ },
6243
6258
  {
6244
6259
  "name": "padding",
6245
6260
  "type": {
6246
6261
  "array": [
6247
6262
  "u8",
6248
- 48
6263
+ 47
6249
6264
  ]
6250
6265
  }
6251
6266
  }
@@ -12009,6 +12024,11 @@
12009
12024
  "code": 6267,
12010
12025
  "name": "UnableToParsePullOracleMessage",
12011
12026
  "msg": "Unable to parse pull oracle message"
12027
+ },
12028
+ {
12029
+ "code": 6268,
12030
+ "name": "MaxBorrows",
12031
+ "msg": "Can not borow more than max borrows"
12012
12032
  }
12013
12033
  ]
12014
12034
  }