@metamask/smart-transactions-controller 6.2.2 → 8.0.0

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.
@@ -1,30 +1,44 @@
1
1
  "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
2
7
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
8
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
9
  };
10
+ var _SmartTransactionsController_instances, _SmartTransactionsController_updateSmartTransaction, _SmartTransactionsController_doesTransactionNeedConfirmation, _SmartTransactionsController_confirmSmartTransaction, _SmartTransactionsController_getChainId, _SmartTransactionsController_getEthQuery;
5
11
  Object.defineProperty(exports, "__esModule", { value: true });
6
12
  exports.DEFAULT_INTERVAL = void 0;
7
- const base_controller_1 = require("@metamask/base-controller");
13
+ // eslint-disable-next-line import/no-nodejs-modules
14
+ const bytes_1 = require("@ethersproject/bytes");
8
15
  const controller_utils_1 = require("@metamask/controller-utils");
16
+ const eth_query_1 = __importDefault(require("@metamask/eth-query"));
17
+ const polling_controller_1 = require("@metamask/polling-controller");
18
+ const transaction_controller_1 = require("@metamask/transaction-controller");
9
19
  const bignumber_js_1 = require("bignumber.js");
10
- const bignumber_1 = require("@ethersproject/bignumber");
11
- const providers_1 = require("@ethersproject/providers");
12
- const bytes_1 = require("@ethersproject/bytes");
13
- const mapValues_1 = __importDefault(require("lodash/mapValues"));
20
+ // eslint-disable-next-line import/no-nodejs-modules
21
+ const events_1 = __importDefault(require("events"));
14
22
  const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
23
+ const constants_1 = require("./constants");
15
24
  const types_1 = require("./types");
16
25
  const utils_1 = require("./utils");
17
- const constants_1 = require("./constants");
18
26
  const SECOND = 1000;
19
27
  exports.DEFAULT_INTERVAL = SECOND * 5;
20
- class SmartTransactionsController extends base_controller_1.BaseController {
21
- constructor({ onNetworkStateChange, getNonceLock, provider, confirmExternalTransaction, trackMetaMetricsEvent, }, config, state) {
28
+ const ETH_QUERY_ERROR_MSG = '`ethQuery` is not defined on SmartTransactionsController';
29
+ class SmartTransactionsController extends polling_controller_1.StaticIntervalPollingControllerV1 {
30
+ constructor({ onNetworkStateChange, getNonceLock, provider, confirmExternalTransaction, getTransactions, trackMetaMetricsEvent, getNetworkClientById, }, config, state) {
22
31
  super(config, state);
32
+ _SmartTransactionsController_instances.add(this);
33
+ /**
34
+ * Name of this controller used during composition
35
+ */
36
+ this.name = 'SmartTransactionsController';
23
37
  this.defaultConfig = {
24
38
  interval: exports.DEFAULT_INTERVAL,
25
39
  chainId: constants_1.CHAIN_IDS.ETHEREUM,
26
40
  clientId: 'default',
27
- supportedChainIds: [constants_1.CHAIN_IDS.ETHEREUM, constants_1.CHAIN_IDS.RINKEBY],
41
+ supportedChainIds: [constants_1.CHAIN_IDS.ETHEREUM, constants_1.CHAIN_IDS.GOERLI],
28
42
  };
29
43
  this.defaultState = {
30
44
  smartTransactionsState: {
@@ -36,22 +50,40 @@ class SmartTransactionsController extends base_controller_1.BaseController {
36
50
  tradeTxFees: undefined,
37
51
  },
38
52
  liveness: true,
53
+ livenessByChainId: {
54
+ [constants_1.CHAIN_IDS.ETHEREUM]: true,
55
+ [constants_1.CHAIN_IDS.GOERLI]: true,
56
+ },
57
+ feesByChainId: {
58
+ [constants_1.CHAIN_IDS.ETHEREUM]: {
59
+ approvalTxFees: undefined,
60
+ tradeTxFees: undefined,
61
+ },
62
+ [constants_1.CHAIN_IDS.GOERLI]: {
63
+ approvalTxFees: undefined,
64
+ tradeTxFees: undefined,
65
+ },
66
+ },
39
67
  },
40
68
  };
69
+ this.initialize();
70
+ this.setIntervalLength(this.config.interval);
41
71
  this.getNonceLock = getNonceLock;
42
- this.ethersProvider = new providers_1.Web3Provider(provider);
72
+ this.ethQuery = undefined;
43
73
  this.confirmExternalTransaction = confirmExternalTransaction;
74
+ this.getRegularTransactions = getTransactions;
44
75
  this.trackMetaMetricsEvent = trackMetaMetricsEvent;
45
- this.initialize();
76
+ this.getNetworkClientById = getNetworkClientById;
46
77
  this.initializeSmartTransactionsForChainId();
47
78
  onNetworkStateChange(({ providerConfig: newProvider }) => {
48
79
  const { chainId } = newProvider;
49
80
  this.configure({ chainId });
50
81
  this.initializeSmartTransactionsForChainId();
51
82
  this.checkPoll(this.state);
52
- this.ethersProvider = new providers_1.Web3Provider(provider);
83
+ this.ethQuery = new eth_query_1.default(provider);
53
84
  });
54
85
  this.subscribe((currentState) => this.checkPoll(currentState));
86
+ this.eventEmitter = new events_1.default();
55
87
  }
56
88
  /* istanbul ignore next */
57
89
  async fetch(request, options) {
@@ -59,6 +91,17 @@ class SmartTransactionsController extends base_controller_1.BaseController {
59
91
  const fetchOptions = Object.assign(Object.assign({}, options), { headers: Object.assign({ 'Content-Type': 'application/json' }, (clientId && { 'X-Client-Id': clientId })) });
60
92
  return (0, utils_1.handleFetch)(request, fetchOptions);
61
93
  }
94
+ async _executePoll(networkClientId) {
95
+ // if this is going to be truly UI driven polling we shouldn't really reach here
96
+ // with a networkClientId that is not supported, but for now I'll add a check in case
97
+ // wondering if we should add some kind of predicate to the polling controller to check whether
98
+ // we should poll or not
99
+ const chainId = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getChainId).call(this, { networkClientId });
100
+ if (!this.config.supportedChainIds.includes(chainId)) {
101
+ return Promise.resolve();
102
+ }
103
+ return this.updateSmartTransactions({ networkClientId });
104
+ }
62
105
  checkPoll(state) {
63
106
  const { smartTransactions } = state.smartTransactionsState;
64
107
  const currentSmartTransactions = smartTransactions[this.config.chainId];
@@ -86,9 +129,9 @@ class SmartTransactionsController extends base_controller_1.BaseController {
86
129
  if (!supportedChainIds.includes(chainId)) {
87
130
  return;
88
131
  }
89
- await (0, controller_utils_1.safelyExecute)(() => this.updateSmartTransactions());
132
+ await (0, controller_utils_1.safelyExecute)(async () => this.updateSmartTransactions());
90
133
  this.timeoutHandle = setInterval(() => {
91
- (0, controller_utils_1.safelyExecute)(() => this.updateSmartTransactions());
134
+ (0, controller_utils_1.safelyExecute)(async () => this.updateSmartTransactions());
92
135
  }, this.config.interval);
93
136
  }
94
137
  async stop() {
@@ -121,8 +164,8 @@ class SmartTransactionsController extends base_controller_1.BaseController {
121
164
  stx_user_opt_in: true,
122
165
  };
123
166
  this.trackMetaMetricsEvent({
124
- event: 'STX Status Updated',
125
- category: 'swaps',
167
+ event: constants_1.MetaMetricsEventName.StxStatusUpdated,
168
+ category: constants_1.MetaMetricsEventCategory.Transactions,
126
169
  sensitiveProperties,
127
170
  });
128
171
  }
@@ -134,123 +177,48 @@ class SmartTransactionsController extends base_controller_1.BaseController {
134
177
  const currentIndex = currentSmartTransactions === null || currentSmartTransactions === void 0 ? void 0 : currentSmartTransactions.findIndex((stx) => stx.uuid === smartTransactionUuid);
135
178
  return currentIndex === -1 || currentIndex === undefined;
136
179
  }
137
- updateSmartTransaction(smartTransaction) {
138
- const { chainId } = this.config;
139
- const { smartTransactionsState } = this.state;
140
- const { smartTransactions } = smartTransactionsState;
141
- const currentSmartTransactions = smartTransactions[chainId];
142
- const currentIndex = currentSmartTransactions === null || currentSmartTransactions === void 0 ? void 0 : currentSmartTransactions.findIndex((stx) => stx.uuid === smartTransaction.uuid);
143
- const isNewSmartTransaction = this.isNewSmartTransaction(smartTransaction.uuid);
144
- this.trackStxStatusChange(smartTransaction, isNewSmartTransaction
145
- ? undefined
146
- : currentSmartTransactions[currentIndex]);
147
- if (isNewSmartTransaction) {
148
- // add smart transaction
149
- const cancelledNonceIndex = currentSmartTransactions.findIndex((stx) => {
150
- var _a, _b, _c;
151
- return ((_a = stx.txParams) === null || _a === void 0 ? void 0 : _a.nonce) === ((_b = smartTransaction.txParams) === null || _b === void 0 ? void 0 : _b.nonce) &&
152
- ((_c = stx.status) === null || _c === void 0 ? void 0 : _c.startsWith('cancelled'));
153
- });
154
- const snapshot = (0, cloneDeep_1.default)(smartTransaction);
155
- const history = [snapshot];
156
- const historifiedSmartTransaction = Object.assign(Object.assign({}, smartTransaction), { history });
157
- const nextSmartTransactions = cancelledNonceIndex > -1
158
- ? currentSmartTransactions
159
- .slice(0, cancelledNonceIndex)
160
- .concat(currentSmartTransactions.slice(cancelledNonceIndex + 1))
161
- .concat(historifiedSmartTransaction)
162
- : currentSmartTransactions.concat(historifiedSmartTransaction);
163
- this.update({
164
- smartTransactionsState: Object.assign(Object.assign({}, smartTransactionsState), { smartTransactions: Object.assign(Object.assign({}, smartTransactionsState.smartTransactions), { [chainId]: nextSmartTransactions }) }),
165
- });
166
- return;
167
- }
168
- if ((smartTransaction.status === types_1.SmartTransactionStatuses.SUCCESS ||
169
- smartTransaction.status === types_1.SmartTransactionStatuses.REVERTED) &&
170
- !smartTransaction.confirmed) {
171
- // confirm smart transaction
172
- const currentSmartTransaction = currentSmartTransactions[currentIndex];
173
- const nextSmartTransaction = Object.assign(Object.assign({}, currentSmartTransaction), smartTransaction);
174
- this.confirmSmartTransaction(nextSmartTransaction);
180
+ updateSmartTransaction(smartTransaction, { networkClientId } = {}) {
181
+ let { ethQuery, config: { chainId }, } = this;
182
+ if (networkClientId) {
183
+ const networkClient = this.getNetworkClientById(networkClientId);
184
+ chainId = networkClient.configuration.chainId;
185
+ ethQuery = new eth_query_1.default(networkClient.provider);
175
186
  }
176
- this.update({
177
- smartTransactionsState: Object.assign(Object.assign({}, smartTransactionsState), { smartTransactions: Object.assign(Object.assign({}, smartTransactionsState.smartTransactions), { [chainId]: smartTransactionsState.smartTransactions[chainId].map((item, index) => {
178
- return index === currentIndex
179
- ? Object.assign(Object.assign({}, item), smartTransaction) : item;
180
- }) }) }),
187
+ __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_updateSmartTransaction).call(this, smartTransaction, {
188
+ chainId,
189
+ ethQuery,
181
190
  });
182
191
  }
183
- async updateSmartTransactions() {
192
+ async updateSmartTransactions({ networkClientId, } = {}) {
184
193
  const { smartTransactions } = this.state.smartTransactionsState;
185
- const { chainId } = this.config;
186
- const currentSmartTransactions = smartTransactions === null || smartTransactions === void 0 ? void 0 : smartTransactions[chainId];
187
- const transactionsToUpdate = currentSmartTransactions
194
+ const chainId = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getChainId).call(this, { networkClientId });
195
+ const smartTransactionsForChainId = smartTransactions[chainId];
196
+ const transactionsToUpdate = smartTransactionsForChainId
188
197
  .filter(utils_1.isSmartTransactionPending)
189
198
  .map((smartTransaction) => smartTransaction.uuid);
190
199
  if (transactionsToUpdate.length > 0) {
191
- this.fetchSmartTransactionsStatus(transactionsToUpdate);
192
- }
193
- }
194
- async confirmSmartTransaction(smartTransaction) {
195
- var _a, _b, _c;
196
- const txHash = (_a = smartTransaction.statusMetadata) === null || _a === void 0 ? void 0 : _a.minedHash;
197
- try {
198
- const transactionReceipt = await this.ethersProvider.getTransactionReceipt(txHash);
199
- const transaction = await this.ethersProvider.getTransaction(txHash);
200
- const maxFeePerGas = (_b = transaction.maxFeePerGas) === null || _b === void 0 ? void 0 : _b.toHexString();
201
- const maxPriorityFeePerGas = (_c = transaction.maxPriorityFeePerGas) === null || _c === void 0 ? void 0 : _c.toHexString();
202
- if (transactionReceipt === null || transactionReceipt === void 0 ? void 0 : transactionReceipt.blockNumber) {
203
- const blockData = await this.ethersProvider.getBlock(transactionReceipt === null || transactionReceipt === void 0 ? void 0 : transactionReceipt.blockNumber, false);
204
- const baseFeePerGas = blockData === null || blockData === void 0 ? void 0 : blockData.baseFeePerGas.toHexString();
205
- const txReceipt = (0, mapValues_1.default)(transactionReceipt, (value) => {
206
- if (value instanceof bignumber_1.BigNumber) {
207
- return value.toHexString();
208
- }
209
- return value;
210
- });
211
- const updatedTxParams = Object.assign(Object.assign({}, smartTransaction.txParams), { maxFeePerGas,
212
- maxPriorityFeePerGas });
213
- // call confirmExternalTransaction
214
- const originalTxMeta = Object.assign(Object.assign({}, smartTransaction), { id: smartTransaction.uuid, status: 'confirmed', hash: txHash, txParams: updatedTxParams });
215
- // create txMeta snapshot for history
216
- const snapshot = (0, utils_1.snapshotFromTxMeta)(originalTxMeta);
217
- // recover previous tx state obj
218
- const previousState = (0, utils_1.replayHistory)(originalTxMeta.history);
219
- // generate history entry and add to history
220
- const entry = (0, utils_1.generateHistoryEntry)(previousState, snapshot, 'txStateManager: setting status to confirmed');
221
- const txMeta = entry.length > 0
222
- ? Object.assign(Object.assign({}, originalTxMeta), { history: originalTxMeta.history.concat(entry) }) : originalTxMeta;
223
- this.confirmExternalTransaction(txMeta, txReceipt, baseFeePerGas);
224
- this.trackMetaMetricsEvent({
225
- event: 'STX Confirmed',
226
- category: 'swaps',
227
- });
228
- this.updateSmartTransaction(Object.assign(Object.assign({}, smartTransaction), { confirmed: true }));
229
- }
230
- }
231
- catch (e) {
232
- this.trackMetaMetricsEvent({
233
- event: 'STX Confirmation Failed',
234
- category: 'swaps',
200
+ this.fetchSmartTransactionsStatus(transactionsToUpdate, {
201
+ networkClientId,
235
202
  });
236
- console.error('confirm error', e);
237
203
  }
238
204
  }
239
205
  // ! Ask backend API to accept list of uuids as params
240
- async fetchSmartTransactionsStatus(uuids) {
241
- const { chainId } = this.config;
206
+ async fetchSmartTransactionsStatus(uuids, { networkClientId } = {}) {
242
207
  const params = new URLSearchParams({
243
208
  uuids: uuids.join(','),
244
209
  });
210
+ const chainId = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getChainId).call(this, { networkClientId });
211
+ const ethQuery = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getEthQuery).call(this, { networkClientId });
245
212
  const url = `${(0, utils_1.getAPIRequestURL)(types_1.APIType.BATCH_STATUS, chainId)}?${params.toString()}`;
246
- const data = await this.fetch(url);
213
+ const data = (await this.fetch(url));
247
214
  Object.entries(data).forEach(([uuid, stxStatus]) => {
248
- this.updateSmartTransaction({
215
+ const smartTransaction = {
249
216
  statusMetadata: stxStatus,
250
217
  status: (0, utils_1.calculateStatus)(stxStatus),
251
218
  cancellable: (0, utils_1.isSmartTransactionCancellable)(stxStatus),
252
219
  uuid,
253
- });
220
+ };
221
+ __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_updateSmartTransaction).call(this, smartTransaction, { chainId, ethQuery });
254
222
  });
255
223
  return data;
256
224
  }
@@ -270,8 +238,8 @@ class SmartTransactionsController extends base_controller_1.BaseController {
270
238
  });
271
239
  return fees;
272
240
  }
273
- async getFees(tradeTx, approvalTx) {
274
- const { chainId } = this.config;
241
+ async getFees(tradeTx, approvalTx, { networkClientId } = {}) {
242
+ const chainId = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getChainId).call(this, { networkClientId });
275
243
  const transactions = [];
276
244
  let unsignedTradeTransactionWithNonce;
277
245
  if (approvalTx) {
@@ -281,6 +249,9 @@ class SmartTransactionsController extends base_controller_1.BaseController {
281
249
  // If there is an approval tx, the trade tx's nonce is increased by 1.
282
250
  nonce: (0, utils_1.incrementNonceInHex)(unsignedApprovalTransactionWithNonce.nonce) });
283
251
  }
252
+ else if (tradeTx.nonce) {
253
+ unsignedTradeTransactionWithNonce = tradeTx;
254
+ }
284
255
  else {
285
256
  unsignedTradeTransactionWithNonce = await this.addNonceToTransaction(tradeTx);
286
257
  }
@@ -301,10 +272,15 @@ class SmartTransactionsController extends base_controller_1.BaseController {
301
272
  tradeTxFees = data === null || data === void 0 ? void 0 : data.txs[0];
302
273
  }
303
274
  this.update({
304
- smartTransactionsState: Object.assign(Object.assign({}, this.state.smartTransactionsState), { fees: {
275
+ smartTransactionsState: Object.assign(Object.assign(Object.assign({}, this.state.smartTransactionsState), (chainId === this.config.chainId && {
276
+ fees: {
305
277
  approvalTxFees,
306
278
  tradeTxFees,
307
- } }),
279
+ },
280
+ })), { feesByChainId: Object.assign(Object.assign({}, this.state.smartTransactionsState.feesByChainId), { [chainId]: {
281
+ approvalTxFees,
282
+ tradeTxFees,
283
+ } }) }),
308
284
  });
309
285
  return {
310
286
  approvalTxFees,
@@ -313,8 +289,10 @@ class SmartTransactionsController extends base_controller_1.BaseController {
313
289
  }
314
290
  // * After this successful call client must add a nonce representative to
315
291
  // * transaction controller external transactions list
316
- async submitSignedTransactions({ txParams, signedTransactions, signedCanceledTransactions, }) {
317
- const { chainId } = this.config;
292
+ async submitSignedTransactions({ transactionMeta, txParams, signedTransactions, signedCanceledTransactions, networkClientId, }) {
293
+ var _a;
294
+ const chainId = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getChainId).call(this, { networkClientId });
295
+ const ethQuery = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getEthQuery).call(this, { networkClientId });
318
296
  const data = await this.fetch((0, utils_1.getAPIRequestURL)(types_1.APIType.SUBMIT_TRANSACTIONS, chainId), {
319
297
  method: 'POST',
320
298
  body: JSON.stringify({
@@ -325,57 +303,68 @@ class SmartTransactionsController extends base_controller_1.BaseController {
325
303
  const time = Date.now();
326
304
  let preTxBalance;
327
305
  try {
328
- const preTxBalanceBN = await this.ethersProvider.getBalance(txParams === null || txParams === void 0 ? void 0 : txParams.from);
329
- preTxBalance = new bignumber_js_1.BigNumber(preTxBalanceBN.toHexString()).toString(16);
306
+ const preTxBalanceBN = await (0, controller_utils_1.query)(ethQuery, 'getBalance', [
307
+ txParams === null || txParams === void 0 ? void 0 : txParams.from,
308
+ ]);
309
+ preTxBalance = new bignumber_js_1.BigNumber(preTxBalanceBN).toString(16);
330
310
  }
331
- catch (e) {
332
- console.error('ethers error', e);
311
+ catch (error) {
312
+ console.error('provider error', error);
333
313
  }
334
- const nonceLock = await this.getNonceLock(txParams === null || txParams === void 0 ? void 0 : txParams.from);
335
- try {
336
- const nonce = (0, bytes_1.hexlify)(nonceLock.nextNonce);
337
- if (txParams && !(txParams === null || txParams === void 0 ? void 0 : txParams.nonce)) {
338
- txParams.nonce = nonce;
314
+ const requiresNonce = !txParams.nonce;
315
+ let nonce;
316
+ let nonceLock;
317
+ let nonceDetails = {};
318
+ if (requiresNonce) {
319
+ nonceLock = await this.getNonceLock(txParams === null || txParams === void 0 ? void 0 : txParams.from);
320
+ nonce = (0, bytes_1.hexlify)(nonceLock.nextNonce);
321
+ nonceDetails = nonceLock.nonceDetails;
322
+ if (txParams) {
323
+ (_a = txParams.nonce) !== null && _a !== void 0 ? _a : (txParams.nonce = nonce);
339
324
  }
340
- const { nonceDetails } = nonceLock;
341
- this.updateSmartTransaction({
325
+ }
326
+ const submitTransactionResponse = Object.assign(Object.assign({}, data), { txHash: (0, utils_1.getTxHash)(signedTransactions[0]) });
327
+ try {
328
+ __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_updateSmartTransaction).call(this, {
342
329
  chainId,
343
330
  nonceDetails,
344
331
  preTxBalance,
345
332
  status: types_1.SmartTransactionStatuses.PENDING,
346
333
  time,
347
334
  txParams,
348
- uuid: data.uuid,
335
+ uuid: submitTransactionResponse.uuid,
336
+ txHash: submitTransactionResponse.txHash,
349
337
  cancellable: true,
350
- });
338
+ type: (transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.type) || 'swap',
339
+ }, { chainId, ethQuery });
351
340
  }
352
341
  finally {
353
- nonceLock.releaseLock();
342
+ nonceLock === null || nonceLock === void 0 ? void 0 : nonceLock.releaseLock();
354
343
  }
355
- return data;
344
+ return submitTransactionResponse;
356
345
  }
357
346
  // TODO: This should return if the cancellation was on chain or not (for nonce management)
358
347
  // After this successful call client must update nonce representative
359
348
  // in transaction controller external transactions list
360
- async cancelSmartTransaction(uuid) {
361
- const { chainId } = this.config;
349
+ async cancelSmartTransaction(uuid, { networkClientId, } = {}) {
350
+ const chainId = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getChainId).call(this, { networkClientId });
362
351
  await this.fetch((0, utils_1.getAPIRequestURL)(types_1.APIType.CANCEL, chainId), {
363
352
  method: 'POST',
364
353
  body: JSON.stringify({ uuid }),
365
354
  });
366
355
  }
367
- async fetchLiveness() {
368
- const { chainId } = this.config;
356
+ async fetchLiveness({ networkClientId, } = {}) {
357
+ const chainId = __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_getChainId).call(this, { networkClientId });
369
358
  let liveness = false;
370
359
  try {
371
360
  const response = await this.fetch((0, utils_1.getAPIRequestURL)(types_1.APIType.LIVENESS, chainId));
372
361
  liveness = Boolean(response.lastBlock);
373
362
  }
374
- catch (e) {
363
+ catch (error) {
375
364
  console.log('"fetchLiveness" API call failed');
376
365
  }
377
366
  this.update({
378
- smartTransactionsState: Object.assign(Object.assign({}, this.state.smartTransactionsState), { liveness }),
367
+ smartTransactionsState: Object.assign(Object.assign(Object.assign({}, this.state.smartTransactionsState), (chainId === this.config.chainId && { liveness })), { livenessByChainId: Object.assign(Object.assign({}, this.state.smartTransactionsState.livenessByChainId), { [chainId]: liveness }) }),
379
368
  });
380
369
  return liveness;
381
370
  }
@@ -398,4 +387,130 @@ class SmartTransactionsController extends base_controller_1.BaseController {
398
387
  }
399
388
  }
400
389
  exports.default = SmartTransactionsController;
390
+ _SmartTransactionsController_instances = new WeakSet(), _SmartTransactionsController_updateSmartTransaction = async function _SmartTransactionsController_updateSmartTransaction(smartTransaction, { chainId = this.config.chainId, ethQuery = this.ethQuery, }) {
391
+ var _a;
392
+ const { smartTransactionsState } = this.state;
393
+ const { smartTransactions } = smartTransactionsState;
394
+ const currentSmartTransactions = (_a = smartTransactions[chainId]) !== null && _a !== void 0 ? _a : [];
395
+ const currentIndex = currentSmartTransactions === null || currentSmartTransactions === void 0 ? void 0 : currentSmartTransactions.findIndex((stx) => stx.uuid === smartTransaction.uuid);
396
+ const isNewSmartTransaction = this.isNewSmartTransaction(smartTransaction.uuid);
397
+ if (this.ethQuery === undefined) {
398
+ throw new Error(ETH_QUERY_ERROR_MSG);
399
+ }
400
+ this.trackStxStatusChange(smartTransaction, isNewSmartTransaction
401
+ ? undefined
402
+ : currentSmartTransactions[currentIndex]);
403
+ if (isNewSmartTransaction) {
404
+ // add smart transaction
405
+ const cancelledNonceIndex = currentSmartTransactions === null || currentSmartTransactions === void 0 ? void 0 : currentSmartTransactions.findIndex((stx) => {
406
+ var _a, _b, _c;
407
+ return ((_a = stx.txParams) === null || _a === void 0 ? void 0 : _a.nonce) === ((_b = smartTransaction.txParams) === null || _b === void 0 ? void 0 : _b.nonce) &&
408
+ ((_c = stx.status) === null || _c === void 0 ? void 0 : _c.startsWith('cancelled'));
409
+ });
410
+ const snapshot = (0, cloneDeep_1.default)(smartTransaction);
411
+ const history = [snapshot];
412
+ const historifiedSmartTransaction = Object.assign(Object.assign({}, smartTransaction), { history });
413
+ const nextSmartTransactions = cancelledNonceIndex > -1
414
+ ? currentSmartTransactions
415
+ .slice(0, cancelledNonceIndex)
416
+ .concat(currentSmartTransactions.slice(cancelledNonceIndex + 1))
417
+ .concat(historifiedSmartTransaction)
418
+ : currentSmartTransactions.concat(historifiedSmartTransaction);
419
+ this.update({
420
+ smartTransactionsState: Object.assign(Object.assign({}, smartTransactionsState), { smartTransactions: Object.assign(Object.assign({}, smartTransactionsState.smartTransactions), { [chainId]: nextSmartTransactions }) }),
421
+ });
422
+ return;
423
+ }
424
+ if ((smartTransaction.status === types_1.SmartTransactionStatuses.SUCCESS ||
425
+ smartTransaction.status === types_1.SmartTransactionStatuses.REVERTED) &&
426
+ !smartTransaction.confirmed) {
427
+ // confirm smart transaction
428
+ const currentSmartTransaction = currentSmartTransactions[currentIndex];
429
+ const nextSmartTransaction = Object.assign(Object.assign({}, currentSmartTransaction), smartTransaction);
430
+ await __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_confirmSmartTransaction).call(this, nextSmartTransaction, {
431
+ chainId,
432
+ ethQuery,
433
+ });
434
+ }
435
+ else {
436
+ this.update({
437
+ smartTransactionsState: Object.assign(Object.assign({}, smartTransactionsState), { smartTransactions: Object.assign(Object.assign({}, smartTransactionsState.smartTransactions), { [chainId]: smartTransactionsState.smartTransactions[chainId].map((item, index) => {
438
+ return index === currentIndex
439
+ ? Object.assign(Object.assign({}, item), smartTransaction) : item;
440
+ }) }) }),
441
+ });
442
+ }
443
+ this.eventEmitter.emit(`${smartTransaction.uuid}:smartTransaction`, smartTransaction);
444
+ }, _SmartTransactionsController_doesTransactionNeedConfirmation = function _SmartTransactionsController_doesTransactionNeedConfirmation(txHash) {
445
+ if (!txHash) {
446
+ return true;
447
+ }
448
+ const transactions = this.getRegularTransactions();
449
+ const foundTransaction = transactions === null || transactions === void 0 ? void 0 : transactions.find((tx) => {
450
+ var _a;
451
+ return ((_a = tx.hash) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === txHash.toLowerCase();
452
+ });
453
+ if (!foundTransaction) {
454
+ return true;
455
+ }
456
+ // If a found transaction is either confirmed or submitted, it doesn't need confirmation from the STX controller.
457
+ // When it's in the submitted state, the TransactionController checks its status and confirms it,
458
+ // so no need to confirm it again here.
459
+ return ![transaction_controller_1.TransactionStatus.confirmed, transaction_controller_1.TransactionStatus.submitted].includes(foundTransaction.status);
460
+ }, _SmartTransactionsController_confirmSmartTransaction = async function _SmartTransactionsController_confirmSmartTransaction(smartTransaction, { chainId = this.config.chainId, ethQuery = this.ethQuery, }) {
461
+ var _a;
462
+ if (ethQuery === undefined) {
463
+ throw new Error(ETH_QUERY_ERROR_MSG);
464
+ }
465
+ const txHash = (_a = smartTransaction.statusMetadata) === null || _a === void 0 ? void 0 : _a.minedHash;
466
+ try {
467
+ const transactionReceipt = await (0, controller_utils_1.query)(ethQuery, 'getTransactionReceipt', [txHash]);
468
+ const transaction = await (0, controller_utils_1.query)(ethQuery, 'getTransactionByHash', [txHash]);
469
+ const maxFeePerGas = transaction === null || transaction === void 0 ? void 0 : transaction.maxFeePerGas;
470
+ const maxPriorityFeePerGas = transaction === null || transaction === void 0 ? void 0 : transaction.maxPriorityFeePerGas;
471
+ if (transactionReceipt === null || transactionReceipt === void 0 ? void 0 : transactionReceipt.blockNumber) {
472
+ const blockData = await (0, controller_utils_1.query)(ethQuery, 'getBlockByNumber', [transactionReceipt === null || transactionReceipt === void 0 ? void 0 : transactionReceipt.blockNumber, false]);
473
+ const baseFeePerGas = blockData === null || blockData === void 0 ? void 0 : blockData.baseFeePerGas;
474
+ const updatedTxParams = Object.assign(Object.assign({}, smartTransaction.txParams), { maxFeePerGas,
475
+ maxPriorityFeePerGas });
476
+ // call confirmExternalTransaction
477
+ const originalTxMeta = Object.assign(Object.assign({}, smartTransaction), { id: smartTransaction.uuid, status: transaction_controller_1.TransactionStatus.confirmed, hash: txHash, txParams: updatedTxParams });
478
+ // create txMeta snapshot for history
479
+ const snapshot = (0, utils_1.snapshotFromTxMeta)(originalTxMeta);
480
+ // recover previous tx state obj
481
+ const previousState = (0, utils_1.replayHistory)(originalTxMeta.history);
482
+ // generate history entry and add to history
483
+ const entry = (0, utils_1.generateHistoryEntry)(previousState, snapshot, 'txStateManager: setting status to confirmed');
484
+ const txMeta = entry.length > 0
485
+ ? Object.assign(Object.assign({}, originalTxMeta), { history: originalTxMeta.history.concat(entry) }) : originalTxMeta;
486
+ if (__classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_doesTransactionNeedConfirmation).call(this, txHash)) {
487
+ this.confirmExternalTransaction(txMeta, transactionReceipt, baseFeePerGas);
488
+ }
489
+ this.trackMetaMetricsEvent({
490
+ event: constants_1.MetaMetricsEventName.StxConfirmed,
491
+ category: constants_1.MetaMetricsEventCategory.Transactions,
492
+ });
493
+ __classPrivateFieldGet(this, _SmartTransactionsController_instances, "m", _SmartTransactionsController_updateSmartTransaction).call(this, Object.assign(Object.assign({}, smartTransaction), { confirmed: true }), { chainId, ethQuery });
494
+ }
495
+ }
496
+ catch (error) {
497
+ this.trackMetaMetricsEvent({
498
+ event: constants_1.MetaMetricsEventName.StxConfirmationFailed,
499
+ category: constants_1.MetaMetricsEventCategory.Transactions,
500
+ });
501
+ console.error('confirm error', error);
502
+ }
503
+ }, _SmartTransactionsController_getChainId = function _SmartTransactionsController_getChainId({ networkClientId, } = {}) {
504
+ return networkClientId
505
+ ? this.getNetworkClientById(networkClientId).configuration.chainId
506
+ : this.config.chainId;
507
+ }, _SmartTransactionsController_getEthQuery = function _SmartTransactionsController_getEthQuery({ networkClientId, } = {}) {
508
+ if (networkClientId) {
509
+ return new eth_query_1.default(this.getNetworkClientById(networkClientId).provider);
510
+ }
511
+ if (this.ethQuery === undefined) {
512
+ throw new Error(ETH_QUERY_ERROR_MSG);
513
+ }
514
+ return this.ethQuery;
515
+ };
401
516
  //# sourceMappingURL=SmartTransactionsController.js.map