@drift-labs/sdk 2.91.0-beta.1 → 2.91.0-beta.2

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.91.0-beta.1
1
+ 2.91.0-beta.2
@@ -3,6 +3,7 @@ import { ConfirmationStrategy, TxSender, TxSigAndSlot } from './types';
3
3
  import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature, Connection, VersionedTransaction, TransactionInstruction, AddressLookupTableAccount, BlockhashWithExpiryBlockHeight } from '@solana/web3.js';
4
4
  import { TxHandler } from './txHandler';
5
5
  import { IWallet } from '../types';
6
+ import NodeCache from 'node-cache';
6
7
  export declare abstract class BaseTxSender implements TxSender {
7
8
  connection: Connection;
8
9
  wallet: IWallet;
@@ -13,7 +14,13 @@ export declare abstract class BaseTxSender implements TxSender {
13
14
  confirmationStrategy: ConfirmationStrategy;
14
15
  additionalTxSenderCallbacks: ((base58EncodedTx: string) => void)[];
15
16
  txHandler: TxHandler;
16
- constructor({ connection, wallet, opts, timeout, additionalConnections, confirmationStrategy, additionalTxSenderCallbacks, txHandler, }: {
17
+ trackTxLandRate?: boolean;
18
+ lookbackWindowMinutes: number;
19
+ txSigCache?: NodeCache;
20
+ txLandRate: number;
21
+ lastPriorityFeeSuggestion: number;
22
+ landRateToFeeFunc: (landRate: number) => number;
23
+ constructor({ connection, wallet, opts, timeout, additionalConnections, confirmationStrategy, additionalTxSenderCallbacks, trackTxLandRate, txHandler, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
17
24
  connection: Connection;
18
25
  wallet: IWallet;
19
26
  opts?: ConfirmOptions;
@@ -22,6 +29,9 @@ export declare abstract class BaseTxSender implements TxSender {
22
29
  confirmationStrategy?: ConfirmationStrategy;
23
30
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
24
31
  txHandler?: TxHandler;
32
+ trackTxLandRate?: boolean;
33
+ txLandRateLookbackWindowMinutes?: number;
34
+ landRateToFeeFunc?: (landRate: number) => number;
25
35
  });
26
36
  send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
27
37
  prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions, preSigned?: boolean): Promise<Transaction>;
@@ -39,4 +49,7 @@ export declare abstract class BaseTxSender implements TxSender {
39
49
  getTimeoutCount(): number;
40
50
  checkConfirmationResultForError(txSig: string, result: RpcResponseAndContext<SignatureResult>): Promise<void>;
41
51
  reportTransactionError(txSig: string): Promise<any>;
52
+ getTxLandRate(): number;
53
+ private defaultLandRateToFeeFunc;
54
+ getSuggestedPriorityFeeMultiplier(): number;
42
55
  }
@@ -10,11 +10,17 @@ const anchor_1 = require("@coral-xyz/anchor");
10
10
  const assert_1 = __importDefault(require("assert"));
11
11
  const bs58_1 = __importDefault(require("bs58"));
12
12
  const txHandler_1 = require("./txHandler");
13
+ const node_cache_1 = __importDefault(require("node-cache"));
14
+ const BASELINE_TX_LAND_RATE = 0.9;
13
15
  const DEFAULT_TIMEOUT = 35000;
16
+ const DEFAULT_TX_LAND_RATE_LOOKBACK_WINDOW_MINUTES = 10;
14
17
  const NOT_CONFIRMED_ERROR_CODE = -1001;
15
18
  class BaseTxSender {
16
- constructor({ connection, wallet, opts = anchor_1.AnchorProvider.defaultOptions(), timeout = DEFAULT_TIMEOUT, additionalConnections = new Array(), confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks, txHandler, }) {
19
+ constructor({ connection, wallet, opts = anchor_1.AnchorProvider.defaultOptions(), timeout = DEFAULT_TIMEOUT, additionalConnections = new Array(), confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks, trackTxLandRate, txHandler, txLandRateLookbackWindowMinutes = DEFAULT_TX_LAND_RATE_LOOKBACK_WINDOW_MINUTES *
20
+ 60, landRateToFeeFunc, }) {
17
21
  this.timeoutCount = 0;
22
+ this.txLandRate = 0;
23
+ this.lastPriorityFeeSuggestion = 1;
18
24
  this.connection = connection;
19
25
  this.wallet = wallet;
20
26
  this.opts = opts;
@@ -28,6 +34,16 @@ class BaseTxSender {
28
34
  wallet: this.wallet,
29
35
  confirmationOptions: this.opts,
30
36
  });
37
+ this.trackTxLandRate = trackTxLandRate;
38
+ this.lookbackWindowMinutes = txLandRateLookbackWindowMinutes * 60;
39
+ if (this.trackTxLandRate) {
40
+ this.txSigCache = new node_cache_1.default({
41
+ stdTTL: this.lookbackWindowMinutes,
42
+ checkperiod: 120,
43
+ });
44
+ }
45
+ this.landRateToFeeFunc =
46
+ landRateToFeeFunc !== null && landRateToFeeFunc !== void 0 ? landRateToFeeFunc : this.defaultLandRateToFeeFunc.bind(this);
31
47
  }
32
48
  async send(tx, additionalSigners, opts, preSigned) {
33
49
  if (additionalSigners === undefined) {
@@ -246,5 +262,40 @@ class BaseTxSender {
246
262
  logs,
247
263
  });
248
264
  }
265
+ getTxLandRate() {
266
+ if (!this.trackTxLandRate) {
267
+ console.warn('trackTxLandRate is false, returning default land rate of 0');
268
+ return this.txLandRate;
269
+ }
270
+ const keys = this.txSigCache.keys();
271
+ const denominator = keys.length;
272
+ if (denominator === 0) {
273
+ return this.txLandRate;
274
+ }
275
+ let numerator = 0;
276
+ for (const key of keys) {
277
+ const value = this.txSigCache.get(key);
278
+ if (value) {
279
+ numerator += 1;
280
+ }
281
+ }
282
+ this.txLandRate = numerator / denominator;
283
+ return this.txLandRate;
284
+ }
285
+ defaultLandRateToFeeFunc(txLandRate) {
286
+ if (txLandRate >= BASELINE_TX_LAND_RATE ||
287
+ this.txSigCache.keys().length < 3) {
288
+ return 1;
289
+ }
290
+ const multiplier = 10 * Math.log10(1 + (BASELINE_TX_LAND_RATE - txLandRate) * 5);
291
+ return Math.min(multiplier, 10);
292
+ }
293
+ getSuggestedPriorityFeeMultiplier() {
294
+ if (!this.trackTxLandRate) {
295
+ console.warn('trackTxLandRate is false, returning default multiplier of 1');
296
+ return 1;
297
+ }
298
+ return this.landRateToFeeFunc(this.getTxLandRate());
299
+ }
249
300
  }
250
301
  exports.BaseTxSender = BaseTxSender;
@@ -15,9 +15,10 @@ export declare class FastSingleTxSender extends BaseTxSender {
15
15
  timoutCount: number;
16
16
  recentBlockhash: BlockhashWithExpiryBlockHeight;
17
17
  skipConfirmation: boolean;
18
+ confirmInBackground: boolean;
18
19
  blockhashCommitment: Commitment;
19
20
  blockhashIntervalId: NodeJS.Timer;
20
- constructor({ connection, wallet, opts, timeout, blockhashRefreshInterval, additionalConnections, skipConfirmation, blockhashCommitment, confirmationStrategy, txHandler, }: {
21
+ constructor({ connection, wallet, opts, timeout, blockhashRefreshInterval, additionalConnections, skipConfirmation, confirmInBackground, blockhashCommitment, confirmationStrategy, trackTxLandRate, txHandler, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
21
22
  connection: Connection;
22
23
  wallet: IWallet;
23
24
  opts?: ConfirmOptions;
@@ -25,9 +26,13 @@ export declare class FastSingleTxSender extends BaseTxSender {
25
26
  blockhashRefreshInterval?: number;
26
27
  additionalConnections?: any;
27
28
  skipConfirmation?: boolean;
29
+ confirmInBackground?: boolean;
28
30
  blockhashCommitment?: Commitment;
29
31
  confirmationStrategy?: ConfirmationStrategy;
32
+ trackTxLandRate?: boolean;
30
33
  txHandler?: TxHandler;
34
+ txLandRateLookbackWindowMinutes?: number;
35
+ landRateToFeeFunc?: (landRate: number) => number;
31
36
  });
32
37
  startBlockhashRefreshLoop(): void;
33
38
  sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
@@ -7,7 +7,7 @@ const baseTxSender_1 = require("./baseTxSender");
7
7
  const DEFAULT_TIMEOUT = 35000;
8
8
  const DEFAULT_BLOCKHASH_REFRESH = 10000;
9
9
  class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
10
- constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, timeout = DEFAULT_TIMEOUT, blockhashRefreshInterval = DEFAULT_BLOCKHASH_REFRESH, additionalConnections = new Array(), skipConfirmation = false, blockhashCommitment = 'finalized', confirmationStrategy = types_1.ConfirmationStrategy.Combo, txHandler, }) {
10
+ constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, timeout = DEFAULT_TIMEOUT, blockhashRefreshInterval = DEFAULT_BLOCKHASH_REFRESH, additionalConnections = new Array(), skipConfirmation = false, confirmInBackground = false, blockhashCommitment = 'finalized', confirmationStrategy = types_1.ConfirmationStrategy.Combo, trackTxLandRate, txHandler, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
11
11
  super({
12
12
  connection,
13
13
  wallet,
@@ -16,6 +16,9 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
16
16
  additionalConnections,
17
17
  confirmationStrategy,
18
18
  txHandler,
19
+ trackTxLandRate,
20
+ txLandRateLookbackWindowMinutes,
21
+ landRateToFeeFunc,
19
22
  });
20
23
  this.timoutCount = 0;
21
24
  this.connection = connection;
@@ -25,6 +28,7 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
25
28
  this.blockhashRefreshInterval = blockhashRefreshInterval;
26
29
  this.additionalConnections = additionalConnections;
27
30
  this.skipConfirmation = skipConfirmation;
31
+ this.confirmInBackground = confirmInBackground;
28
32
  this.blockhashCommitment = blockhashCommitment;
29
33
  this.startBlockhashRefreshLoop();
30
34
  }
@@ -41,9 +45,11 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
41
45
  }
42
46
  }
43
47
  async sendRawTransaction(rawTransaction, opts) {
48
+ var _a, _b;
44
49
  let txid;
45
50
  try {
46
51
  txid = await this.connection.sendRawTransaction(rawTransaction, opts);
52
+ (_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(txid, false);
47
53
  this.sendToAdditionalConnections(rawTransaction, opts);
48
54
  }
49
55
  catch (e) {
@@ -53,9 +59,20 @@ class FastSingleTxSender extends baseTxSender_1.BaseTxSender {
53
59
  let slot;
54
60
  if (!this.skipConfirmation) {
55
61
  try {
56
- const result = await this.confirmTransaction(txid, opts.commitment);
57
- await this.checkConfirmationResultForError(txid, result);
58
- slot = result.context.slot;
62
+ if (this.confirmInBackground) {
63
+ this.confirmTransaction(txid, opts.commitment).then(async (result) => {
64
+ var _a;
65
+ (_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(txid, true);
66
+ await this.checkConfirmationResultForError(txid, result);
67
+ slot = result.context.slot;
68
+ });
69
+ }
70
+ else {
71
+ const result = await this.confirmTransaction(txid, opts.commitment);
72
+ (_b = this.txSigCache) === null || _b === void 0 ? void 0 : _b.set(txid, true);
73
+ await this.checkConfirmationResultForError(txid, result);
74
+ slot = result.context.slot;
75
+ }
59
76
  }
60
77
  catch (e) {
61
78
  console.error(e);
@@ -15,7 +15,7 @@ export declare class ForwardOnlyTxSender extends BaseTxSender {
15
15
  retrySleep: number;
16
16
  additionalConnections: Connection[];
17
17
  timoutCount: number;
18
- constructor({ connection, wallet, opts, timeout, retrySleep, confirmationStrategy, additionalTxSenderCallbacks, txHandler, }: {
18
+ constructor({ connection, wallet, opts, timeout, retrySleep, confirmationStrategy, additionalTxSenderCallbacks, txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
19
19
  connection: Connection;
20
20
  wallet: IWallet;
21
21
  opts?: ConfirmOptions;
@@ -24,6 +24,9 @@ export declare class ForwardOnlyTxSender extends BaseTxSender {
24
24
  confirmationStrategy?: ConfirmationStrategy;
25
25
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
26
26
  txHandler?: TxHandler;
27
+ trackTxLandRate?: boolean;
28
+ txLandRateLookbackWindowMinutes?: number;
29
+ landRateToFeeFunc?: (landRate: number) => number;
27
30
  });
28
31
  sleep(reference: ResolveReference): Promise<void>;
29
32
  sendToAdditionalConnections(rawTx: Buffer | Uint8Array, _opts: ConfirmOptions): void;
@@ -12,7 +12,7 @@ const types_1 = require("./types");
12
12
  const DEFAULT_TIMEOUT = 35000;
13
13
  const DEFAULT_RETRY = 5000;
14
14
  class ForwardOnlyTxSender extends baseTxSender_1.BaseTxSender {
15
- constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, timeout = DEFAULT_TIMEOUT, retrySleep = DEFAULT_RETRY, confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks = [], txHandler, }) {
15
+ constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, timeout = DEFAULT_TIMEOUT, retrySleep = DEFAULT_RETRY, confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks = [], txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
16
16
  super({
17
17
  connection,
18
18
  wallet,
@@ -22,6 +22,9 @@ class ForwardOnlyTxSender extends baseTxSender_1.BaseTxSender {
22
22
  confirmationStrategy,
23
23
  additionalTxSenderCallbacks,
24
24
  txHandler,
25
+ trackTxLandRate,
26
+ txLandRateLookbackWindowMinutes,
27
+ landRateToFeeFunc,
25
28
  });
26
29
  this.timoutCount = 0;
27
30
  this.connection = connection;
@@ -44,11 +47,13 @@ class ForwardOnlyTxSender extends baseTxSender_1.BaseTxSender {
44
47
  });
45
48
  }
46
49
  async sendRawTransaction(rawTransaction, opts) {
50
+ var _a, _b;
47
51
  const deserializedTx = web3_js_1.VersionedTransaction.deserialize(rawTransaction);
48
52
  const txSig = deserializedTx.signatures[0];
49
53
  const encodedTxSig = bs58_1.default.encode(txSig);
50
54
  const startTime = this.getTimestamp();
51
55
  this.sendToAdditionalConnections(rawTransaction, opts);
56
+ (_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(encodedTxSig, false);
52
57
  let done = false;
53
58
  const resolveReference = {
54
59
  resolve: undefined,
@@ -71,6 +76,7 @@ class ForwardOnlyTxSender extends baseTxSender_1.BaseTxSender {
71
76
  try {
72
77
  const result = await this.confirmTransaction(encodedTxSig, opts.commitment);
73
78
  slot = result.context.slot;
79
+ (_b = this.txSigCache) === null || _b === void 0 ? void 0 : _b.set(encodedTxSig, true);
74
80
  // eslint-disable-next-line no-useless-catch
75
81
  }
76
82
  catch (e) {
@@ -15,7 +15,7 @@ export declare class RetryTxSender extends BaseTxSender {
15
15
  retrySleep: number;
16
16
  additionalConnections: Connection[];
17
17
  timoutCount: number;
18
- constructor({ connection, wallet, opts, timeout, retrySleep, additionalConnections, confirmationStrategy, additionalTxSenderCallbacks, txHandler, }: {
18
+ constructor({ connection, wallet, opts, timeout, retrySleep, additionalConnections, confirmationStrategy, additionalTxSenderCallbacks, txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
19
19
  connection: Connection;
20
20
  wallet: IWallet;
21
21
  opts?: ConfirmOptions;
@@ -25,6 +25,9 @@ export declare class RetryTxSender extends BaseTxSender {
25
25
  confirmationStrategy?: ConfirmationStrategy;
26
26
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
27
27
  txHandler?: TxHandler;
28
+ trackTxLandRate?: boolean;
29
+ txLandRateLookbackWindowMinutes?: number;
30
+ landRateToFeeFunc?: (landRate: number) => number;
28
31
  });
29
32
  sleep(reference: ResolveReference): Promise<void>;
30
33
  sendRawTransaction(rawTransaction: Buffer | Uint8Array, opts: ConfirmOptions): Promise<TxSigAndSlot>;
@@ -7,7 +7,7 @@ const baseTxSender_1 = require("./baseTxSender");
7
7
  const DEFAULT_TIMEOUT = 35000;
8
8
  const DEFAULT_RETRY = 2000;
9
9
  class RetryTxSender extends baseTxSender_1.BaseTxSender {
10
- constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, timeout = DEFAULT_TIMEOUT, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks = [], txHandler, }) {
10
+ constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, timeout = DEFAULT_TIMEOUT, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks = [], txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
11
11
  super({
12
12
  connection,
13
13
  wallet,
@@ -17,6 +17,9 @@ class RetryTxSender extends baseTxSender_1.BaseTxSender {
17
17
  confirmationStrategy,
18
18
  additionalTxSenderCallbacks,
19
19
  txHandler,
20
+ trackTxLandRate,
21
+ txLandRateLookbackWindowMinutes,
22
+ landRateToFeeFunc,
20
23
  });
21
24
  this.timoutCount = 0;
22
25
  this.connection = connection;
@@ -33,8 +36,10 @@ class RetryTxSender extends baseTxSender_1.BaseTxSender {
33
36
  });
34
37
  }
35
38
  async sendRawTransaction(rawTransaction, opts) {
39
+ var _a, _b;
36
40
  const startTime = this.getTimestamp();
37
41
  const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
42
+ (_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(txid, false);
38
43
  this.sendToAdditionalConnections(rawTransaction, opts);
39
44
  let done = false;
40
45
  const resolveReference = {
@@ -63,6 +68,7 @@ class RetryTxSender extends baseTxSender_1.BaseTxSender {
63
68
  let slot;
64
69
  try {
65
70
  const result = await this.confirmTransaction(txid, opts.commitment);
71
+ (_b = this.txSigCache) === null || _b === void 0 ? void 0 : _b.set(txid, true);
66
72
  await this.checkConfirmationResultForError(txid, result);
67
73
  slot = result.context.slot;
68
74
  // eslint-disable-next-line no-useless-catch
@@ -20,7 +20,7 @@ export declare class WhileValidTxSender extends BaseTxSender {
20
20
  lastValidBlockHeight: number;
21
21
  }>;
22
22
  blockhashCommitment: Commitment;
23
- constructor({ connection, wallet, opts, retrySleep, additionalConnections, additionalTxSenderCallbacks, blockhashCommitment, txHandler, }: {
23
+ constructor({ connection, wallet, opts, retrySleep, additionalConnections, additionalTxSenderCallbacks, blockhashCommitment, txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
24
24
  connection: Connection;
25
25
  wallet: IWallet;
26
26
  opts?: ConfirmOptions;
@@ -29,6 +29,9 @@ export declare class WhileValidTxSender extends BaseTxSender {
29
29
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
30
30
  blockhashCommitment?: Commitment;
31
31
  txHandler?: TxHandler;
32
+ trackTxLandRate?: boolean;
33
+ txLandRateLookbackWindowMinutes?: number;
34
+ landRateToFeeFunc?: (landRate: number) => number;
32
35
  });
33
36
  sleep(reference: ResolveReference): Promise<void>;
34
37
  prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions, preSigned?: boolean): Promise<Transaction>;
@@ -10,7 +10,7 @@ const bs58_1 = __importDefault(require("bs58"));
10
10
  const DEFAULT_RETRY = 2000;
11
11
  const VALID_BLOCK_HEIGHT_OFFSET = -150; // This is a bit of weirdness but the lastValidBlockHeight value returned from connection.getLatestBlockhash is always 300 blocks ahead of the current block, even though the transaction actually expires after 150 blocks. This accounts for that so that we can at least accuractely estimate the transaction expiry.
12
12
  class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
13
- constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), additionalTxSenderCallbacks = [], blockhashCommitment = 'finalized', txHandler, }) {
13
+ constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), additionalTxSenderCallbacks = [], blockhashCommitment = 'finalized', txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
14
14
  super({
15
15
  connection,
16
16
  wallet,
@@ -18,6 +18,9 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
18
18
  additionalConnections,
19
19
  additionalTxSenderCallbacks,
20
20
  txHandler,
21
+ trackTxLandRate,
22
+ txLandRateLookbackWindowMinutes,
23
+ landRateToFeeFunc,
21
24
  });
22
25
  this.timoutCount = 0;
23
26
  this.untilValid = new Map();
@@ -83,8 +86,10 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
83
86
  return this.sendRawTransaction(signedTx.serialize(), opts);
84
87
  }
85
88
  async sendRawTransaction(rawTransaction, opts) {
89
+ var _a, _b;
86
90
  const startTime = this.getTimestamp();
87
91
  const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
92
+ (_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(txid, false);
88
93
  this.sendToAdditionalConnections(rawTransaction, opts);
89
94
  let done = false;
90
95
  const resolveReference = {
@@ -118,6 +123,7 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
118
123
  lastValidBlockHeight: lastValidBlockHeight + VALID_BLOCK_HEIGHT_OFFSET,
119
124
  blockhash,
120
125
  }, opts.commitment);
126
+ (_b = this.txSigCache) === null || _b === void 0 ? void 0 : _b.set(txid, true);
121
127
  await this.checkConfirmationResultForError(txid, result);
122
128
  slot = result.context.slot;
123
129
  // eslint-disable-next-line no-useless-catch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.91.0-beta.1",
3
+ "version": "2.91.0-beta.2",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -46,6 +46,7 @@
46
46
  "@solana/web3.js": "1.92.3",
47
47
  "@switchboard-xyz/on-demand": "1.2.1",
48
48
  "anchor-bankrun": "^0.3.0",
49
+ "node-cache": "^5.1.2",
49
50
  "rpc-websockets": "7.5.1",
50
51
  "solana-bankrun": "^0.3.0",
51
52
  "strict-event-emitter-types": "^2.0.0",
@@ -25,8 +25,11 @@ import assert from 'assert';
25
25
  import bs58 from 'bs58';
26
26
  import { TxHandler } from './txHandler';
27
27
  import { IWallet } from '../types';
28
+ import NodeCache from 'node-cache';
28
29
 
30
+ const BASELINE_TX_LAND_RATE = 0.9;
29
31
  const DEFAULT_TIMEOUT = 35000;
32
+ const DEFAULT_TX_LAND_RATE_LOOKBACK_WINDOW_MINUTES = 10;
30
33
  const NOT_CONFIRMED_ERROR_CODE = -1001;
31
34
 
32
35
  export abstract class BaseTxSender implements TxSender {
@@ -39,6 +42,14 @@ export abstract class BaseTxSender implements TxSender {
39
42
  confirmationStrategy: ConfirmationStrategy;
40
43
  additionalTxSenderCallbacks: ((base58EncodedTx: string) => void)[];
41
44
  txHandler: TxHandler;
45
+ trackTxLandRate?: boolean;
46
+
47
+ // For landing rate calcs
48
+ lookbackWindowMinutes: number;
49
+ txSigCache?: NodeCache;
50
+ txLandRate = 0;
51
+ lastPriorityFeeSuggestion = 1;
52
+ landRateToFeeFunc: (landRate: number) => number;
42
53
 
43
54
  public constructor({
44
55
  connection,
@@ -48,7 +59,11 @@ export abstract class BaseTxSender implements TxSender {
48
59
  additionalConnections = new Array<Connection>(),
49
60
  confirmationStrategy = ConfirmationStrategy.Combo,
50
61
  additionalTxSenderCallbacks,
62
+ trackTxLandRate,
51
63
  txHandler,
64
+ txLandRateLookbackWindowMinutes = DEFAULT_TX_LAND_RATE_LOOKBACK_WINDOW_MINUTES *
65
+ 60,
66
+ landRateToFeeFunc,
52
67
  }: {
53
68
  connection: Connection;
54
69
  wallet: IWallet;
@@ -58,6 +73,9 @@ export abstract class BaseTxSender implements TxSender {
58
73
  confirmationStrategy?: ConfirmationStrategy;
59
74
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
60
75
  txHandler?: TxHandler;
76
+ trackTxLandRate?: boolean;
77
+ txLandRateLookbackWindowMinutes?: number;
78
+ landRateToFeeFunc?: (landRate: number) => number;
61
79
  }) {
62
80
  this.connection = connection;
63
81
  this.wallet = wallet;
@@ -73,6 +91,16 @@ export abstract class BaseTxSender implements TxSender {
73
91
  wallet: this.wallet,
74
92
  confirmationOptions: this.opts,
75
93
  });
94
+ this.trackTxLandRate = trackTxLandRate;
95
+ this.lookbackWindowMinutes = txLandRateLookbackWindowMinutes * 60;
96
+ if (this.trackTxLandRate) {
97
+ this.txSigCache = new NodeCache({
98
+ stdTTL: this.lookbackWindowMinutes,
99
+ checkperiod: 120,
100
+ });
101
+ }
102
+ this.landRateToFeeFunc =
103
+ landRateToFeeFunc ?? this.defaultLandRateToFeeFunc.bind(this);
76
104
  }
77
105
 
78
106
  async send(
@@ -404,4 +432,49 @@ export abstract class BaseTxSender implements TxSender {
404
432
  logs,
405
433
  });
406
434
  }
435
+
436
+ public getTxLandRate() {
437
+ if (!this.trackTxLandRate) {
438
+ console.warn(
439
+ 'trackTxLandRate is false, returning default land rate of 0'
440
+ );
441
+ return this.txLandRate;
442
+ }
443
+ const keys = this.txSigCache.keys();
444
+ const denominator = keys.length;
445
+ if (denominator === 0) {
446
+ return this.txLandRate;
447
+ }
448
+ let numerator = 0;
449
+ for (const key of keys) {
450
+ const value = this.txSigCache.get(key);
451
+ if (value) {
452
+ numerator += 1;
453
+ }
454
+ }
455
+ this.txLandRate = numerator / denominator;
456
+ return this.txLandRate;
457
+ }
458
+
459
+ private defaultLandRateToFeeFunc(txLandRate: number) {
460
+ if (
461
+ txLandRate >= BASELINE_TX_LAND_RATE ||
462
+ this.txSigCache.keys().length < 3
463
+ ) {
464
+ return 1;
465
+ }
466
+ const multiplier =
467
+ 10 * Math.log10(1 + (BASELINE_TX_LAND_RATE - txLandRate) * 5);
468
+ return Math.min(multiplier, 10);
469
+ }
470
+
471
+ public getSuggestedPriorityFeeMultiplier() {
472
+ if (!this.trackTxLandRate) {
473
+ console.warn(
474
+ 'trackTxLandRate is false, returning default multiplier of 1'
475
+ );
476
+ return 1;
477
+ }
478
+ return this.landRateToFeeFunc(this.getTxLandRate());
479
+ }
407
480
  }
@@ -24,6 +24,7 @@ export class FastSingleTxSender extends BaseTxSender {
24
24
  timoutCount = 0;
25
25
  recentBlockhash: BlockhashWithExpiryBlockHeight;
26
26
  skipConfirmation: boolean;
27
+ confirmInBackground: boolean;
27
28
  blockhashCommitment: Commitment;
28
29
  blockhashIntervalId: NodeJS.Timer;
29
30
 
@@ -35,9 +36,13 @@ export class FastSingleTxSender extends BaseTxSender {
35
36
  blockhashRefreshInterval = DEFAULT_BLOCKHASH_REFRESH,
36
37
  additionalConnections = new Array<Connection>(),
37
38
  skipConfirmation = false,
39
+ confirmInBackground = false,
38
40
  blockhashCommitment = 'finalized',
39
41
  confirmationStrategy = ConfirmationStrategy.Combo,
42
+ trackTxLandRate,
40
43
  txHandler,
44
+ txLandRateLookbackWindowMinutes,
45
+ landRateToFeeFunc,
41
46
  }: {
42
47
  connection: Connection;
43
48
  wallet: IWallet;
@@ -46,9 +51,13 @@ export class FastSingleTxSender extends BaseTxSender {
46
51
  blockhashRefreshInterval?: number;
47
52
  additionalConnections?;
48
53
  skipConfirmation?: boolean;
54
+ confirmInBackground?: boolean;
49
55
  blockhashCommitment?: Commitment;
50
56
  confirmationStrategy?: ConfirmationStrategy;
57
+ trackTxLandRate?: boolean;
51
58
  txHandler?: TxHandler;
59
+ txLandRateLookbackWindowMinutes?: number;
60
+ landRateToFeeFunc?: (landRate: number) => number;
52
61
  }) {
53
62
  super({
54
63
  connection,
@@ -58,6 +67,9 @@ export class FastSingleTxSender extends BaseTxSender {
58
67
  additionalConnections,
59
68
  confirmationStrategy,
60
69
  txHandler,
70
+ trackTxLandRate,
71
+ txLandRateLookbackWindowMinutes,
72
+ landRateToFeeFunc,
61
73
  });
62
74
  this.connection = connection;
63
75
  this.wallet = wallet;
@@ -66,6 +78,7 @@ export class FastSingleTxSender extends BaseTxSender {
66
78
  this.blockhashRefreshInterval = blockhashRefreshInterval;
67
79
  this.additionalConnections = additionalConnections;
68
80
  this.skipConfirmation = skipConfirmation;
81
+ this.confirmInBackground = confirmInBackground;
69
82
  this.blockhashCommitment = blockhashCommitment;
70
83
  this.startBlockhashRefreshLoop();
71
84
  }
@@ -91,6 +104,7 @@ export class FastSingleTxSender extends BaseTxSender {
91
104
  let txid: TransactionSignature;
92
105
  try {
93
106
  txid = await this.connection.sendRawTransaction(rawTransaction, opts);
107
+ this.txSigCache?.set(txid, false);
94
108
  this.sendToAdditionalConnections(rawTransaction, opts);
95
109
  } catch (e) {
96
110
  console.error(e);
@@ -100,9 +114,20 @@ export class FastSingleTxSender extends BaseTxSender {
100
114
  let slot: number;
101
115
  if (!this.skipConfirmation) {
102
116
  try {
103
- const result = await this.confirmTransaction(txid, opts.commitment);
104
- await this.checkConfirmationResultForError(txid, result);
105
- slot = result.context.slot;
117
+ if (this.confirmInBackground) {
118
+ this.confirmTransaction(txid, opts.commitment).then(
119
+ async (result) => {
120
+ this.txSigCache?.set(txid, true);
121
+ await this.checkConfirmationResultForError(txid, result);
122
+ slot = result.context.slot;
123
+ }
124
+ );
125
+ } else {
126
+ const result = await this.confirmTransaction(txid, opts.commitment);
127
+ this.txSigCache?.set(txid, true);
128
+ await this.checkConfirmationResultForError(txid, result);
129
+ slot = result.context.slot;
130
+ }
106
131
  } catch (e) {
107
132
  console.error(e);
108
133
  throw e;
@@ -35,6 +35,9 @@ export class ForwardOnlyTxSender extends BaseTxSender {
35
35
  confirmationStrategy = ConfirmationStrategy.Combo,
36
36
  additionalTxSenderCallbacks = [],
37
37
  txHandler,
38
+ trackTxLandRate,
39
+ txLandRateLookbackWindowMinutes,
40
+ landRateToFeeFunc,
38
41
  }: {
39
42
  connection: Connection;
40
43
  wallet: IWallet;
@@ -44,6 +47,9 @@ export class ForwardOnlyTxSender extends BaseTxSender {
44
47
  confirmationStrategy?: ConfirmationStrategy;
45
48
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
46
49
  txHandler?: TxHandler;
50
+ trackTxLandRate?: boolean;
51
+ txLandRateLookbackWindowMinutes?: number;
52
+ landRateToFeeFunc?: (landRate: number) => number;
47
53
  }) {
48
54
  super({
49
55
  connection,
@@ -54,6 +60,9 @@ export class ForwardOnlyTxSender extends BaseTxSender {
54
60
  confirmationStrategy,
55
61
  additionalTxSenderCallbacks,
56
62
  txHandler,
63
+ trackTxLandRate,
64
+ txLandRateLookbackWindowMinutes,
65
+ landRateToFeeFunc,
57
66
  });
58
67
  this.connection = connection;
59
68
  this.wallet = wallet;
@@ -91,6 +100,7 @@ export class ForwardOnlyTxSender extends BaseTxSender {
91
100
  const startTime = this.getTimestamp();
92
101
 
93
102
  this.sendToAdditionalConnections(rawTransaction, opts);
103
+ this.txSigCache?.set(encodedTxSig, false);
94
104
 
95
105
  let done = false;
96
106
  const resolveReference: ResolveReference = {
@@ -119,6 +129,7 @@ export class ForwardOnlyTxSender extends BaseTxSender {
119
129
  opts.commitment
120
130
  );
121
131
  slot = result.context.slot;
132
+ this.txSigCache?.set(encodedTxSig, true);
122
133
  // eslint-disable-next-line no-useless-catch
123
134
  } catch (e) {
124
135
  throw e;
@@ -31,6 +31,9 @@ export class RetryTxSender extends BaseTxSender {
31
31
  confirmationStrategy = ConfirmationStrategy.Combo,
32
32
  additionalTxSenderCallbacks = [],
33
33
  txHandler,
34
+ trackTxLandRate,
35
+ txLandRateLookbackWindowMinutes,
36
+ landRateToFeeFunc,
34
37
  }: {
35
38
  connection: Connection;
36
39
  wallet: IWallet;
@@ -41,6 +44,9 @@ export class RetryTxSender extends BaseTxSender {
41
44
  confirmationStrategy?: ConfirmationStrategy;
42
45
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
43
46
  txHandler?: TxHandler;
47
+ trackTxLandRate?: boolean;
48
+ txLandRateLookbackWindowMinutes?: number;
49
+ landRateToFeeFunc?: (landRate: number) => number;
44
50
  }) {
45
51
  super({
46
52
  connection,
@@ -51,6 +57,9 @@ export class RetryTxSender extends BaseTxSender {
51
57
  confirmationStrategy,
52
58
  additionalTxSenderCallbacks,
53
59
  txHandler,
60
+ trackTxLandRate,
61
+ txLandRateLookbackWindowMinutes,
62
+ landRateToFeeFunc,
54
63
  });
55
64
  this.connection = connection;
56
65
  this.wallet = wallet;
@@ -74,6 +83,7 @@ export class RetryTxSender extends BaseTxSender {
74
83
  const startTime = this.getTimestamp();
75
84
 
76
85
  const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
86
+ this.txSigCache?.set(txid, false);
77
87
  this.sendToAdditionalConnections(rawTransaction, opts);
78
88
 
79
89
  let done = false;
@@ -105,6 +115,7 @@ export class RetryTxSender extends BaseTxSender {
105
115
  let slot: number;
106
116
  try {
107
117
  const result = await this.confirmTransaction(txid, opts.commitment);
118
+ this.txSigCache?.set(txid, true);
108
119
 
109
120
  await this.checkConfirmationResultForError(txid, result);
110
121
 
@@ -44,6 +44,9 @@ export class WhileValidTxSender extends BaseTxSender {
44
44
  additionalTxSenderCallbacks = [],
45
45
  blockhashCommitment = 'finalized',
46
46
  txHandler,
47
+ trackTxLandRate,
48
+ txLandRateLookbackWindowMinutes,
49
+ landRateToFeeFunc,
47
50
  }: {
48
51
  connection: Connection;
49
52
  wallet: IWallet;
@@ -53,6 +56,9 @@ export class WhileValidTxSender extends BaseTxSender {
53
56
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
54
57
  blockhashCommitment?: Commitment;
55
58
  txHandler?: TxHandler;
59
+ trackTxLandRate?: boolean;
60
+ txLandRateLookbackWindowMinutes?: number;
61
+ landRateToFeeFunc?: (landRate: number) => number;
56
62
  }) {
57
63
  super({
58
64
  connection,
@@ -61,6 +67,9 @@ export class WhileValidTxSender extends BaseTxSender {
61
67
  additionalConnections,
62
68
  additionalTxSenderCallbacks,
63
69
  txHandler,
70
+ trackTxLandRate,
71
+ txLandRateLookbackWindowMinutes,
72
+ landRateToFeeFunc,
64
73
  });
65
74
  this.retrySleep = retrySleep;
66
75
  this.blockhashCommitment = blockhashCommitment;
@@ -168,6 +177,7 @@ export class WhileValidTxSender extends BaseTxSender {
168
177
  const startTime = this.getTimestamp();
169
178
 
170
179
  const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
180
+ this.txSigCache?.set(txid, false);
171
181
  this.sendToAdditionalConnections(rawTransaction, opts);
172
182
 
173
183
  let done = false;
@@ -208,7 +218,7 @@ export class WhileValidTxSender extends BaseTxSender {
208
218
  },
209
219
  opts.commitment
210
220
  );
211
-
221
+ this.txSigCache?.set(txid, true);
212
222
  await this.checkConfirmationResultForError(txid, result);
213
223
 
214
224
  slot = result.context.slot;