@drift-labs/sdk 2.96.0-beta.9 → 2.97.0-beta.1

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 (69) hide show
  1. package/README.md +3 -0
  2. package/VERSION +1 -1
  3. package/bun.lockb +0 -0
  4. package/lib/accounts/pollingDriftClientAccountSubscriber.d.ts +5 -3
  5. package/lib/accounts/pollingDriftClientAccountSubscriber.js +24 -1
  6. package/lib/accounts/types.d.ts +5 -0
  7. package/lib/accounts/types.js +7 -1
  8. package/lib/accounts/utils.d.ts +7 -0
  9. package/lib/accounts/utils.js +33 -1
  10. package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +5 -4
  11. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +24 -1
  12. package/lib/config.d.ts +6 -1
  13. package/lib/config.js +10 -1
  14. package/lib/constants/perpMarkets.js +33 -1
  15. package/lib/constants/spotMarkets.js +10 -0
  16. package/lib/constants/txConstants.d.ts +1 -0
  17. package/lib/constants/txConstants.js +4 -0
  18. package/lib/driftClient.d.ts +36 -8
  19. package/lib/driftClient.js +166 -43
  20. package/lib/driftClientConfig.d.ts +3 -0
  21. package/lib/events/types.js +1 -5
  22. package/lib/idl/drift.json +169 -1
  23. package/lib/index.d.ts +1 -0
  24. package/lib/index.js +1 -0
  25. package/lib/orderParams.js +8 -8
  26. package/lib/orderSubscriber/OrderSubscriber.js +1 -6
  27. package/lib/tokenFaucet.js +2 -1
  28. package/lib/tx/baseTxSender.d.ts +0 -1
  29. package/lib/tx/baseTxSender.js +8 -26
  30. package/lib/tx/fastSingleTxSender.js +2 -2
  31. package/lib/tx/forwardOnlyTxSender.js +2 -2
  32. package/lib/tx/reportTransactionError.d.ts +20 -0
  33. package/lib/tx/reportTransactionError.js +103 -0
  34. package/lib/tx/retryTxSender.js +2 -2
  35. package/lib/tx/txHandler.js +10 -7
  36. package/lib/tx/whileValidTxSender.d.ts +4 -5
  37. package/lib/tx/whileValidTxSender.js +16 -17
  38. package/lib/types.d.ts +22 -1
  39. package/lib/types.js +6 -1
  40. package/lib/util/TransactionConfirmationManager.d.ts +16 -0
  41. package/lib/util/TransactionConfirmationManager.js +174 -0
  42. package/package.json +4 -3
  43. package/src/accounts/pollingDriftClientAccountSubscriber.ts +41 -5
  44. package/src/accounts/types.ts +6 -0
  45. package/src/accounts/utils.ts +42 -0
  46. package/src/accounts/webSocketDriftClientAccountSubscriber.ts +40 -5
  47. package/src/config.ts +17 -1
  48. package/src/constants/perpMarkets.ts +35 -1
  49. package/src/constants/spotMarkets.ts +11 -0
  50. package/src/constants/txConstants.ts +1 -0
  51. package/src/driftClient.ts +346 -53
  52. package/src/driftClientConfig.ts +3 -0
  53. package/src/events/types.ts +1 -5
  54. package/src/idl/drift.json +169 -1
  55. package/src/index.ts +1 -0
  56. package/src/orderParams.ts +20 -12
  57. package/src/orderSubscriber/OrderSubscriber.ts +2 -5
  58. package/src/tokenFaucet.ts +2 -2
  59. package/src/tx/baseTxSender.ts +10 -32
  60. package/src/tx/fastSingleTxSender.ts +2 -2
  61. package/src/tx/forwardOnlyTxSender.ts +2 -2
  62. package/src/tx/reportTransactionError.ts +159 -0
  63. package/src/tx/retryTxSender.ts +2 -2
  64. package/src/tx/txHandler.ts +8 -2
  65. package/src/tx/whileValidTxSender.ts +18 -27
  66. package/src/types.ts +31 -1
  67. package/src/util/TransactionConfirmationManager.ts +292 -0
  68. package/tests/ci/verifyConstants.ts +13 -0
  69. package/tests/tx/TransactionConfirmationManager.test.ts +305 -0
@@ -3,27 +3,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getOrderParams = exports.getMarketOrderParams = exports.getTriggerLimitOrderParams = exports.getTriggerMarketOrderParams = exports.getLimitOrderParams = void 0;
4
4
  const types_1 = require("./types");
5
5
  function getLimitOrderParams(params) {
6
- return Object.assign({}, params, {
6
+ return getOrderParams(Object.assign({}, params, {
7
7
  orderType: types_1.OrderType.LIMIT,
8
- });
8
+ }));
9
9
  }
10
10
  exports.getLimitOrderParams = getLimitOrderParams;
11
11
  function getTriggerMarketOrderParams(params) {
12
- return Object.assign({}, params, {
12
+ return getOrderParams(Object.assign({}, params, {
13
13
  orderType: types_1.OrderType.TRIGGER_MARKET,
14
- });
14
+ }));
15
15
  }
16
16
  exports.getTriggerMarketOrderParams = getTriggerMarketOrderParams;
17
17
  function getTriggerLimitOrderParams(params) {
18
- return Object.assign({}, params, {
18
+ return getOrderParams(Object.assign({}, params, {
19
19
  orderType: types_1.OrderType.TRIGGER_LIMIT,
20
- });
20
+ }));
21
21
  }
22
22
  exports.getTriggerLimitOrderParams = getTriggerLimitOrderParams;
23
23
  function getMarketOrderParams(params) {
24
- return Object.assign({}, params, {
24
+ return getOrderParams(Object.assign({}, params, {
25
25
  orderType: types_1.OrderType.MARKET,
26
- });
26
+ }));
27
27
  }
28
28
  exports.getMarketOrderParams = getMarketOrderParams;
29
29
  /**
@@ -133,12 +133,7 @@ class OrderSubscriber {
133
133
  if (newOrders.length > 0) {
134
134
  this.eventEmitter.emit('orderCreated', userAccount, newOrders, new web3_js_1.PublicKey(key), slot, dataType);
135
135
  }
136
- if (userAccount.hasOpenOrder) {
137
- this.usersAccounts.set(key, { slot, userAccount });
138
- }
139
- else {
140
- this.usersAccounts.delete(key);
141
- }
136
+ this.usersAccounts.set(key, { slot, userAccount });
142
137
  }
143
138
  }
144
139
  /**
@@ -31,13 +31,14 @@ const anchor = __importStar(require("@coral-xyz/anchor"));
31
31
  const anchor_1 = require("@coral-xyz/anchor");
32
32
  const spl_token_1 = require("@solana/spl-token");
33
33
  const web3_js_1 = require("@solana/web3.js");
34
+ const _1 = require(".");
34
35
  const token_faucet_json_1 = __importDefault(require("./idl/token_faucet.json"));
35
36
  class TokenFaucet {
36
37
  constructor(connection, wallet, programId, mint, opts, context) {
37
38
  this.connection = connection;
38
39
  this.context = context;
39
40
  this.wallet = wallet;
40
- this.opts = opts || anchor_1.AnchorProvider.defaultOptions();
41
+ this.opts = opts || _1.DEFAULT_CONFIRMATION_OPTS;
41
42
  // @ts-ignore
42
43
  const provider = new anchor_1.AnchorProvider(context ? context.connection.toConnection() : this.connection,
43
44
  // @ts-ignore
@@ -48,7 +48,6 @@ export declare abstract class BaseTxSender implements TxSender {
48
48
  addAdditionalConnection(newConnection: Connection): void;
49
49
  getTimeoutCount(): number;
50
50
  checkConfirmationResultForError(txSig: string, result: SignatureResult): Promise<void>;
51
- reportTransactionError(txSig: string): Promise<any>;
52
51
  getTxLandRate(): number;
53
52
  private defaultLandRateToFeeFunc;
54
53
  getSuggestedPriorityFeeMultiplier(): number;
@@ -5,18 +5,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.BaseTxSender = void 0;
7
7
  const types_1 = require("./types");
8
- const web3_js_1 = require("@solana/web3.js");
9
- const anchor_1 = require("@coral-xyz/anchor");
10
8
  const assert_1 = __importDefault(require("assert"));
11
9
  const bs58_1 = __importDefault(require("bs58"));
12
10
  const txHandler_1 = require("./txHandler");
13
11
  const node_cache_1 = __importDefault(require("node-cache"));
12
+ const config_1 = require("../config");
13
+ const txConstants_1 = require("../constants/txConstants");
14
+ const reportTransactionError_1 = require("./reportTransactionError");
14
15
  const BASELINE_TX_LAND_RATE = 0.9;
15
16
  const DEFAULT_TIMEOUT = 35000;
16
17
  const DEFAULT_TX_LAND_RATE_LOOKBACK_WINDOW_MINUTES = 10;
17
- const NOT_CONFIRMED_ERROR_CODE = -1001;
18
18
  class BaseTxSender {
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, landRateToFeeFunc, }) {
19
+ constructor({ connection, wallet, opts = config_1.DEFAULT_CONFIRMATION_OPTS, timeout = DEFAULT_TIMEOUT, additionalConnections = new Array(), confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks, trackTxLandRate, txHandler, txLandRateLookbackWindowMinutes = DEFAULT_TX_LAND_RATE_LOOKBACK_WINDOW_MINUTES, landRateToFeeFunc, }) {
20
20
  this.timeoutCount = 0;
21
21
  this.txLandRate = 0;
22
22
  this.lastPriorityFeeSuggestion = 1;
@@ -166,7 +166,7 @@ class BaseTxSender {
166
166
  }
167
167
  this.timeoutCount += 1;
168
168
  const duration = (Date.now() - start) / 1000;
169
- throw new types_1.TxSendError(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`, NOT_CONFIRMED_ERROR_CODE);
169
+ throw new types_1.TxSendError(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`, txConstants_1.NOT_CONFIRMED_ERROR_CODE);
170
170
  }
171
171
  return response;
172
172
  }
@@ -192,7 +192,7 @@ class BaseTxSender {
192
192
  // Transaction not confirmed within 30 seconds
193
193
  this.timeoutCount += 1;
194
194
  const duration = (Date.now() - start) / 1000;
195
- throw new types_1.TxSendError(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`, NOT_CONFIRMED_ERROR_CODE);
195
+ throw new types_1.TxSendError(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`, txConstants_1.NOT_CONFIRMED_ERROR_CODE);
196
196
  }
197
197
  async confirmTransaction(signature, commitment) {
198
198
  if (this.confirmationStrategy === types_1.ConfirmationStrategy.WebSocket ||
@@ -243,30 +243,12 @@ class BaseTxSender {
243
243
  return this.timeoutCount;
244
244
  }
245
245
  async checkConfirmationResultForError(txSig, result) {
246
+ var _a;
246
247
  if (result.err) {
247
- await this.reportTransactionError(txSig);
248
+ await (0, reportTransactionError_1.throwTransactionError)(txSig, this.connection, (_a = this.opts) === null || _a === void 0 ? void 0 : _a.commitment);
248
249
  }
249
250
  return;
250
251
  }
251
- async reportTransactionError(txSig) {
252
- var _a, _b;
253
- const transactionResult = await this.connection.getTransaction(txSig, {
254
- maxSupportedTransactionVersion: 0,
255
- });
256
- if (!((_a = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.meta) === null || _a === void 0 ? void 0 : _a.err)) {
257
- return undefined;
258
- }
259
- const logs = transactionResult.meta.logMessages;
260
- const lastLog = logs[logs.length - 1];
261
- const friendlyMessage = (_b = lastLog === null || lastLog === void 0 ? void 0 : lastLog.match(/(failed:) (.+)/)) === null || _b === void 0 ? void 0 : _b[2];
262
- // @ts-ignore
263
- throw new web3_js_1.SendTransactionError({
264
- action: 'send',
265
- signature: txSig,
266
- transactionMessage: `Transaction Failed${friendlyMessage ? `: ${friendlyMessage}` : ''}`,
267
- logs,
268
- });
269
- }
270
252
  getTxLandRate() {
271
253
  if (!this.trackTxLandRate) {
272
254
  console.warn('trackTxLandRate is false, returning default land rate of 0');
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FastSingleTxSender = void 0;
4
4
  const types_1 = require("./types");
5
- const anchor_1 = require("@coral-xyz/anchor");
6
5
  const baseTxSender_1 = require("./baseTxSender");
6
+ const config_1 = require("../config");
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, confirmInBackground = false, blockhashCommitment = 'finalized', confirmationStrategy = types_1.ConfirmationStrategy.Combo, trackTxLandRate, txHandler, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
10
+ constructor({ connection, wallet, opts = { ...config_1.DEFAULT_CONFIRMATION_OPTS, 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,
@@ -4,15 +4,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ForwardOnlyTxSender = void 0;
7
- const anchor_1 = require("@coral-xyz/anchor");
8
7
  const web3_js_1 = require("@solana/web3.js");
9
8
  const bs58_1 = __importDefault(require("bs58"));
10
9
  const baseTxSender_1 = require("./baseTxSender");
11
10
  const types_1 = require("./types");
11
+ const config_1 = require("../config");
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, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
15
+ constructor({ connection, wallet, opts = { ...config_1.DEFAULT_CONFIRMATION_OPTS, 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,
@@ -0,0 +1,20 @@
1
+ import { Commitment, Connection, SendTransactionError, VersionedTransactionResponse } from '@solana/web3.js';
2
+ /**
3
+ * THROWS if there is an error
4
+ *
5
+ * Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
6
+ * @param txSig
7
+ * @param connection
8
+ * @returns
9
+ */
10
+ export declare const throwTransactionError: (txSig: string, connection: Connection, commitment?: Commitment) => Promise<void>;
11
+ /**
12
+ * RETURNS an error if there is one
13
+ *
14
+ * Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
15
+ * @param txSig
16
+ * @param connection
17
+ * @returns
18
+ */
19
+ export declare const getTransactionErrorFromTxSig: (txSig: string, connection: Connection, commitment?: Commitment) => Promise<SendTransactionError>;
20
+ export declare const getTransactionError: (transactionResult: VersionedTransactionResponse) => SendTransactionError;
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTransactionError = exports.getTransactionErrorFromTxSig = exports.throwTransactionError = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const config_1 = require("../config");
6
+ /**
7
+ * The new getTransaction method expects a Finality type instead of a Commitment type. The only options for Finality are 'confirmed' and 'finalized'.
8
+ * @param commitment
9
+ * @returns
10
+ */
11
+ const commitmentToFinality = (commitment) => {
12
+ switch (commitment) {
13
+ case 'confirmed':
14
+ return 'confirmed';
15
+ case 'finalized':
16
+ return 'finalized';
17
+ default:
18
+ throw new Error(`Invalid commitment when reporting transaction error. The commitment must be 'confirmed' or 'finalized' but was given '${commitment}'. If you're using this commitment for a specific reason, you may need to roll your own logic here.`);
19
+ }
20
+ };
21
+ const getTransactionResult = async (txSig, connection, commitment) => {
22
+ const finality = commitmentToFinality(commitment || connection.commitment || config_1.DEFAULT_CONFIRMATION_OPTS.commitment);
23
+ return await connection.getTransaction(txSig, {
24
+ maxSupportedTransactionVersion: 0,
25
+ commitment: finality,
26
+ });
27
+ };
28
+ const getTransactionResultWithRetry = async (txSig, connection, commitment) => {
29
+ const start = Date.now();
30
+ const retryTimeout = 3000; // Timeout after 3 seconds
31
+ const retryInterval = 800; // Retry with 800ms interval
32
+ const retryCount = 3; // Retry 3 times
33
+ let currentCount = 0;
34
+ let transactionResult = await getTransactionResult(txSig, connection, commitment);
35
+ // Retry 3 times or until timeout as long as we don't have a result yet
36
+ while (!transactionResult &&
37
+ Date.now() - start < retryTimeout &&
38
+ currentCount < retryCount) {
39
+ // Sleep for 1 second :: Do this first so that we don't run the first loop immediately after the initial fetch above
40
+ await new Promise((resolve) => setTimeout(resolve, retryInterval));
41
+ transactionResult = await getTransactionResult(txSig, connection, commitment);
42
+ currentCount++;
43
+ }
44
+ return transactionResult;
45
+ };
46
+ /**
47
+ * THROWS if there is an error
48
+ *
49
+ * Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
50
+ * @param txSig
51
+ * @param connection
52
+ * @returns
53
+ */
54
+ const throwTransactionError = async (txSig, connection, commitment) => {
55
+ const err = await (0, exports.getTransactionErrorFromTxSig)(txSig, connection, commitment);
56
+ if (err) {
57
+ throw err;
58
+ }
59
+ return;
60
+ };
61
+ exports.throwTransactionError = throwTransactionError;
62
+ /**
63
+ * RETURNS an error if there is one
64
+ *
65
+ * Should only be used for a txSig that is confirmed has an error. There is a race-condition where sometimes the transaction is not instantly available to fetch after the confirmation has already failed with an error, so this method has retry logic which we don't want to do wastefully. This method will throw a generic error if it can't get the transaction result after a retry period.
66
+ * @param txSig
67
+ * @param connection
68
+ * @returns
69
+ */
70
+ const getTransactionErrorFromTxSig = async (txSig, connection, commitment) => {
71
+ var _a;
72
+ const transactionResult = await getTransactionResultWithRetry(txSig, connection, commitment);
73
+ if (!transactionResult) {
74
+ // Throw a generic error because we couldn't get the transaction result for the given txSig
75
+ return new web3_js_1.SendTransactionError({
76
+ action: 'send',
77
+ signature: txSig,
78
+ transactionMessage: `Transaction Failed`,
79
+ });
80
+ }
81
+ if (!((_a = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.meta) === null || _a === void 0 ? void 0 : _a.err)) {
82
+ // Assume that the transaction was successful and we are here erroneously because we have a result with no error
83
+ return;
84
+ }
85
+ return (0, exports.getTransactionError)(transactionResult);
86
+ };
87
+ exports.getTransactionErrorFromTxSig = getTransactionErrorFromTxSig;
88
+ const getTransactionError = (transactionResult) => {
89
+ var _a, _b, _c, _d, _e, _f;
90
+ if (!((_a = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.meta) === null || _a === void 0 ? void 0 : _a.err)) {
91
+ return;
92
+ }
93
+ const logs = (_c = (_b = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.meta) === null || _b === void 0 ? void 0 : _b.logMessages) !== null && _c !== void 0 ? _c : ['No logs'];
94
+ const lastLog = logs[logs.length - 1];
95
+ const friendlyMessage = (_d = lastLog === null || lastLog === void 0 ? void 0 : lastLog.match(/(failed:) (.+)/)) === null || _d === void 0 ? void 0 : _d[2];
96
+ return new web3_js_1.SendTransactionError({
97
+ action: 'send',
98
+ signature: (_f = (_e = transactionResult === null || transactionResult === void 0 ? void 0 : transactionResult.transaction) === null || _e === void 0 ? void 0 : _e.signatures) === null || _f === void 0 ? void 0 : _f[0],
99
+ transactionMessage: `Transaction Failed${friendlyMessage ? `: ${friendlyMessage}` : ''}`,
100
+ logs,
101
+ });
102
+ };
103
+ exports.getTransactionError = getTransactionError;
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RetryTxSender = void 0;
4
4
  const types_1 = require("./types");
5
- const anchor_1 = require("@coral-xyz/anchor");
6
5
  const baseTxSender_1 = require("./baseTxSender");
6
+ const config_1 = require("../config");
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, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
10
+ constructor({ connection, wallet, opts = { ...config_1.DEFAULT_CONFIRMATION_OPTS, 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,
@@ -11,6 +11,7 @@ const computeUnits_1 = require("../util/computeUnits");
11
11
  const cachedBlockhashFetcher_1 = require("./blockhashFetcher/cachedBlockhashFetcher");
12
12
  const baseBlockhashFetcher_1 = require("./blockhashFetcher/baseBlockhashFetcher");
13
13
  const utils_1 = require("./utils");
14
+ const config_1 = require("../config");
14
15
  /**
15
16
  * Explanation for SIGNATURE_BLOCK_AND_EXPIRY:
16
17
  *
@@ -26,22 +27,24 @@ const RECENT_BLOCKHASH_STALE_TIME_MS = 2000; // Reuse blockhashes within this ti
26
27
  */
27
28
  class TxHandler {
28
29
  constructor(props) {
29
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
30
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
30
31
  this.blockHashToLastValidBlockHeightLookup = {};
31
32
  this.returnBlockHeightsWithSignedTxCallbackData = false;
32
- this.blockhashCommitment = 'finalized';
33
+ this.blockhashCommitment = config_1.DEFAULT_CONFIRMATION_OPTS.commitment;
33
34
  this.getProps = (wallet, confirmationOpts) => [wallet !== null && wallet !== void 0 ? wallet : this.wallet, confirmationOpts !== null && confirmationOpts !== void 0 ? confirmationOpts : this.confirmationOptions];
34
35
  this.connection = props.connection;
35
36
  this.wallet = props.wallet;
36
37
  this.confirmationOptions = props.confirmationOptions;
37
- this.blockHashFetcher = ((_a = props === null || props === void 0 ? void 0 : props.config) === null || _a === void 0 ? void 0 : _a.blockhashCachingEnabled)
38
- ? new cachedBlockhashFetcher_1.CachedBlockhashFetcher(this.connection, this.blockhashCommitment, (_d = (_c = (_b = props === null || props === void 0 ? void 0 : props.config) === null || _b === void 0 ? void 0 : _b.blockhashCachingConfig) === null || _c === void 0 ? void 0 : _c.retryCount) !== null && _d !== void 0 ? _d : BLOCKHASH_FETCH_RETRY_COUNT, (_g = (_f = (_e = props === null || props === void 0 ? void 0 : props.config) === null || _e === void 0 ? void 0 : _e.blockhashCachingConfig) === null || _f === void 0 ? void 0 : _f.retrySleepTimeMs) !== null && _g !== void 0 ? _g : BLOCKHASH_FETCH_RETRY_SLEEP, (_k = (_j = (_h = props === null || props === void 0 ? void 0 : props.config) === null || _h === void 0 ? void 0 : _h.blockhashCachingConfig) === null || _j === void 0 ? void 0 : _j.staleCacheTimeMs) !== null && _k !== void 0 ? _k : RECENT_BLOCKHASH_STALE_TIME_MS)
38
+ this.blockhashCommitment =
39
+ (_e = (_d = (_b = (_a = props.confirmationOptions) === null || _a === void 0 ? void 0 : _a.preflightCommitment) !== null && _b !== void 0 ? _b : (_c = props === null || props === void 0 ? void 0 : props.connection) === null || _c === void 0 ? void 0 : _c.commitment) !== null && _d !== void 0 ? _d : this.blockhashCommitment) !== null && _e !== void 0 ? _e : 'confirmed';
40
+ this.blockHashFetcher = ((_f = props === null || props === void 0 ? void 0 : props.config) === null || _f === void 0 ? void 0 : _f.blockhashCachingEnabled)
41
+ ? new cachedBlockhashFetcher_1.CachedBlockhashFetcher(this.connection, this.blockhashCommitment, (_j = (_h = (_g = props === null || props === void 0 ? void 0 : props.config) === null || _g === void 0 ? void 0 : _g.blockhashCachingConfig) === null || _h === void 0 ? void 0 : _h.retryCount) !== null && _j !== void 0 ? _j : BLOCKHASH_FETCH_RETRY_COUNT, (_m = (_l = (_k = props === null || props === void 0 ? void 0 : props.config) === null || _k === void 0 ? void 0 : _k.blockhashCachingConfig) === null || _l === void 0 ? void 0 : _l.retrySleepTimeMs) !== null && _m !== void 0 ? _m : BLOCKHASH_FETCH_RETRY_SLEEP, (_q = (_p = (_o = props === null || props === void 0 ? void 0 : props.config) === null || _o === void 0 ? void 0 : _o.blockhashCachingConfig) === null || _p === void 0 ? void 0 : _p.staleCacheTimeMs) !== null && _q !== void 0 ? _q : RECENT_BLOCKHASH_STALE_TIME_MS)
39
42
  : new baseBlockhashFetcher_1.BaseBlockhashFetcher(this.connection, this.blockhashCommitment);
40
43
  // #Optionals
41
44
  this.returnBlockHeightsWithSignedTxCallbackData =
42
- (_m = (_l = props.opts) === null || _l === void 0 ? void 0 : _l.returnBlockHeightsWithSignedTxCallbackData) !== null && _m !== void 0 ? _m : false;
43
- this.onSignedCb = (_o = props.opts) === null || _o === void 0 ? void 0 : _o.onSignedCb;
44
- this.preSignedCb = (_p = props.opts) === null || _p === void 0 ? void 0 : _p.preSignedCb;
45
+ (_s = (_r = props.opts) === null || _r === void 0 ? void 0 : _r.returnBlockHeightsWithSignedTxCallbackData) !== null && _s !== void 0 ? _s : false;
46
+ this.onSignedCb = (_t = props.opts) === null || _t === void 0 ? void 0 : _t.onSignedCb;
47
+ this.preSignedCb = (_u = props.opts) === null || _u === void 0 ? void 0 : _u.preSignedCb;
45
48
  }
46
49
  addHashAndExpiryToLookup(hashAndExpiry) {
47
50
  if (!this.returnBlockHeightsWithSignedTxCallbackData)
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- import { TxSigAndSlot } from './types';
3
- import { Commitment, ConfirmOptions, Connection, Signer, Transaction, VersionedTransaction } from '@solana/web3.js';
2
+ import { ConfirmationStrategy, TxSigAndSlot } from './types';
3
+ import { ConfirmOptions, Connection, Signer, Transaction, VersionedTransaction } from '@solana/web3.js';
4
4
  import { BaseTxSender } from './baseTxSender';
5
5
  import { TxHandler } from './txHandler';
6
6
  import { IWallet } from '../types';
@@ -19,17 +19,16 @@ export declare class WhileValidTxSender extends BaseTxSender {
19
19
  blockhash: string;
20
20
  lastValidBlockHeight: number;
21
21
  }>;
22
- blockhashCommitment: Commitment;
23
22
  useBlockHeightOffset: boolean;
24
23
  private checkAndSetUseBlockHeightOffset;
25
- constructor({ connection, wallet, opts, retrySleep, additionalConnections, additionalTxSenderCallbacks, blockhashCommitment, txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
24
+ constructor({ connection, wallet, opts, retrySleep, additionalConnections, confirmationStrategy, additionalTxSenderCallbacks, txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
26
25
  connection: Connection;
27
26
  wallet: IWallet;
28
27
  opts?: ConfirmOptions;
29
28
  retrySleep?: number;
30
29
  additionalConnections?: any;
31
30
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
32
- blockhashCommitment?: Commitment;
31
+ confirmationStrategy?: ConfirmationStrategy;
33
32
  txHandler?: TxHandler;
34
33
  trackTxLandRate?: boolean;
35
34
  txLandRateLookbackWindowMinutes?: number;
@@ -4,11 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.WhileValidTxSender = void 0;
7
- const anchor_1 = require("@coral-xyz/anchor");
7
+ const types_1 = require("./types");
8
+ const web3_js_1 = require("@solana/web3.js");
8
9
  const baseTxSender_1 = require("./baseTxSender");
9
10
  const bs58_1 = __importDefault(require("bs58"));
11
+ const config_1 = require("../config");
10
12
  const DEFAULT_RETRY = 2000;
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
13
  class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
13
14
  async checkAndSetUseBlockHeightOffset() {
14
15
  this.connection.getVersion().then((version) => {
@@ -29,7 +30,7 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
29
30
  }
30
31
  });
31
32
  }
32
- constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), additionalTxSenderCallbacks = [], blockhashCommitment = 'finalized', txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
33
+ constructor({ connection, wallet, opts = { ...config_1.DEFAULT_CONFIRMATION_OPTS, maxRetries: 0 }, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), confirmationStrategy = types_1.ConfirmationStrategy.Combo, additionalTxSenderCallbacks = [], txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }) {
33
34
  super({
34
35
  connection,
35
36
  wallet,
@@ -39,13 +40,13 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
39
40
  txHandler,
40
41
  trackTxLandRate,
41
42
  txLandRateLookbackWindowMinutes,
43
+ confirmationStrategy,
42
44
  landRateToFeeFunc,
43
45
  });
44
46
  this.timoutCount = 0;
45
47
  this.untilValid = new Map();
46
48
  this.useBlockHeightOffset = true;
47
49
  this.retrySleep = retrySleep;
48
- this.blockhashCommitment = blockhashCommitment;
49
50
  this.checkAndSetUseBlockHeightOffset();
50
51
  }
51
52
  async sleep(reference) {
@@ -69,7 +70,7 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
69
70
  latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
70
71
  }
71
72
  // handle subclass-specific side effects
72
- const txSig = bs58_1.default.encode(((_a = signedTx.signatures[0]) === null || _a === void 0 ? void 0 : _a.signature) || signedTx.signatures[0]);
73
+ const txSig = bs58_1.default.encode((signedTx === null || signedTx === void 0 ? void 0 : signedTx.signature) || ((_a = signedTx.signatures[0]) === null || _a === void 0 ? void 0 : _a.signature));
73
74
  this.untilValid.set(txSig, latestBlockhash);
74
75
  return signedTx;
75
76
  }
@@ -107,7 +108,7 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
107
108
  return this.sendRawTransaction(signedTx.serialize(), opts);
108
109
  }
109
110
  async sendRawTransaction(rawTransaction, opts) {
110
- var _a, _b;
111
+ var _a, _b, _c;
111
112
  const startTime = this.getTimestamp();
112
113
  const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
113
114
  (_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(txid, false);
@@ -138,19 +139,17 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
138
139
  })();
139
140
  let slot;
140
141
  try {
141
- const { blockhash, lastValidBlockHeight } = this.untilValid.get(txid);
142
- const result = await this.connection.confirmTransaction({
143
- signature: txid,
144
- blockhash,
145
- lastValidBlockHeight: this.useBlockHeightOffset
146
- ? lastValidBlockHeight + VALID_BLOCK_HEIGHT_OFFSET
147
- : lastValidBlockHeight,
148
- }, opts === null || opts === void 0 ? void 0 : opts.commitment);
149
- if (!result) {
150
- throw new Error(`Couldn't get signature status for txid: ${txid}`);
151
- }
142
+ const result = await this.confirmTransaction(txid, opts.commitment);
152
143
  (_b = this.txSigCache) === null || _b === void 0 ? void 0 : _b.set(txid, true);
153
144
  await this.checkConfirmationResultForError(txid, result.value);
145
+ if ((_c = result === null || result === void 0 ? void 0 : result.value) === null || _c === void 0 ? void 0 : _c.err) {
146
+ // Fallback error handling if there's a problem reporting the error in checkConfirmationResultForError
147
+ throw new web3_js_1.SendTransactionError({
148
+ action: 'send',
149
+ signature: txid,
150
+ transactionMessage: `Transaction Failed`,
151
+ });
152
+ }
154
153
  slot = result.context.slot;
155
154
  // eslint-disable-next-line no-useless-catch
156
155
  }
package/lib/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /// <reference types="bn.js" />
2
- import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
2
+ import { Keypair, PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
3
3
  import { BN } from '.';
4
4
  export type MappedRecord<A extends Record<string, unknown>, B> = {
5
5
  [K in keyof A]: B;
@@ -1096,6 +1096,21 @@ export declare class ModifyOrderPolicy {
1096
1096
  };
1097
1097
  }
1098
1098
  export declare const DefaultOrderParams: OrderParams;
1099
+ export type SwiftServerMessage = {
1100
+ slot: BN;
1101
+ swiftOrderSignature: Uint8Array;
1102
+ };
1103
+ export type SwiftOrderParamsMessage = {
1104
+ swiftOrderParams: OptionalOrderParams;
1105
+ expectedOrderId: number;
1106
+ subAccountId: number;
1107
+ takeProfitOrderParams: SwiftTriggerOrderParams | null;
1108
+ stopLossOrderParams: SwiftTriggerOrderParams | null;
1109
+ };
1110
+ export type SwiftTriggerOrderParams = {
1111
+ triggerPrice: BN;
1112
+ baseAssetAmount: BN;
1113
+ };
1099
1114
  export type MakerInfo = {
1100
1115
  maker: PublicKey;
1101
1116
  makerStats: PublicKey;
@@ -1112,6 +1127,10 @@ export type ReferrerInfo = {
1112
1127
  referrer: PublicKey;
1113
1128
  referrerStats: PublicKey;
1114
1129
  };
1130
+ export declare enum PlaceAndTakeOrderSuccessCondition {
1131
+ PartialFill = 1,
1132
+ FullFill = 2
1133
+ }
1115
1134
  type ExactType<T> = Pick<T, keyof T>;
1116
1135
  export type BaseTxParams = ExactType<{
1117
1136
  computeUnits?: number;
@@ -1137,11 +1156,13 @@ export interface IWallet {
1137
1156
  signTransaction(tx: Transaction): Promise<Transaction>;
1138
1157
  signAllTransactions(txs: Transaction[]): Promise<Transaction[]>;
1139
1158
  publicKey: PublicKey;
1159
+ payer?: Keypair;
1140
1160
  }
1141
1161
  export interface IVersionedWallet {
1142
1162
  signVersionedTransaction(tx: VersionedTransaction): Promise<VersionedTransaction>;
1143
1163
  signAllVersionedTransactions(txs: VersionedTransaction[]): Promise<VersionedTransaction[]>;
1144
1164
  publicKey: PublicKey;
1165
+ payer?: Keypair;
1145
1166
  }
1146
1167
  export type FeeStructure = {
1147
1168
  feeTiers: FeeTier[];
package/lib/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SwapReduceOnly = exports.DefaultOrderParams = exports.ModifyOrderPolicy = exports.PostOnlyParams = exports.LiquidationType = exports.LPAction = exports.TradeSide = exports.getVariant = exports.isOneOfVariant = exports.isVariant = exports.SettlePnlMode = exports.StakeAction = exports.SpotFulfillmentConfigStatus = exports.SettlePnlExplanation = exports.DepositExplanation = exports.SpotFulfillmentStatus = exports.SpotFulfillmentType = exports.OrderTriggerCondition = exports.OrderActionExplanation = exports.OrderAction = exports.OrderStatus = exports.MarketType = exports.OrderType = exports.OracleSource = exports.DepositDirection = exports.PositionDirection = exports.SpotBalanceType = exports.SwapDirection = exports.AssetTier = exports.ContractTier = exports.ContractType = exports.UserStatus = exports.InsuranceFundOperation = exports.SpotOperation = exports.PerpOperation = exports.MarketStatus = exports.ExchangeStatus = void 0;
3
+ exports.SwapReduceOnly = exports.PlaceAndTakeOrderSuccessCondition = exports.DefaultOrderParams = exports.ModifyOrderPolicy = exports.PostOnlyParams = exports.LiquidationType = exports.LPAction = exports.TradeSide = exports.getVariant = exports.isOneOfVariant = exports.isVariant = exports.SettlePnlMode = exports.StakeAction = exports.SpotFulfillmentConfigStatus = exports.SettlePnlExplanation = exports.DepositExplanation = exports.SpotFulfillmentStatus = exports.SpotFulfillmentType = exports.OrderTriggerCondition = exports.OrderActionExplanation = exports.OrderAction = exports.OrderStatus = exports.MarketType = exports.OrderType = exports.OracleSource = exports.DepositDirection = exports.PositionDirection = exports.SpotBalanceType = exports.SwapDirection = exports.AssetTier = exports.ContractTier = exports.ContractType = exports.UserStatus = exports.InsuranceFundOperation = exports.SpotOperation = exports.PerpOperation = exports.MarketStatus = exports.ExchangeStatus = void 0;
4
4
  const _1 = require(".");
5
5
  // # Utility Types / Enums / Constants
6
6
  var ExchangeStatus;
@@ -325,6 +325,11 @@ exports.DefaultOrderParams = {
325
325
  auctionStartPrice: null,
326
326
  auctionEndPrice: null,
327
327
  };
328
+ var PlaceAndTakeOrderSuccessCondition;
329
+ (function (PlaceAndTakeOrderSuccessCondition) {
330
+ PlaceAndTakeOrderSuccessCondition[PlaceAndTakeOrderSuccessCondition["PartialFill"] = 1] = "PartialFill";
331
+ PlaceAndTakeOrderSuccessCondition[PlaceAndTakeOrderSuccessCondition["FullFill"] = 2] = "FullFill";
332
+ })(PlaceAndTakeOrderSuccessCondition = exports.PlaceAndTakeOrderSuccessCondition || (exports.PlaceAndTakeOrderSuccessCondition = {}));
328
333
  class SwapReduceOnly {
329
334
  }
330
335
  exports.SwapReduceOnly = SwapReduceOnly;
@@ -0,0 +1,16 @@
1
+ import { Connection, RpcResponseAndContext, SignatureResult, SignatureStatus, TransactionConfirmationStatus } from '@solana/web3.js';
2
+ /**
3
+ * Class to await for transaction confirmations in an optimised manner. It tracks a shared list of all pending transactions and fetches them in bulk in a shared RPC request whenever they have an "overlapping" polling interval. E.g. tx1 with an interval of 200ms and tx2 with an interval of 300ms (if sent at the same time) will be fetched together at at 600ms, 1200ms, 1800ms, etc.
4
+ */
5
+ export declare class TransactionConfirmationManager {
6
+ private connection;
7
+ private pendingConfirmations;
8
+ private intervalId;
9
+ constructor(connection: Connection);
10
+ confirmTransactionWebSocket(txSig: string, timeout?: number, desiredConfirmationStatus?: TransactionConfirmationStatus): Promise<RpcResponseAndContext<SignatureResult>>;
11
+ confirmTransactionPolling(txSig: string, desiredConfirmationStatus?: TransactionConfirmationStatus, timeout?: number, pollInterval?: number, searchTransactionHistory?: boolean): Promise<SignatureStatus>;
12
+ private startConfirmationLoop;
13
+ private checkPendingConfirmations;
14
+ private checkStatusMatchesDesiredConfirmationStatus;
15
+ private checkTransactionStatuses;
16
+ }