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

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 (59) 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 +3 -1
  15. package/lib/driftClient.js +45 -32
  16. package/lib/driftClientConfig.d.ts +2 -1
  17. package/lib/events/eventSubscriber.js +12 -4
  18. package/lib/idl/drift.json +28 -8
  19. package/lib/testClient.js +1 -2
  20. package/lib/tokenFaucet.d.ts +3 -1
  21. package/lib/tokenFaucet.js +41 -8
  22. package/lib/tx/blockhashFetcher/baseBlockhashFetcher.d.ts +8 -0
  23. package/lib/tx/blockhashFetcher/baseBlockhashFetcher.js +13 -0
  24. package/lib/tx/blockhashFetcher/cachedBlockhashFetcher.d.ts +28 -0
  25. package/lib/tx/blockhashFetcher/cachedBlockhashFetcher.js +73 -0
  26. package/lib/tx/blockhashFetcher/types.d.ts +4 -0
  27. package/lib/tx/blockhashFetcher/types.js +2 -0
  28. package/lib/tx/txHandler.d.ts +10 -0
  29. package/lib/tx/txHandler.js +16 -7
  30. package/lib/tx/txParamProcessor.d.ts +2 -1
  31. package/lib/tx/txParamProcessor.js +7 -3
  32. package/lib/tx/utils.d.ts +2 -0
  33. package/lib/tx/utils.js +10 -0
  34. package/lib/types.d.ts +1 -0
  35. package/lib/user.js +1 -1
  36. package/package.json +4 -1
  37. package/src/accounts/bulkAccountLoader.ts +3 -2
  38. package/src/accounts/pollingDriftClientAccountSubscriber.ts +16 -3
  39. package/src/accounts/pollingUserAccountSubscriber.ts +13 -12
  40. package/src/accounts/testBulkAccountLoader.ts +53 -0
  41. package/src/bankrun/bankrunConnection.ts +466 -0
  42. package/src/blockhashSubscriber/BlockhashSubscriber.ts +24 -19
  43. package/src/constants/perpMarkets.ts +10 -0
  44. package/src/constants/spotMarkets.ts +10 -0
  45. package/src/driftClient.ts +91 -42
  46. package/src/driftClientConfig.ts +2 -1
  47. package/src/events/eventSubscriber.ts +5 -0
  48. package/src/idl/drift.json +28 -8
  49. package/src/testClient.ts +1 -2
  50. package/src/tokenFaucet.ts +49 -12
  51. package/src/tx/blockhashFetcher/baseBlockhashFetcher.ts +19 -0
  52. package/src/tx/blockhashFetcher/cachedBlockhashFetcher.ts +90 -0
  53. package/src/tx/blockhashFetcher/types.ts +5 -0
  54. package/src/tx/txHandler.ts +38 -4
  55. package/src/tx/txParamProcessor.ts +11 -2
  56. package/src/tx/utils.ts +11 -0
  57. package/src/types.ts +1 -0
  58. package/src/user.ts +5 -2
  59. package/tests/tx/cachedBlockhashFetcher.test.ts +96 -0
@@ -8,7 +8,8 @@ type TransactionBuildingProps = {
8
8
  */
9
9
  export declare class TransactionParamProcessor {
10
10
  private static getComputeUnitsFromSim;
11
- static getTxSimComputeUnits(tx: VersionedTransaction, connection: Connection, bufferMultiplier: number): Promise<{
11
+ static getTxSimComputeUnits(tx: VersionedTransaction, connection: Connection, bufferMultiplier: number, // Making this a mandatory param to force the user to remember that simulated CU's can be inaccurate and a buffer should be applied
12
+ lowerBoundCu?: number): Promise<{
12
13
  success: boolean;
13
14
  computeUnits: number;
14
15
  }>;
@@ -15,8 +15,8 @@ class TransactionParamProcessor {
15
15
  }
16
16
  return undefined;
17
17
  }
18
- static async getTxSimComputeUnits(tx, connection, bufferMultiplier // Making this a mandatory param to force the user to remember that simulated CU's can be inaccurate and a buffer should be applied
19
- ) {
18
+ static async getTxSimComputeUnits(tx, connection, bufferMultiplier, // Making this a mandatory param to force the user to remember that simulated CU's can be inaccurate and a buffer should be applied
19
+ lowerBoundCu) {
20
20
  var _a, _b, _c;
21
21
  try {
22
22
  if (TEST_SIMS_ALWAYS_FAIL)
@@ -29,7 +29,11 @@ class TransactionParamProcessor {
29
29
  }
30
30
  const computeUnits = await this.getComputeUnitsFromSim(simTxResult);
31
31
  // Apply the buffer, but round down to the MAX_COMPUTE_UNITS, and round up to the nearest whole number
32
- const bufferedComputeUnits = Math.ceil(Math.min(computeUnits * bufferMultiplier, MAX_COMPUTE_UNITS));
32
+ let bufferedComputeUnits = Math.ceil(Math.min(computeUnits * bufferMultiplier, MAX_COMPUTE_UNITS));
33
+ // If a lower bound CU is passed then enforce it
34
+ if (lowerBoundCu) {
35
+ bufferedComputeUnits = Math.max(bufferedComputeUnits, Math.min(lowerBoundCu, MAX_COMPUTE_UNITS));
36
+ }
33
37
  return {
34
38
  success: true,
35
39
  computeUnits: bufferedComputeUnits,
@@ -0,0 +1,2 @@
1
+ import { Transaction, VersionedTransaction } from '@solana/web3.js';
2
+ export declare const isVersionedTransaction: (tx: Transaction | VersionedTransaction) => boolean;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isVersionedTransaction = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const isVersionedTransaction = (tx) => {
6
+ const version = tx === null || tx === void 0 ? void 0 : tx.version;
7
+ const isVersionedTx = tx instanceof web3_js_1.VersionedTransaction || version !== undefined;
8
+ return isVersionedTx;
9
+ };
10
+ exports.isVersionedTransaction = isVersionedTransaction;
package/lib/types.d.ts CHANGED
@@ -1085,6 +1085,7 @@ export type ProcessingTxParams = {
1085
1085
  computeUnitsBufferMultiplier?: number;
1086
1086
  useSimulatedComputeUnitsForCUPriceCalculation?: boolean;
1087
1087
  getCUPriceFromComputeUnits?: (computeUnits: number) => number;
1088
+ lowerBoundCu?: number;
1088
1089
  };
1089
1090
  export type TxParams = BaseTxParams & ProcessingTxParams;
1090
1091
  export declare class SwapReduceOnly {
package/lib/user.js CHANGED
@@ -27,7 +27,7 @@ class User {
27
27
  this.driftClient = config.driftClient;
28
28
  this.userAccountPublicKey = config.userAccountPublicKey;
29
29
  if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
30
- this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
30
+ this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.driftClient.connection, config.userAccountPublicKey, config.accountSubscription.accountLoader, this.driftClient.program.account.user.coder.accounts.decodeUnchecked.bind(this.driftClient.program.account.user.coder.accounts));
31
31
  }
32
32
  else if (((_b = config.accountSubscription) === null || _b === void 0 ? void 0 : _b.type) === 'custom') {
33
33
  this.accountSubscriber = config.accountSubscription.userAccountSubscriber;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.85.0-beta.1",
3
+ "version": "2.85.0-beta.11",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -41,7 +41,9 @@
41
41
  "@pythnetwork/pyth-solana-receiver": "^0.7.0",
42
42
  "@solana/spl-token": "0.3.7",
43
43
  "@solana/web3.js": "1.92.3",
44
+ "anchor-bankrun": "^0.3.0",
44
45
  "rpc-websockets": "7.5.1",
46
+ "solana-bankrun": "^0.3.0",
45
47
  "strict-event-emitter-types": "^2.0.0",
46
48
  "uuid": "^8.3.2",
47
49
  "zstddec": "^0.1.0"
@@ -63,6 +65,7 @@
63
65
  "mocha": "^10.0.0",
64
66
  "object-sizeof": "^2.6.3",
65
67
  "prettier": "3.0.1",
68
+ "sinon": "^18.0.0",
66
69
  "ts-node": "^10.8.0",
67
70
  "typescript": "^4.9.5"
68
71
  },
@@ -1,9 +1,10 @@
1
- import { Commitment, Connection, PublicKey } from '@solana/web3.js';
1
+ import { Commitment, PublicKey } from '@solana/web3.js';
2
2
  import { v4 as uuidv4 } from 'uuid';
3
3
  import { BufferAndSlot } from './types';
4
4
  import { promiseTimeout } from '../util/promiseTimeout';
5
+ import { Connection } from '../bankrun/bankrunConnection';
5
6
 
6
- type AccountToLoad = {
7
+ export type AccountToLoad = {
7
8
  publicKey: PublicKey;
8
9
  callbacks: Map<string, (buffer: Buffer, slot: number) => void>;
9
10
  };
@@ -288,14 +288,20 @@ export class PollingDriftClientAccountSubscriber
288
288
  public async fetch(): Promise<void> {
289
289
  await this.accountLoader.load();
290
290
  for (const [_, accountToPoll] of this.accountsToPoll) {
291
- const { buffer, slot } = this.accountLoader.getBufferAndSlot(
291
+ const bufferAndSlot = this.accountLoader.getBufferAndSlot(
292
292
  accountToPoll.publicKey
293
293
  );
294
+
295
+ if (!bufferAndSlot) {
296
+ continue;
297
+ }
298
+
299
+ const { buffer, slot } = bufferAndSlot;
300
+
294
301
  if (buffer) {
295
302
  const account = this.program.account[
296
303
  accountToPoll.key
297
304
  ].coder.accounts.decodeUnchecked(capitalize(accountToPoll.key), buffer);
298
-
299
305
  if (accountToPoll.mapKey != undefined) {
300
306
  this[accountToPoll.key].set(accountToPoll.mapKey, {
301
307
  data: account,
@@ -311,9 +317,16 @@ export class PollingDriftClientAccountSubscriber
311
317
  }
312
318
 
313
319
  for (const [_, oracleToPoll] of this.oraclesToPoll) {
314
- const { buffer, slot } = this.accountLoader.getBufferAndSlot(
320
+ const bufferAndSlot = this.accountLoader.getBufferAndSlot(
315
321
  oracleToPoll.publicKey
316
322
  );
323
+
324
+ if (!bufferAndSlot) {
325
+ continue;
326
+ }
327
+
328
+ const { buffer, slot } = bufferAndSlot;
329
+
317
330
  if (buffer) {
318
331
  const oracleClient = this.oracleClientCache.get(
319
332
  oracleToPoll.source,
@@ -4,7 +4,7 @@ import {
4
4
  UserAccountEvents,
5
5
  UserAccountSubscriber,
6
6
  } from './types';
7
- import { Program } from '@coral-xyz/anchor';
7
+ import { Connection } from '../bankrun/bankrunConnection';
8
8
  import StrictEventEmitter from 'strict-event-emitter-types';
9
9
  import { EventEmitter } from 'events';
10
10
  import { PublicKey } from '@solana/web3.js';
@@ -13,7 +13,7 @@ import { BulkAccountLoader } from './bulkAccountLoader';
13
13
 
14
14
  export class PollingUserAccountSubscriber implements UserAccountSubscriber {
15
15
  isSubscribed: boolean;
16
- program: Program;
16
+ connection: Connection;
17
17
  eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
18
18
  userAccountPublicKey: PublicKey;
19
19
 
@@ -21,18 +21,22 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
21
21
  callbackId?: string;
22
22
  errorCallbackId?: string;
23
23
 
24
+ decode: (name, buffer) => UserAccount;
25
+
24
26
  user?: DataAndSlot<UserAccount>;
25
27
 
26
28
  public constructor(
27
- program: Program,
29
+ connection: Connection,
28
30
  userAccountPublicKey: PublicKey,
29
- accountLoader: BulkAccountLoader
31
+ accountLoader: BulkAccountLoader,
32
+ decode: (name, buffer) => UserAccount
30
33
  ) {
31
34
  this.isSubscribed = false;
32
- this.program = program;
35
+ this.connection = connection;
33
36
  this.accountLoader = accountLoader;
34
37
  this.eventEmitter = new EventEmitter();
35
38
  this.userAccountPublicKey = userAccountPublicKey;
39
+ this.decode = decode;
36
40
  }
37
41
 
38
42
  async subscribe(userAccount?: UserAccount): Promise<boolean> {
@@ -71,10 +75,7 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
71
75
  return;
72
76
  }
73
77
 
74
- const account = this.program.account.user.coder.accounts.decode(
75
- 'User',
76
- buffer
77
- );
78
+ const account = this.decode('User', buffer);
78
79
  this.user = { data: account, slot };
79
80
  this.eventEmitter.emit('userAccountUpdate', account);
80
81
  this.eventEmitter.emit('update');
@@ -94,19 +95,19 @@ export class PollingUserAccountSubscriber implements UserAccountSubscriber {
94
95
 
95
96
  async fetch(): Promise<void> {
96
97
  try {
97
- const dataAndContext = await this.program.account.user.fetchAndContext(
98
+ const dataAndContext = await this.connection.getAccountInfoAndContext(
98
99
  this.userAccountPublicKey,
99
100
  this.accountLoader.commitment
100
101
  );
101
102
  if (dataAndContext.context.slot > (this.user?.slot ?? 0)) {
102
103
  this.user = {
103
- data: dataAndContext.data as UserAccount,
104
+ data: this.decode('User', dataAndContext.value.data),
104
105
  slot: dataAndContext.context.slot,
105
106
  };
106
107
  }
107
108
  } catch (e) {
108
109
  console.log(
109
- `PollingUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}`
110
+ `PollingUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}-${e.stack}`
110
111
  );
111
112
  }
112
113
  }
@@ -0,0 +1,53 @@
1
+ import { AccountToLoad, BulkAccountLoader } from './bulkAccountLoader';
2
+
3
+ export class TestBulkAccountLoader extends BulkAccountLoader {
4
+ async loadChunk(accountsToLoadChunks: AccountToLoad[][]): Promise<void> {
5
+ if (accountsToLoadChunks.length === 0) {
6
+ return;
7
+ }
8
+
9
+ const accounts = [];
10
+ for (const accountsToLoadChunk of accountsToLoadChunks) {
11
+ for (const accountToLoad of accountsToLoadChunk) {
12
+ const account = await this.connection.getAccountInfoAndContext(
13
+ accountToLoad.publicKey,
14
+ this.commitment
15
+ );
16
+ accounts.push(account);
17
+ const newSlot = account.context.slot;
18
+ if (newSlot > this.mostRecentSlot) {
19
+ this.mostRecentSlot = newSlot;
20
+ }
21
+
22
+ if (accountToLoad.callbacks.size === 0) {
23
+ return;
24
+ }
25
+
26
+ const key = accountToLoad.publicKey.toBase58();
27
+ const prev = this.bufferAndSlotMap.get(key);
28
+
29
+ if (prev && newSlot < prev.slot) {
30
+ return;
31
+ }
32
+
33
+ let newBuffer: Buffer | undefined = undefined;
34
+
35
+ if (account.value) {
36
+ newBuffer = account.value.data;
37
+ }
38
+
39
+ if (!prev) {
40
+ this.bufferAndSlotMap.set(key, { slot: newSlot, buffer: newBuffer });
41
+ this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
42
+ return;
43
+ }
44
+
45
+ const oldBuffer = prev.buffer;
46
+ if (newBuffer && (!oldBuffer || !newBuffer.equals(oldBuffer))) {
47
+ this.bufferAndSlotMap.set(key, { slot: newSlot, buffer: newBuffer });
48
+ this.handleAccountCallbacks(accountToLoad, newBuffer, newSlot);
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }