@drift-labs/sdk 2.96.0-beta.24 → 2.96.0-beta.26

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.96.0-beta.24
1
+ 2.96.0-beta.26
package/lib/config.d.ts CHANGED
@@ -26,6 +26,7 @@ export type DriftEnv = 'devnet' | 'mainnet-beta';
26
26
  export declare const DRIFT_PROGRAM_ID = "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH";
27
27
  export declare const DRIFT_ORACLE_RECEIVER_ID = "G6EoTTTgpkNBtVXo96EQp2m6uwwVh2Kt6YidjkmQqoha";
28
28
  export declare const SWIFT_ID = "SW1fThqrxLzVprnCMpiybiqYQfoNCdduC5uWsSUKChS";
29
+ export declare const ANCHOR_TEST_SWIFT_ID = "DpaEdAPW3ZX67fnczT14AoX12Lx9VMkxvtT81nCHy3Nv";
29
30
  export declare const DEFAULT_CONFIRMATION_OPTS: ConfirmOptions;
30
31
  export declare const configs: {
31
32
  [key in DriftEnv]: DriftConfig;
package/lib/config.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findAllMarketAndOracles = exports.getMarketsAndOraclesForSubscription = exports.initialize = exports.getConfig = exports.configs = exports.DEFAULT_CONFIRMATION_OPTS = exports.SWIFT_ID = exports.DRIFT_ORACLE_RECEIVER_ID = exports.DRIFT_PROGRAM_ID = void 0;
3
+ exports.findAllMarketAndOracles = exports.getMarketsAndOraclesForSubscription = exports.initialize = exports.getConfig = exports.configs = exports.DEFAULT_CONFIRMATION_OPTS = exports.ANCHOR_TEST_SWIFT_ID = exports.SWIFT_ID = exports.DRIFT_ORACLE_RECEIVER_ID = exports.DRIFT_PROGRAM_ID = void 0;
4
4
  const perpMarkets_1 = require("./constants/perpMarkets");
5
5
  const spotMarkets_1 = require("./constants/spotMarkets");
6
6
  const on_demand_1 = require("@switchboard-xyz/on-demand");
7
7
  exports.DRIFT_PROGRAM_ID = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH';
8
8
  exports.DRIFT_ORACLE_RECEIVER_ID = 'G6EoTTTgpkNBtVXo96EQp2m6uwwVh2Kt6YidjkmQqoha';
9
9
  exports.SWIFT_ID = 'SW1fThqrxLzVprnCMpiybiqYQfoNCdduC5uWsSUKChS';
10
+ exports.ANCHOR_TEST_SWIFT_ID = 'DpaEdAPW3ZX67fnczT14AoX12Lx9VMkxvtT81nCHy3Nv';
10
11
  exports.DEFAULT_CONFIRMATION_OPTS = {
11
12
  preflightCommitment: 'confirmed',
12
13
  commitment: 'confirmed',
@@ -263,7 +263,7 @@ exports.DevnetPerpMarkets = [
263
263
  symbol: 'W-PERP',
264
264
  baseAssetSymbol: 'W',
265
265
  marketIndex: 23,
266
- oracle: new web3_js_1.PublicKey('4iCi4DvXrubHQne8jzbMaWL3pd7v1Fip8iTe4H9vHNXB'),
266
+ oracle: new web3_js_1.PublicKey('J9nrFWjDUeDVZ4BhhxsbQXWgLcLEgQyNBrCbwSADmJdr'),
267
267
  launchTs: 1709852537000,
268
268
  oracleSource: __1.OracleSource.SWITCHBOARD_ON_DEMAND,
269
269
  pythFeedId: '0xeff7446475e218517566ea99e72a4abec2e1bd8498b43b7d8331e29dcb059389',
@@ -810,6 +810,16 @@ exports.MainnetPerpMarkets = [
810
810
  oracleSource: __1.OracleSource.PYTH_PULL,
811
811
  pythFeedId: '0xffff73128917a90950cd0473fd2551d7cd274fd5a6cc45641881bbcc6ee73417',
812
812
  },
813
+ {
814
+ fullName: 'WARWICK-FIGHT-WIN-BET',
815
+ category: ['Prediction', 'Sport'],
816
+ symbol: 'WARWICK-FIGHT-WIN-BET',
817
+ baseAssetSymbol: 'WARWICK-FIGHT-WIN',
818
+ marketIndex: 46,
819
+ oracle: new web3_js_1.PublicKey('Dz5Nvxo1hv7Zfyu11hy8e97twLMRKk6heTWCDGXytj7N'),
820
+ launchTs: 1727965864000,
821
+ oracleSource: __1.OracleSource.Prelaunch,
822
+ },
813
823
  ];
814
824
  exports.PerpMarkets = {
815
825
  devnet: exports.DevnetPerpMarkets,
@@ -0,0 +1 @@
1
+ export declare const NOT_CONFIRMED_ERROR_CODE = -1001;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NOT_CONFIRMED_ERROR_CODE = void 0;
4
+ exports.NOT_CONFIRMED_ERROR_CODE = -1001;
@@ -37,6 +37,7 @@ export declare class DriftClient {
37
37
  connection: Connection;
38
38
  wallet: IWallet;
39
39
  program: Program;
40
+ swiftID: PublicKey;
40
41
  provider: AnchorProvider;
41
42
  opts?: ConfirmOptions;
42
43
  users: Map<string, User>;
@@ -80,7 +80,7 @@ class DriftClient {
80
80
  this._isSubscribed = val;
81
81
  }
82
82
  constructor(config) {
83
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7;
83
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8;
84
84
  this.users = new Map();
85
85
  this._isSubscribed = false;
86
86
  this.perpMarketLastSlotCache = new Map();
@@ -98,16 +98,17 @@ class DriftClient {
98
98
  // @ts-ignore
99
99
  config.wallet, this.opts);
100
100
  this.program = new anchor_1.Program(drift_json_1.default, (_c = config.programID) !== null && _c !== void 0 ? _c : new web3_js_1.PublicKey(config_1.DRIFT_PROGRAM_ID), this.provider);
101
- this.authority = (_d = config.authority) !== null && _d !== void 0 ? _d : this.wallet.publicKey;
102
- this.activeSubAccountId = (_e = config.activeSubAccountId) !== null && _e !== void 0 ? _e : 0;
103
- this.skipLoadUsers = (_f = config.skipLoadUsers) !== null && _f !== void 0 ? _f : false;
104
- this.txVersion = (_g = config.txVersion) !== null && _g !== void 0 ? _g : 'legacy';
101
+ this.swiftID = (_d = config.swiftID) !== null && _d !== void 0 ? _d : new web3_js_1.PublicKey(config_1.SWIFT_ID);
102
+ this.authority = (_e = config.authority) !== null && _e !== void 0 ? _e : this.wallet.publicKey;
103
+ this.activeSubAccountId = (_f = config.activeSubAccountId) !== null && _f !== void 0 ? _f : 0;
104
+ this.skipLoadUsers = (_g = config.skipLoadUsers) !== null && _g !== void 0 ? _g : false;
105
+ this.txVersion = (_h = config.txVersion) !== null && _h !== void 0 ? _h : 'legacy';
105
106
  this.txParams = {
106
- computeUnits: (_j = (_h = config.txParams) === null || _h === void 0 ? void 0 : _h.computeUnits) !== null && _j !== void 0 ? _j : 600000,
107
- computeUnitsPrice: (_l = (_k = config.txParams) === null || _k === void 0 ? void 0 : _k.computeUnitsPrice) !== null && _l !== void 0 ? _l : 0,
107
+ computeUnits: (_k = (_j = config.txParams) === null || _j === void 0 ? void 0 : _j.computeUnits) !== null && _k !== void 0 ? _k : 600000,
108
+ computeUnitsPrice: (_m = (_l = config.txParams) === null || _l === void 0 ? void 0 : _l.computeUnitsPrice) !== null && _m !== void 0 ? _m : 0,
108
109
  };
109
110
  this.txHandler =
110
- (_m = config === null || config === void 0 ? void 0 : config.txHandler) !== null && _m !== void 0 ? _m : new txHandler_1.TxHandler({
111
+ (_o = config === null || config === void 0 ? void 0 : config.txHandler) !== null && _o !== void 0 ? _o : new txHandler_1.TxHandler({
111
112
  connection: this.connection,
112
113
  // @ts-ignore
113
114
  wallet: this.provider.wallet,
@@ -133,8 +134,8 @@ class DriftClient {
133
134
  : config.subAccountIds
134
135
  ? new Map([[this.authority.toString(), config.subAccountIds]])
135
136
  : new Map();
136
- this.includeDelegates = (_o = config.includeDelegates) !== null && _o !== void 0 ? _o : false;
137
- if (((_p = config.accountSubscription) === null || _p === void 0 ? void 0 : _p.type) === 'polling') {
137
+ this.includeDelegates = (_p = config.includeDelegates) !== null && _p !== void 0 ? _p : false;
138
+ if (((_q = config.accountSubscription) === null || _q === void 0 ? void 0 : _q.type) === 'polling') {
138
139
  this.userAccountSubscriptionConfig = {
139
140
  type: 'polling',
140
141
  accountLoader: config.accountSubscription.accountLoader,
@@ -147,15 +148,15 @@ class DriftClient {
147
148
  else {
148
149
  this.userAccountSubscriptionConfig = {
149
150
  type: 'websocket',
150
- resubTimeoutMs: (_q = config.accountSubscription) === null || _q === void 0 ? void 0 : _q.resubTimeoutMs,
151
- logResubMessages: (_r = config.accountSubscription) === null || _r === void 0 ? void 0 : _r.logResubMessages,
152
- commitment: (_s = config.accountSubscription) === null || _s === void 0 ? void 0 : _s.commitment,
151
+ resubTimeoutMs: (_r = config.accountSubscription) === null || _r === void 0 ? void 0 : _r.resubTimeoutMs,
152
+ logResubMessages: (_s = config.accountSubscription) === null || _s === void 0 ? void 0 : _s.logResubMessages,
153
+ commitment: (_t = config.accountSubscription) === null || _t === void 0 ? void 0 : _t.commitment,
153
154
  };
154
155
  this.userStatsAccountSubscriptionConfig = {
155
156
  type: 'websocket',
156
- resubTimeoutMs: (_t = config.accountSubscription) === null || _t === void 0 ? void 0 : _t.resubTimeoutMs,
157
- logResubMessages: (_u = config.accountSubscription) === null || _u === void 0 ? void 0 : _u.logResubMessages,
158
- commitment: (_v = config.accountSubscription) === null || _v === void 0 ? void 0 : _v.commitment,
157
+ resubTimeoutMs: (_u = config.accountSubscription) === null || _u === void 0 ? void 0 : _u.resubTimeoutMs,
158
+ logResubMessages: (_v = config.accountSubscription) === null || _v === void 0 ? void 0 : _v.logResubMessages,
159
+ commitment: (_w = config.accountSubscription) === null || _w === void 0 ? void 0 : _w.commitment,
159
160
  };
160
161
  }
161
162
  if (config.userStats) {
@@ -173,14 +174,14 @@ class DriftClient {
173
174
  const noMarketsAndOraclesSpecified = config.perpMarketIndexes === undefined &&
174
175
  config.spotMarketIndexes === undefined &&
175
176
  config.oracleInfos === undefined;
176
- if (((_w = config.accountSubscription) === null || _w === void 0 ? void 0 : _w.type) === 'polling') {
177
- this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, (_x = config.perpMarketIndexes) !== null && _x !== void 0 ? _x : [], (_y = config.spotMarketIndexes) !== null && _y !== void 0 ? _y : [], (_z = config.oracleInfos) !== null && _z !== void 0 ? _z : [], noMarketsAndOraclesSpecified, delistedMarketSetting);
177
+ if (((_x = config.accountSubscription) === null || _x === void 0 ? void 0 : _x.type) === 'polling') {
178
+ this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, (_y = config.perpMarketIndexes) !== null && _y !== void 0 ? _y : [], (_z = config.spotMarketIndexes) !== null && _z !== void 0 ? _z : [], (_0 = config.oracleInfos) !== null && _0 !== void 0 ? _0 : [], noMarketsAndOraclesSpecified, delistedMarketSetting);
178
179
  }
179
180
  else {
180
- this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, (_0 = config.perpMarketIndexes) !== null && _0 !== void 0 ? _0 : [], (_1 = config.spotMarketIndexes) !== null && _1 !== void 0 ? _1 : [], (_2 = config.oracleInfos) !== null && _2 !== void 0 ? _2 : [], noMarketsAndOraclesSpecified, delistedMarketSetting, {
181
- resubTimeoutMs: (_3 = config.accountSubscription) === null || _3 === void 0 ? void 0 : _3.resubTimeoutMs,
182
- logResubMessages: (_4 = config.accountSubscription) === null || _4 === void 0 ? void 0 : _4.logResubMessages,
183
- }, (_5 = config.accountSubscription) === null || _5 === void 0 ? void 0 : _5.commitment);
181
+ this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, (_1 = config.perpMarketIndexes) !== null && _1 !== void 0 ? _1 : [], (_2 = config.spotMarketIndexes) !== null && _2 !== void 0 ? _2 : [], (_3 = config.oracleInfos) !== null && _3 !== void 0 ? _3 : [], noMarketsAndOraclesSpecified, delistedMarketSetting, {
182
+ resubTimeoutMs: (_4 = config.accountSubscription) === null || _4 === void 0 ? void 0 : _4.resubTimeoutMs,
183
+ logResubMessages: (_5 = config.accountSubscription) === null || _5 === void 0 ? void 0 : _5.logResubMessages,
184
+ }, (_6 = config.accountSubscription) === null || _6 === void 0 ? void 0 : _6.commitment);
184
185
  }
185
186
  this.eventEmitter = this.accountSubscriber.eventEmitter;
186
187
  this.metricsEventEmitter = new events_1.EventEmitter();
@@ -188,14 +189,14 @@ class DriftClient {
188
189
  this.enableMetricsEvents = true;
189
190
  }
190
191
  this.txSender =
191
- (_6 = config.txSender) !== null && _6 !== void 0 ? _6 : new retryTxSender_1.RetryTxSender({
192
+ (_7 = config.txSender) !== null && _7 !== void 0 ? _7 : new retryTxSender_1.RetryTxSender({
192
193
  connection: this.connection,
193
194
  wallet: this.wallet,
194
195
  opts: this.opts,
195
196
  txHandler: this.txHandler,
196
197
  });
197
198
  this.sbOnDemandProgramdId =
198
- config_1.configs[(_7 = config.env) !== null && _7 !== void 0 ? _7 : 'mainnet-beta'].SB_ON_DEMAND_PID;
199
+ config_1.configs[(_8 = config.env) !== null && _8 !== void 0 ? _8 : 'mainnet-beta'].SB_ON_DEMAND_PID;
199
200
  }
200
201
  getUserMapKey(subAccountId, authority) {
201
202
  return `${subAccountId}_${authority.toString()}`;
@@ -2956,7 +2957,7 @@ class DriftClient {
2956
2957
  readablePerpMarketIndex: marketIndex,
2957
2958
  });
2958
2959
  const swiftServerSignatureIx = web3_js_1.Ed25519Program.createInstructionWithPublicKey({
2959
- publicKey: new web3_js_1.PublicKey(config_1.SWIFT_ID).toBytes(),
2960
+ publicKey: new web3_js_1.PublicKey(this.swiftID).toBytes(),
2960
2961
  signature: Uint8Array.from(swiftSignature),
2961
2962
  message: Uint8Array.from(encodedSwiftServerMessage),
2962
2963
  });
@@ -11,6 +11,7 @@ export type DriftClientConfig = {
11
11
  wallet: IWallet;
12
12
  env?: DriftEnv;
13
13
  programID?: PublicKey;
14
+ swiftID?: PublicKey;
14
15
  accountSubscription?: DriftClientSubscriptionConfig;
15
16
  opts?: ConfirmOptions;
16
17
  txSender?: TxSender;
@@ -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,16 +5,16 @@ 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
8
  const assert_1 = __importDefault(require("assert"));
10
9
  const bs58_1 = __importDefault(require("bs58"));
11
10
  const txHandler_1 = require("./txHandler");
12
11
  const node_cache_1 = __importDefault(require("node-cache"));
13
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
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;
@@ -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');
@@ -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;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { TxSigAndSlot } from './types';
2
+ import { ConfirmationStrategy, TxSigAndSlot } from './types';
3
3
  import { ConfirmOptions, Connection, Signer, Transaction, VersionedTransaction } from '@solana/web3.js';
4
4
  import { BaseTxSender } from './baseTxSender';
5
5
  import { TxHandler } from './txHandler';
@@ -21,13 +21,14 @@ export declare class WhileValidTxSender extends BaseTxSender {
21
21
  }>;
22
22
  useBlockHeightOffset: boolean;
23
23
  private checkAndSetUseBlockHeightOffset;
24
- constructor({ connection, wallet, opts, retrySleep, additionalConnections, additionalTxSenderCallbacks, txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
24
+ constructor({ connection, wallet, opts, retrySleep, additionalConnections, confirmationStrategy, additionalTxSenderCallbacks, txHandler, trackTxLandRate, txLandRateLookbackWindowMinutes, landRateToFeeFunc, }: {
25
25
  connection: Connection;
26
26
  wallet: IWallet;
27
27
  opts?: ConfirmOptions;
28
28
  retrySleep?: number;
29
29
  additionalConnections?: any;
30
30
  additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
31
+ confirmationStrategy: ConfirmationStrategy;
31
32
  txHandler?: TxHandler;
32
33
  trackTxLandRate?: boolean;
33
34
  txLandRateLookbackWindowMinutes?: number;
@@ -4,6 +4,7 @@ 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 types_1 = require("./types");
7
8
  const web3_js_1 = require("@solana/web3.js");
8
9
  const baseTxSender_1 = require("./baseTxSender");
9
10
  const bs58_1 = __importDefault(require("bs58"));
@@ -29,7 +30,7 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
29
30
  }
30
31
  });
31
32
  }
32
- constructor({ connection, wallet, opts = { ...config_1.DEFAULT_CONFIRMATION_OPTS, maxRetries: 0 }, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), additionalTxSenderCallbacks = [], 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,6 +40,7 @@ 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;
@@ -103,13 +105,11 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
103
105
  }
104
106
  const txSig = bs58_1.default.encode(signedTx.signatures[0]);
105
107
  this.untilValid.set(txSig, latestBlockhash);
106
- console.debug(`preflight_commitment`, `sending_tx_with_preflight_commitment::${opts === null || opts === void 0 ? void 0 : opts.preflightCommitment}`);
107
108
  return this.sendRawTransaction(signedTx.serialize(), opts);
108
109
  }
109
110
  async sendRawTransaction(rawTransaction, opts) {
110
111
  var _a, _b, _c;
111
112
  const startTime = this.getTimestamp();
112
- console.debug(`preflight_commitment`, `sending_tx_with_preflight_commitment::${opts === null || opts === void 0 ? void 0 : opts.preflightCommitment}`);
113
113
  const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
114
114
  (_a = this.txSigCache) === null || _a === void 0 ? void 0 : _a.set(txid, false);
115
115
  this.sendToAdditionalConnections(rawTransaction, opts);
package/lib/types.d.ts CHANGED
@@ -1103,6 +1103,7 @@ export type SwiftServerMessage = {
1103
1103
  export type SwiftOrderParamsMessage = {
1104
1104
  swiftOrderParams: OptionalOrderParams;
1105
1105
  expectedOrderId: number;
1106
+ subAccountId: number;
1106
1107
  takeProfitOrderParams: SwiftTriggerOrderParams | null;
1107
1108
  stopLossOrderParams: SwiftTriggerOrderParams | null;
1108
1109
  };
@@ -1,4 +1,4 @@
1
- import { Connection, SignatureStatus, TransactionConfirmationStatus } from '@solana/web3.js';
1
+ import { Connection, RpcResponseAndContext, SignatureResult, SignatureStatus, TransactionConfirmationStatus } from '@solana/web3.js';
2
2
  /**
3
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
4
  */
@@ -7,8 +7,10 @@ export declare class TransactionConfirmationManager {
7
7
  private pendingConfirmations;
8
8
  private intervalId;
9
9
  constructor(connection: Connection);
10
- confirmTransaction(txSig: string, desiredConfirmationStatus?: TransactionConfirmationStatus, timeout?: number, pollInterval?: number, searchTransactionHistory?: boolean): Promise<SignatureStatus>;
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>;
11
12
  private startConfirmationLoop;
12
13
  private checkPendingConfirmations;
14
+ private checkStatusMatchesDesiredConfirmationStatus;
13
15
  private checkTransactionStatuses;
14
16
  }
@@ -2,6 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TransactionConfirmationManager = void 0;
4
4
  const config_1 = require("../config");
5
+ const __1 = require("..");
6
+ const txConstants_1 = require("../constants/txConstants");
7
+ const reportTransactionError_1 = require("../tx/reportTransactionError");
8
+ const promiseTimeout_1 = require("./promiseTimeout");
5
9
  const confirmationStatusValues = {
6
10
  processed: 0,
7
11
  confirmed: 1,
@@ -16,7 +20,75 @@ class TransactionConfirmationManager {
16
20
  this.intervalId = null;
17
21
  this.connection = connection;
18
22
  }
19
- async confirmTransaction(txSig, desiredConfirmationStatus = config_1.DEFAULT_CONFIRMATION_OPTS.commitment, timeout = 30000, pollInterval = 1000, searchTransactionHistory = false) {
23
+ async confirmTransactionWebSocket(txSig, timeout = 30000, desiredConfirmationStatus = config_1.DEFAULT_CONFIRMATION_OPTS.commitment) {
24
+ const start = Date.now();
25
+ const subscriptionCommitment = desiredConfirmationStatus || config_1.DEFAULT_CONFIRMATION_OPTS.commitment;
26
+ let response = null;
27
+ let subscriptionId;
28
+ const confirmationPromise = new Promise((resolve, reject) => {
29
+ try {
30
+ subscriptionId = this.connection.onSignature(txSig, (result, context) => {
31
+ response = {
32
+ context,
33
+ value: result,
34
+ };
35
+ resolve(null);
36
+ }, subscriptionCommitment);
37
+ }
38
+ catch (err) {
39
+ reject(err);
40
+ }
41
+ });
42
+ // We do a one-shot confirmation check just in case the transaction is ALREADY confirmed when we create the websocket confirmation .. We want to run this concurrently with the onSignature subscription. If this returns true then we can return early as the transaction has already been confirmed.
43
+ const oneShotConfirmationPromise = this.connection.getSignatureStatuses([
44
+ txSig,
45
+ ]);
46
+ const resolveReference = {};
47
+ // This is the promise we are waiting on to resolve the overall confirmation. It will resolve the faster of a positive oneShot confirmation, or the websocket confirmation, or the timeout.
48
+ const overallWaitingForConfirmationPromise = new Promise((resolve) => {
49
+ resolveReference.resolve = resolve;
50
+ });
51
+ // Await for the one shot confirmation and resolve the waiting promise if we get a positive confirmation result
52
+ oneShotConfirmationPromise.then(async (oneShotResponse) => {
53
+ var _a, _b;
54
+ if (!oneShotResponse || !((_a = oneShotResponse === null || oneShotResponse === void 0 ? void 0 : oneShotResponse.value) === null || _a === void 0 ? void 0 : _a[0]))
55
+ return;
56
+ const resultValue = oneShotResponse.value[0];
57
+ if (resultValue.err) {
58
+ await (0, reportTransactionError_1.throwTransactionError)(txSig, this.connection);
59
+ }
60
+ if (this.checkStatusMatchesDesiredConfirmationStatus(resultValue, desiredConfirmationStatus)) {
61
+ response = {
62
+ context: oneShotResponse.context,
63
+ value: oneShotResponse.value[0],
64
+ };
65
+ (_b = resolveReference.resolve) === null || _b === void 0 ? void 0 : _b.call(resolveReference);
66
+ }
67
+ }, (onRejected) => {
68
+ throw onRejected;
69
+ });
70
+ // Await for the websocket confirmation with the configured timeout
71
+ (0, promiseTimeout_1.promiseTimeout)(confirmationPromise, timeout).then(() => {
72
+ var _a;
73
+ (_a = resolveReference.resolve) === null || _a === void 0 ? void 0 : _a.call(resolveReference);
74
+ }, (onRejected) => {
75
+ throw onRejected;
76
+ });
77
+ try {
78
+ await overallWaitingForConfirmationPromise;
79
+ }
80
+ finally {
81
+ if (subscriptionId !== undefined) {
82
+ this.connection.removeSignatureListener(subscriptionId);
83
+ }
84
+ }
85
+ const duration = (Date.now() - start) / 1000;
86
+ if (response === null) {
87
+ throw new __1.TxSendError(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${txSig} using the Solana Explorer or CLI tools.`, txConstants_1.NOT_CONFIRMED_ERROR_CODE);
88
+ }
89
+ return response;
90
+ }
91
+ async confirmTransactionPolling(txSig, desiredConfirmationStatus = config_1.DEFAULT_CONFIRMATION_OPTS.commitment, timeout = 30000, pollInterval = 1000, searchTransactionHistory = false) {
20
92
  // Interval must be > 400ms and a multiple of 100ms
21
93
  if (pollInterval < 400 || pollInterval % 100 !== 0) {
22
94
  throw new Error('Transaction confirmation polling interval must be at least 400ms and a multiple of 100ms');
@@ -60,6 +132,14 @@ class TransactionConfirmationManager {
60
132
  this.intervalId = null;
61
133
  }
62
134
  }
135
+ checkStatusMatchesDesiredConfirmationStatus(status, desiredConfirmationStatus) {
136
+ if (status.confirmationStatus &&
137
+ confirmationStatusValues[status.confirmationStatus] >=
138
+ confirmationStatusValues[desiredConfirmationStatus]) {
139
+ return true;
140
+ }
141
+ return false;
142
+ }
63
143
  async checkTransactionStatuses(requests) {
64
144
  const txSigs = requests.map((request) => request.txSig);
65
145
  const { value: statuses } = await this.connection.getSignatureStatuses(txSigs, {
@@ -75,8 +155,8 @@ class TransactionConfirmationManager {
75
155
  continue;
76
156
  }
77
157
  if (status.err) {
78
- request.reject(new Error(`Transaction failed: ${JSON.stringify(status.err)}`));
79
158
  this.pendingConfirmations.delete(request.txSig);
159
+ request.reject(await (0, reportTransactionError_1.getTransactionErrorFromTxSig)(request.txSig, this.connection));
80
160
  continue;
81
161
  }
82
162
  if (confirmationStatusValues[status.confirmationStatus] === undefined ||
@@ -84,9 +164,7 @@ class TransactionConfirmationManager {
84
164
  undefined) {
85
165
  throw new Error(`Invalid confirmation status when awaiting confirmation: ${status.confirmationStatus}`);
86
166
  }
87
- if (status.confirmationStatus &&
88
- confirmationStatusValues[status.confirmationStatus] >=
89
- confirmationStatusValues[request.desiredConfirmationStatus]) {
167
+ if (this.checkStatusMatchesDesiredConfirmationStatus(status, request.desiredConfirmationStatus)) {
90
168
  request.resolve(status);
91
169
  this.pendingConfirmations.delete(request.txSig);
92
170
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.96.0-beta.24",
3
+ "version": "2.96.0-beta.26",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
package/src/config.ts CHANGED
@@ -44,6 +44,8 @@ export const DRIFT_PROGRAM_ID = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH';
44
44
  export const DRIFT_ORACLE_RECEIVER_ID =
45
45
  'G6EoTTTgpkNBtVXo96EQp2m6uwwVh2Kt6YidjkmQqoha';
46
46
  export const SWIFT_ID = 'SW1fThqrxLzVprnCMpiybiqYQfoNCdduC5uWsSUKChS';
47
+ export const ANCHOR_TEST_SWIFT_ID =
48
+ 'DpaEdAPW3ZX67fnczT14AoX12Lx9VMkxvtT81nCHy3Nv';
47
49
 
48
50
  export const DEFAULT_CONFIRMATION_OPTS: ConfirmOptions = {
49
51
  preflightCommitment: 'confirmed',