@drift-labs/sdk 2.74.0-beta.2 → 2.74.0-beta.4

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.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.74.0-beta.2
1
+ 2.74.0-beta.4
@@ -0,0 +1,21 @@
1
+ import { BlockhashWithExpiryBlockHeight, Context } from '@solana/web3.js';
2
+ import { BlockhashSubscriberConfig } from './types';
3
+ export declare class BlockhashSubscriber {
4
+ private connection;
5
+ private isSubscribed;
6
+ private latestBlockHeight;
7
+ private latestBlockHeightContext;
8
+ private blockhashes;
9
+ private updateBlockhashIntervalId;
10
+ private commitment;
11
+ private updateIntervalMs;
12
+ constructor(config: BlockhashSubscriberConfig);
13
+ getBlockhashCacheSize(): number;
14
+ getLatestBlockHeight(): number;
15
+ getLatestBlockHeightContext(): Context | undefined;
16
+ getLatestBlockhash(offset?: number): BlockhashWithExpiryBlockHeight | undefined;
17
+ pruneBlockhashes(): void;
18
+ updateBlockhash(): Promise<void>;
19
+ subscribe(): Promise<void>;
20
+ unsubscribe(): void;
21
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BlockhashSubscriber = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ class BlockhashSubscriber {
6
+ constructor(config) {
7
+ var _a, _b;
8
+ this.isSubscribed = false;
9
+ this.blockhashes = [];
10
+ if (!config.connection && !config.rpcUrl) {
11
+ throw new Error('BlockhashSubscriber requires one of connection or rpcUrl must be provided');
12
+ }
13
+ this.connection = config.connection || new web3_js_1.Connection(config.rpcUrl);
14
+ this.commitment = (_a = config.commitment) !== null && _a !== void 0 ? _a : 'confirmed';
15
+ this.updateIntervalMs = (_b = config.updateIntervalMs) !== null && _b !== void 0 ? _b : 1000;
16
+ }
17
+ getBlockhashCacheSize() {
18
+ return this.blockhashes.length;
19
+ }
20
+ getLatestBlockHeight() {
21
+ return this.latestBlockHeight;
22
+ }
23
+ getLatestBlockHeightContext() {
24
+ return this.latestBlockHeightContext;
25
+ }
26
+ getLatestBlockhash(offset) {
27
+ if (this.blockhashes.length === 0) {
28
+ return undefined;
29
+ }
30
+ const clampedOffset = Math.max(0, Math.min(this.blockhashes.length - 1, offset !== null && offset !== void 0 ? offset : 0));
31
+ return this.blockhashes[this.blockhashes.length - 1 - clampedOffset];
32
+ }
33
+ pruneBlockhashes() {
34
+ if (this.latestBlockHeight) {
35
+ this.blockhashes = this.blockhashes.filter((blockhash) => blockhash.lastValidBlockHeight > this.latestBlockHeight);
36
+ }
37
+ }
38
+ async updateBlockhash() {
39
+ const [resp, lastConfirmedBlockHeight] = await Promise.all([
40
+ this.connection.getLatestBlockhashAndContext({
41
+ commitment: this.commitment,
42
+ }),
43
+ this.connection.getBlockHeight({ commitment: this.commitment }),
44
+ ]);
45
+ this.latestBlockHeight = lastConfirmedBlockHeight;
46
+ this.latestBlockHeightContext = resp.context;
47
+ // avoid caching duplicate blockhashes
48
+ if (this.blockhashes.length > 0) {
49
+ if (resp.value.blockhash ===
50
+ this.blockhashes[this.blockhashes.length - 1].blockhash) {
51
+ return;
52
+ }
53
+ }
54
+ this.blockhashes.push(resp.value);
55
+ this.pruneBlockhashes();
56
+ }
57
+ async subscribe() {
58
+ if (this.isSubscribed) {
59
+ return;
60
+ }
61
+ this.isSubscribed = true;
62
+ await this.updateBlockhash();
63
+ this.updateBlockhashIntervalId = setInterval(this.updateBlockhash.bind(this), this.updateIntervalMs);
64
+ }
65
+ unsubscribe() {
66
+ if (this.updateBlockhashIntervalId) {
67
+ clearInterval(this.updateBlockhashIntervalId);
68
+ this.updateBlockhashIntervalId = undefined;
69
+ }
70
+ this.isSubscribed = false;
71
+ }
72
+ }
73
+ exports.BlockhashSubscriber = BlockhashSubscriber;
@@ -0,0 +1 @@
1
+ export * from './BlockhashSubscriber';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./BlockhashSubscriber"), exports);
@@ -0,0 +1,7 @@
1
+ import { Commitment, Connection } from '@solana/web3.js';
2
+ export type BlockhashSubscriberConfig = {
3
+ rpcUrl?: string;
4
+ connection?: Connection;
5
+ commitment?: Commitment;
6
+ updateIntervalMs?: number;
7
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/lib/index.d.ts CHANGED
@@ -98,4 +98,5 @@ export * from './auctionSubscriber';
98
98
  export * from './auctionSubscriber/types';
99
99
  export * from './memcmp';
100
100
  export * from './decode/user';
101
+ export * from './blockhashSubscriber';
101
102
  export { BN, PublicKey, pyth };
package/lib/index.js CHANGED
@@ -121,3 +121,4 @@ __exportStar(require("./auctionSubscriber"), exports);
121
121
  __exportStar(require("./auctionSubscriber/types"), exports);
122
122
  __exportStar(require("./memcmp"), exports);
123
123
  __exportStar(require("./decode/user"), exports);
124
+ __exportStar(require("./blockhashSubscriber"), exports);
@@ -22,7 +22,7 @@ export declare abstract class BaseTxSender implements TxSender {
22
22
  });
23
23
  send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean, extraConfirmationOptions?: ExtraConfirmationOptions): Promise<TxSigAndSlot>;
24
24
  prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions): Promise<Transaction>;
25
- getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
25
+ getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions, blockhash?: string): Promise<VersionedTransaction>;
26
26
  sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean, extraConfirmationOptions?: ExtraConfirmationOptions): Promise<TxSigAndSlot>;
27
27
  sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
28
28
  simulateTransaction(tx: VersionedTransaction): Promise<boolean>;
@@ -47,16 +47,23 @@ class BaseTxSender {
47
47
  const signedTx = await this.wallet.signTransaction(tx);
48
48
  return signedTx;
49
49
  }
50
- async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts) {
50
+ async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts, blockhash) {
51
51
  if (additionalSigners === undefined) {
52
52
  additionalSigners = [];
53
53
  }
54
54
  if (opts === undefined) {
55
55
  opts = this.opts;
56
56
  }
57
+ let recentBlockhash = '';
58
+ if (blockhash) {
59
+ recentBlockhash = blockhash;
60
+ }
61
+ else {
62
+ recentBlockhash = (await this.connection.getLatestBlockhash(opts.preflightCommitment)).blockhash;
63
+ }
57
64
  const message = new web3_js_1.TransactionMessage({
58
65
  payerKey: this.wallet.publicKey,
59
- recentBlockhash: (await this.connection.getLatestBlockhash(opts.preflightCommitment)).blockhash,
66
+ recentBlockhash,
60
67
  instructions: ixs,
61
68
  }).compileToV0Message(lookupTableAccounts);
62
69
  const tx = new web3_js_1.VersionedTransaction(message);
@@ -27,6 +27,6 @@ export declare class FastSingleTxSender extends BaseTxSender {
27
27
  });
28
28
  startBlockhashRefreshLoop(): void;
29
29
  prepareTx(tx: Transaction, additionalSigners: Array<Signer>, _opts: ConfirmOptions): Promise<Transaction>;
30
- getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
30
+ getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions, blockhash?: string): Promise<VersionedTransaction>;
31
31
  sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
32
32
  }
@@ -52,7 +52,7 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
52
52
  const signedTx = await this.wallet.signTransaction(tx);
53
53
  return signedTx;
54
54
  }
55
- async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts) {
55
+ async getVersionedTransaction(ixs, lookupTableAccounts, additionalSigners, opts, blockhash) {
56
56
  var _a;
57
57
  if (additionalSigners === undefined) {
58
58
  additionalSigners = [];
@@ -60,10 +60,18 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
60
60
  if (opts === undefined) {
61
61
  opts = this.opts;
62
62
  }
63
+ let recentBlockhash = '';
64
+ if (blockhash) {
65
+ recentBlockhash = blockhash;
66
+ }
67
+ else {
68
+ recentBlockhash =
69
+ (_a = this.recentBlockhash) !== null && _a !== void 0 ? _a : (await this.connection.getLatestBlockhash(opts.preflightCommitment))
70
+ .blockhash;
71
+ }
63
72
  const message = new web3_js_1.TransactionMessage({
64
73
  payerKey: this.wallet.publicKey,
65
- recentBlockhash: (_a = this.recentBlockhash) !== null && _a !== void 0 ? _a : (await this.connection.getLatestBlockhash(opts.preflightCommitment))
66
- .blockhash,
74
+ recentBlockhash,
67
75
  instructions: ixs,
68
76
  }).compileToV0Message(lookupTableAccounts);
69
77
  const tx = new web3_js_1.VersionedTransaction(message);
package/lib/tx/types.d.ts CHANGED
@@ -17,7 +17,7 @@ export interface TxSender {
17
17
  wallet: IWallet;
18
18
  send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean, extraConfirmationOptions?: ExtraConfirmationOptions): Promise<TxSigAndSlot>;
19
19
  sendVersionedTransaction(tx: VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean, extraConfirmationOptions?: ExtraConfirmationOptions): Promise<TxSigAndSlot>;
20
- getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<VersionedTransaction>;
20
+ getVersionedTransaction(ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], additionalSigners?: Array<Signer>, opts?: ConfirmOptions, blockhash?: string): Promise<VersionedTransaction>;
21
21
  sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
22
22
  simulateTransaction(tx: VersionedTransaction): Promise<boolean>;
23
23
  getTimeoutCount(): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.74.0-beta.2",
3
+ "version": "2.74.0-beta.4",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -0,0 +1,108 @@
1
+ import {
2
+ BlockhashWithExpiryBlockHeight,
3
+ Commitment,
4
+ Connection,
5
+ Context,
6
+ } from '@solana/web3.js';
7
+ import { BlockhashSubscriberConfig } from './types';
8
+
9
+ export class BlockhashSubscriber {
10
+ private connection: Connection;
11
+ private isSubscribed = false;
12
+ private latestBlockHeight: number;
13
+ private latestBlockHeightContext: Context | undefined;
14
+ private blockhashes: Array<BlockhashWithExpiryBlockHeight> = [];
15
+ private updateBlockhashIntervalId: NodeJS.Timeout | undefined;
16
+ private commitment: Commitment;
17
+ private updateIntervalMs: number;
18
+
19
+ constructor(config: BlockhashSubscriberConfig) {
20
+ if (!config.connection && !config.rpcUrl) {
21
+ throw new Error(
22
+ 'BlockhashSubscriber requires one of connection or rpcUrl must be provided'
23
+ );
24
+ }
25
+ this.connection = config.connection || new Connection(config.rpcUrl!);
26
+ this.commitment = config.commitment ?? 'confirmed';
27
+ this.updateIntervalMs = config.updateIntervalMs ?? 1000;
28
+ }
29
+
30
+ getBlockhashCacheSize(): number {
31
+ return this.blockhashes.length;
32
+ }
33
+
34
+ getLatestBlockHeight(): number {
35
+ return this.latestBlockHeight;
36
+ }
37
+
38
+ getLatestBlockHeightContext(): Context | undefined {
39
+ return this.latestBlockHeightContext;
40
+ }
41
+
42
+ getLatestBlockhash(
43
+ offset?: number
44
+ ): BlockhashWithExpiryBlockHeight | undefined {
45
+ if (this.blockhashes.length === 0) {
46
+ return undefined;
47
+ }
48
+ const clampedOffset = Math.max(
49
+ 0,
50
+ Math.min(this.blockhashes.length - 1, offset ?? 0)
51
+ );
52
+
53
+ return this.blockhashes[this.blockhashes.length - 1 - clampedOffset];
54
+ }
55
+
56
+ pruneBlockhashes() {
57
+ if (this.latestBlockHeight) {
58
+ this.blockhashes = this.blockhashes.filter(
59
+ (blockhash) => blockhash.lastValidBlockHeight > this.latestBlockHeight!
60
+ );
61
+ }
62
+ }
63
+
64
+ async updateBlockhash() {
65
+ const [resp, lastConfirmedBlockHeight] = await Promise.all([
66
+ this.connection.getLatestBlockhashAndContext({
67
+ commitment: this.commitment,
68
+ }),
69
+ this.connection.getBlockHeight({ commitment: this.commitment }),
70
+ ]);
71
+ this.latestBlockHeight = lastConfirmedBlockHeight;
72
+ this.latestBlockHeightContext = resp.context;
73
+
74
+ // avoid caching duplicate blockhashes
75
+ if (this.blockhashes.length > 0) {
76
+ if (
77
+ resp.value.blockhash ===
78
+ this.blockhashes[this.blockhashes.length - 1].blockhash
79
+ ) {
80
+ return;
81
+ }
82
+ }
83
+
84
+ this.blockhashes.push(resp.value);
85
+ this.pruneBlockhashes();
86
+ }
87
+
88
+ async subscribe() {
89
+ if (this.isSubscribed) {
90
+ return;
91
+ }
92
+ this.isSubscribed = true;
93
+
94
+ await this.updateBlockhash();
95
+ this.updateBlockhashIntervalId = setInterval(
96
+ this.updateBlockhash.bind(this),
97
+ this.updateIntervalMs
98
+ );
99
+ }
100
+
101
+ unsubscribe() {
102
+ if (this.updateBlockhashIntervalId) {
103
+ clearInterval(this.updateBlockhashIntervalId);
104
+ this.updateBlockhashIntervalId = undefined;
105
+ }
106
+ this.isSubscribed = false;
107
+ }
108
+ }
@@ -0,0 +1 @@
1
+ export * from './BlockhashSubscriber';
@@ -0,0 +1,8 @@
1
+ import { Commitment, Connection } from '@solana/web3.js';
2
+
3
+ export type BlockhashSubscriberConfig = {
4
+ rpcUrl?: string;
5
+ connection?: Connection;
6
+ commitment?: Commitment;
7
+ updateIntervalMs?: number;
8
+ };
package/src/index.ts CHANGED
@@ -99,5 +99,6 @@ export * from './auctionSubscriber';
99
99
  export * from './auctionSubscriber/types';
100
100
  export * from './memcmp';
101
101
  export * from './decode/user';
102
+ export * from './blockhashSubscriber';
102
103
 
103
104
  export { BN, PublicKey, pyth };
@@ -112,7 +112,8 @@ export abstract class BaseTxSender implements TxSender {
112
112
  ixs: TransactionInstruction[],
113
113
  lookupTableAccounts: AddressLookupTableAccount[],
114
114
  additionalSigners?: Array<Signer>,
115
- opts?: ConfirmOptions
115
+ opts?: ConfirmOptions,
116
+ blockhash?: string
116
117
  ): Promise<VersionedTransaction> {
117
118
  if (additionalSigners === undefined) {
118
119
  additionalSigners = [];
@@ -121,11 +122,18 @@ export abstract class BaseTxSender implements TxSender {
121
122
  opts = this.opts;
122
123
  }
123
124
 
125
+ let recentBlockhash = '';
126
+ if (blockhash) {
127
+ recentBlockhash = blockhash;
128
+ } else {
129
+ recentBlockhash = (
130
+ await this.connection.getLatestBlockhash(opts.preflightCommitment)
131
+ ).blockhash;
132
+ }
133
+
124
134
  const message = new TransactionMessage({
125
135
  payerKey: this.wallet.publicKey,
126
- recentBlockhash: (
127
- await this.connection.getLatestBlockhash(opts.preflightCommitment)
128
- ).blockhash,
136
+ recentBlockhash,
129
137
  instructions: ixs,
130
138
  }).compileToV0Message(lookupTableAccounts);
131
139
 
@@ -109,7 +109,8 @@ export class FastSingleTxSender extends BaseTxSender {
109
109
  ixs: TransactionInstruction[],
110
110
  lookupTableAccounts: AddressLookupTableAccount[],
111
111
  additionalSigners?: Array<Signer>,
112
- opts?: ConfirmOptions
112
+ opts?: ConfirmOptions,
113
+ blockhash?: string
113
114
  ): Promise<VersionedTransaction> {
114
115
  if (additionalSigners === undefined) {
115
116
  additionalSigners = [];
@@ -118,12 +119,19 @@ export class FastSingleTxSender extends BaseTxSender {
118
119
  opts = this.opts;
119
120
  }
120
121
 
121
- const message = new TransactionMessage({
122
- payerKey: this.wallet.publicKey,
123
- recentBlockhash:
122
+ let recentBlockhash = '';
123
+ if (blockhash) {
124
+ recentBlockhash = blockhash;
125
+ } else {
126
+ recentBlockhash =
124
127
  this.recentBlockhash ??
125
128
  (await this.connection.getLatestBlockhash(opts.preflightCommitment))
126
- .blockhash,
129
+ .blockhash;
130
+ }
131
+
132
+ const message = new TransactionMessage({
133
+ payerKey: this.wallet.publicKey,
134
+ recentBlockhash,
127
135
  instructions: ixs,
128
136
  }).compileToV0Message(lookupTableAccounts);
129
137
 
package/src/tx/types.ts CHANGED
@@ -47,7 +47,8 @@ export interface TxSender {
47
47
  ixs: TransactionInstruction[],
48
48
  lookupTableAccounts: AddressLookupTableAccount[],
49
49
  additionalSigners?: Array<Signer>,
50
- opts?: ConfirmOptions
50
+ opts?: ConfirmOptions,
51
+ blockhash?: string
51
52
  ): Promise<VersionedTransaction>;
52
53
 
53
54
  sendRawTransaction(
package/tests/amm/test.ts CHANGED
@@ -1193,7 +1193,9 @@ describe('AMM Tests', () => {
1193
1193
  };
1194
1194
 
1195
1195
  // good oracle
1196
- assert(isOracleValid(mockMarket1, oraclePriceData, oracleGuardRails, slot + 5));
1196
+ assert(
1197
+ isOracleValid(mockMarket1, oraclePriceData, oracleGuardRails, slot + 5)
1198
+ );
1197
1199
 
1198
1200
  // conf too high
1199
1201
  assert(