@metamask/transaction-controller 16.0.0 → 18.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.
- package/CHANGELOG.md +66 -1
- package/dist/TransactionController.d.ts +184 -21
- package/dist/TransactionController.d.ts.map +1 -1
- package/dist/TransactionController.js +635 -121
- package/dist/TransactionController.js.map +1 -1
- package/dist/constants.d.ts +2 -3
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -15
- package/dist/constants.js.map +1 -1
- package/dist/helpers/PendingTransactionTracker.d.ts +23 -5
- package/dist/helpers/PendingTransactionTracker.d.ts.map +1 -1
- package/dist/helpers/PendingTransactionTracker.js +263 -108
- package/dist/helpers/PendingTransactionTracker.js.map +1 -1
- package/dist/logger.d.ts +0 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -2
- package/dist/logger.js.map +1 -1
- package/dist/types.d.ts +225 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/etherscan.d.ts.map +1 -1
- package/dist/utils/etherscan.js.map +1 -1
- package/dist/utils/gas-fees.d.ts +3 -2
- package/dist/utils/gas-fees.d.ts.map +1 -1
- package/dist/utils/gas-fees.js +22 -4
- package/dist/utils/gas-fees.js.map +1 -1
- package/dist/utils/gas.d.ts +2 -0
- package/dist/utils/gas.d.ts.map +1 -1
- package/dist/utils/gas.js +26 -17
- package/dist/utils/gas.js.map +1 -1
- package/dist/utils/swaps.d.ts +81 -0
- package/dist/utils/swaps.d.ts.map +1 -0
- package/dist/utils/swaps.js +253 -0
- package/dist/utils/swaps.js.map +1 -0
- package/dist/utils/utils.d.ts +21 -3
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +45 -4
- package/dist/utils/utils.js.map +1 -1
- package/dist/utils/validation.d.ts +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +90 -7
- package/dist/utils/validation.js.map +1 -1
- package/package.json +16 -15
|
@@ -24,7 +24,7 @@ const eth_method_registry_1 = __importDefault(require("eth-method-registry"));
|
|
|
24
24
|
const ethereumjs_util_1 = require("ethereumjs-util");
|
|
25
25
|
const events_1 = require("events");
|
|
26
26
|
const lodash_1 = require("lodash");
|
|
27
|
-
const nonce_tracker_1 =
|
|
27
|
+
const nonce_tracker_1 = require("nonce-tracker");
|
|
28
28
|
const uuid_1 = require("uuid");
|
|
29
29
|
const EtherscanRemoteTransactionSource_1 = require("./helpers/EtherscanRemoteTransactionSource");
|
|
30
30
|
const IncomingTransactionHelper_1 = require("./helpers/IncomingTransactionHelper");
|
|
@@ -35,6 +35,7 @@ const external_transactions_1 = require("./utils/external-transactions");
|
|
|
35
35
|
const gas_1 = require("./utils/gas");
|
|
36
36
|
const gas_fees_1 = require("./utils/gas-fees");
|
|
37
37
|
const history_1 = require("./utils/history");
|
|
38
|
+
const swaps_1 = require("./utils/swaps");
|
|
38
39
|
const transaction_type_1 = require("./utils/transaction-type");
|
|
39
40
|
const utils_1 = require("./utils/utils");
|
|
40
41
|
const validation_1 = require("./utils/validation");
|
|
@@ -54,7 +55,7 @@ const controllerName = 'TransactionController';
|
|
|
54
55
|
/**
|
|
55
56
|
* Controller responsible for submitting and managing transactions.
|
|
56
57
|
*/
|
|
57
|
-
class TransactionController extends base_controller_1.
|
|
58
|
+
class TransactionController extends base_controller_1.BaseControllerV1 {
|
|
58
59
|
/**
|
|
59
60
|
* Creates a TransactionController instance.
|
|
60
61
|
*
|
|
@@ -62,6 +63,8 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
62
63
|
* @param options.blockTracker - The block tracker used to poll for new blocks data.
|
|
63
64
|
* @param options.disableHistory - Whether to disable storing history in transaction metadata.
|
|
64
65
|
* @param options.disableSendFlowHistory - Explicitly disable transaction metadata history.
|
|
66
|
+
* @param options.disableSwaps - Whether to disable additional processing on swaps transactions.
|
|
67
|
+
* @param options.getSavedGasFees - Gets the saved gas fee config.
|
|
65
68
|
* @param options.getCurrentAccountEIP1559Compatibility - Whether or not the account supports EIP-1559.
|
|
66
69
|
* @param options.getCurrentNetworkEIP1559Compatibility - Whether or not the network supports EIP-1559.
|
|
67
70
|
* @param options.getGasFeeEstimates - Callback to retrieve gas fee estimates.
|
|
@@ -75,13 +78,23 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
75
78
|
* @param options.incomingTransactions.updateTransactions - Whether to update local transactions using remote transaction data.
|
|
76
79
|
* @param options.messenger - The controller messenger.
|
|
77
80
|
* @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
|
|
81
|
+
* @param options.pendingTransactions - Configuration options for pending transaction support.
|
|
82
|
+
* @param options.pendingTransactions.isResubmitEnabled - Whether transaction publishing is automatically retried.
|
|
78
83
|
* @param options.provider - The provider used to create the underlying EthQuery instance.
|
|
79
84
|
* @param options.securityProviderRequest - A function for verifying a transaction, whether it is malicious or not.
|
|
85
|
+
* @param options.hooks - The controller hooks.
|
|
86
|
+
* @param options.hooks.afterSign - Additional logic to execute after signing a transaction. Return false to not change the status to signed.
|
|
87
|
+
* @param options.hooks.beforeApproveOnInit - Additional logic to execute before starting an approval flow for a transaction during initialization. Return false to skip the transaction.
|
|
88
|
+
* @param options.hooks.beforeCheckPendingTransaction - Additional logic to execute before checking pending transactions. Return false to prevent the broadcast of the transaction.
|
|
89
|
+
* @param options.hooks.beforePublish - Additional logic to execute before publishing a transaction. Return false to prevent the broadcast of the transaction.
|
|
90
|
+
* @param options.hooks.getAdditionalSignArguments - Returns additional arguments required to sign a transaction.
|
|
80
91
|
* @param config - Initial options used to configure this controller.
|
|
81
92
|
* @param state - Initial state to set on this controller.
|
|
82
93
|
*/
|
|
83
|
-
constructor({ blockTracker, disableHistory, disableSendFlowHistory, getCurrentAccountEIP1559Compatibility, getCurrentNetworkEIP1559Compatibility, getGasFeeEstimates, getNetworkState, getPermittedAccounts, getSelectedAddress, incomingTransactions = {}, messenger, onNetworkStateChange, provider, securityProviderRequest, }, config, state) {
|
|
94
|
+
constructor({ blockTracker, disableHistory, disableSendFlowHistory, disableSwaps, getSavedGasFees, getCurrentAccountEIP1559Compatibility, getCurrentNetworkEIP1559Compatibility, getGasFeeEstimates, getNetworkState, getPermittedAccounts, getSelectedAddress, incomingTransactions = {}, messenger, onNetworkStateChange, pendingTransactions = {}, provider, securityProviderRequest, hooks = {}, }, config, state) {
|
|
95
|
+
var _a, _b, _c, _d, _e;
|
|
84
96
|
super(config, state);
|
|
97
|
+
this.inProcessOfSigning = new Set();
|
|
85
98
|
this.mutex = new async_mutex_1.Mutex();
|
|
86
99
|
/**
|
|
87
100
|
* EventEmitter instance used to listen to specific transactional events
|
|
@@ -103,13 +116,14 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
103
116
|
this.provider = provider;
|
|
104
117
|
this.messagingSystem = messenger;
|
|
105
118
|
this.getNetworkState = getNetworkState;
|
|
106
|
-
// @ts-expect-error TODO: Provider type alignment
|
|
107
119
|
this.ethQuery = new eth_query_1.default(provider);
|
|
108
120
|
this.isSendFlowHistoryDisabled = disableSendFlowHistory !== null && disableSendFlowHistory !== void 0 ? disableSendFlowHistory : false;
|
|
109
121
|
this.isHistoryDisabled = disableHistory !== null && disableHistory !== void 0 ? disableHistory : false;
|
|
122
|
+
this.isSwapsDisabled = disableSwaps !== null && disableSwaps !== void 0 ? disableSwaps : false;
|
|
110
123
|
this.registry = new eth_method_registry_1.default({ provider });
|
|
124
|
+
this.getSavedGasFees = getSavedGasFees !== null && getSavedGasFees !== void 0 ? getSavedGasFees : ((_chainId) => undefined);
|
|
111
125
|
this.getCurrentAccountEIP1559Compatibility =
|
|
112
|
-
getCurrentAccountEIP1559Compatibility;
|
|
126
|
+
getCurrentAccountEIP1559Compatibility !== null && getCurrentAccountEIP1559Compatibility !== void 0 ? getCurrentAccountEIP1559Compatibility : (() => Promise.resolve(true));
|
|
113
127
|
this.getCurrentNetworkEIP1559Compatibility =
|
|
114
128
|
getCurrentNetworkEIP1559Compatibility;
|
|
115
129
|
this.getGasFeeEstimates =
|
|
@@ -117,11 +131,21 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
117
131
|
this.getPermittedAccounts = getPermittedAccounts;
|
|
118
132
|
this.getSelectedAddress = getSelectedAddress;
|
|
119
133
|
this.securityProviderRequest = securityProviderRequest;
|
|
120
|
-
this.
|
|
134
|
+
this.afterSign = (_a = hooks === null || hooks === void 0 ? void 0 : hooks.afterSign) !== null && _a !== void 0 ? _a : (() => true);
|
|
135
|
+
this.beforeApproveOnInit = (_b = hooks === null || hooks === void 0 ? void 0 : hooks.beforeApproveOnInit) !== null && _b !== void 0 ? _b : (() => true);
|
|
136
|
+
this.beforeCheckPendingTransaction =
|
|
137
|
+
(_c = hooks === null || hooks === void 0 ? void 0 : hooks.beforeCheckPendingTransaction) !== null && _c !== void 0 ? _c :
|
|
138
|
+
/* istanbul ignore next */
|
|
139
|
+
(() => true);
|
|
140
|
+
this.beforePublish = (_d = hooks === null || hooks === void 0 ? void 0 : hooks.beforePublish) !== null && _d !== void 0 ? _d : (() => true);
|
|
141
|
+
this.getAdditionalSignArguments =
|
|
142
|
+
(_e = hooks === null || hooks === void 0 ? void 0 : hooks.getAdditionalSignArguments) !== null && _e !== void 0 ? _e : (() => []);
|
|
143
|
+
this.nonceTracker = new nonce_tracker_1.NonceTracker({
|
|
144
|
+
// @ts-expect-error provider types misaligned: SafeEventEmitterProvider vs Record<string,string>
|
|
121
145
|
provider,
|
|
122
146
|
blockTracker,
|
|
123
|
-
getPendingTransactions:
|
|
124
|
-
getConfirmedTransactions:
|
|
147
|
+
getPendingTransactions: this.getNonceTrackerTransactions.bind(this, types_1.TransactionStatus.submitted),
|
|
148
|
+
getConfirmedTransactions: this.getNonceTrackerTransactions.bind(this, types_1.TransactionStatus.confirmed),
|
|
125
149
|
});
|
|
126
150
|
this.incomingTransactionHelper = new IncomingTransactionHelper_1.IncomingTransactionHelper({
|
|
127
151
|
blockTracker,
|
|
@@ -139,25 +163,37 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
139
163
|
this.incomingTransactionHelper.hub.on('transactions', this.onIncomingTransactions.bind(this));
|
|
140
164
|
this.incomingTransactionHelper.hub.on('updatedLastFetchedBlockNumbers', this.onUpdatedLastFetchedBlockNumbers.bind(this));
|
|
141
165
|
this.pendingTransactionTracker = new PendingTransactionTracker_1.PendingTransactionTracker({
|
|
166
|
+
approveTransaction: this.approveTransaction.bind(this),
|
|
142
167
|
blockTracker,
|
|
143
|
-
failTransaction: this.failTransaction.bind(this),
|
|
144
168
|
getChainId: this.getChainId.bind(this),
|
|
145
169
|
getEthQuery: () => this.ethQuery,
|
|
146
170
|
getTransactions: () => this.state.transactions,
|
|
171
|
+
isResubmitEnabled: pendingTransactions.isResubmitEnabled,
|
|
147
172
|
nonceTracker: this.nonceTracker,
|
|
173
|
+
onStateChange: this.subscribe.bind(this),
|
|
174
|
+
publishTransaction: this.publishTransaction.bind(this),
|
|
175
|
+
hooks: {
|
|
176
|
+
beforeCheckPendingTransaction: this.beforeCheckPendingTransaction.bind(this),
|
|
177
|
+
beforePublish: this.beforePublish.bind(this),
|
|
178
|
+
},
|
|
148
179
|
});
|
|
149
|
-
this.
|
|
150
|
-
this.pendingTransactionTracker.hub.on('transaction-confirmed', (transactionMeta) => this.hub.emit(`${transactionMeta.id}:confirmed`, transactionMeta));
|
|
180
|
+
this.addPendingTransactionTrackerListeners();
|
|
151
181
|
onNetworkStateChange(() => {
|
|
152
|
-
// @ts-expect-error TODO: Provider type alignment
|
|
153
182
|
this.ethQuery = new eth_query_1.default(this.provider);
|
|
154
183
|
this.registry = new eth_method_registry_1.default({ provider: this.provider });
|
|
184
|
+
this.onBootCleanup();
|
|
155
185
|
});
|
|
156
|
-
this.
|
|
186
|
+
this.onBootCleanup();
|
|
157
187
|
}
|
|
158
|
-
failTransaction(transactionMeta, error) {
|
|
159
|
-
const newTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { error, status: types_1.TransactionStatus.failed });
|
|
188
|
+
failTransaction(transactionMeta, error, actionId) {
|
|
189
|
+
const newTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { error: (0, utils_1.normalizeTxError)(error), status: types_1.TransactionStatus.failed });
|
|
190
|
+
this.hub.emit('transaction-failed', {
|
|
191
|
+
actionId,
|
|
192
|
+
error: error.message,
|
|
193
|
+
transactionMeta: newTransactionMeta,
|
|
194
|
+
});
|
|
160
195
|
this.updateTransaction(newTransactionMeta, 'TransactionController#failTransaction - Add error message and set status to failed');
|
|
196
|
+
this.onTransactionStatusChange(newTransactionMeta);
|
|
161
197
|
this.hub.emit(`${transactionMeta.id}:finished`, newTransactionMeta);
|
|
162
198
|
}
|
|
163
199
|
registryLookup(fourBytePrefix) {
|
|
@@ -208,12 +244,14 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
208
244
|
* @param opts.securityAlertResponse - Response from security validator.
|
|
209
245
|
* @param opts.sendFlowHistory - The sendFlowHistory entries to add.
|
|
210
246
|
* @param opts.type - Type of transaction to add, such as 'cancel' or 'swap'.
|
|
247
|
+
* @param opts.swaps - Options for swaps transactions.
|
|
248
|
+
* @param opts.swaps.hasApproveTx - Whether the transaction has an approval transaction.
|
|
249
|
+
* @param opts.swaps.meta - Metadata for swap transaction.
|
|
211
250
|
* @returns Object containing a promise resolving to the transaction hash if approved.
|
|
212
251
|
*/
|
|
213
|
-
addTransaction(txParams, { actionId, deviceConfirmedOn, method, origin, requireApproval, securityAlertResponse, sendFlowHistory, type, } = {}) {
|
|
252
|
+
addTransaction(txParams, { actionId, deviceConfirmedOn, method, origin, requireApproval, securityAlertResponse, sendFlowHistory, swaps = {}, type, } = {}) {
|
|
214
253
|
return __awaiter(this, void 0, void 0, function* () {
|
|
215
|
-
|
|
216
|
-
const { transactions } = this.state;
|
|
254
|
+
(0, logger_1.projectLogger)('Adding transaction', txParams);
|
|
217
255
|
txParams = (0, utils_1.normalizeTxParams)(txParams);
|
|
218
256
|
const isEIP1559Compatible = yield this.getEIP1559Compatibility();
|
|
219
257
|
(0, validation_1.validateTxParams)(txParams, isEIP1559Compatible);
|
|
@@ -223,6 +261,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
223
261
|
const dappSuggestedGasFees = this.generateDappSuggestedGasFees(txParams, origin);
|
|
224
262
|
const transactionType = type !== null && type !== void 0 ? type : (yield (0, transaction_type_1.determineTransactionType)(txParams, this.ethQuery)).type;
|
|
225
263
|
const existingTransactionMeta = this.getTransactionWithActionId(actionId);
|
|
264
|
+
const chainId = this.getChainId();
|
|
226
265
|
// If a request to add a transaction with the same actionId is submitted again, a new transaction will not be created for it.
|
|
227
266
|
const transactionMeta = existingTransactionMeta || {
|
|
228
267
|
// Add actionId to txMeta to check if same actionId is seen again
|
|
@@ -240,17 +279,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
240
279
|
verifiedOnBlockchain: false,
|
|
241
280
|
type: transactionType,
|
|
242
281
|
};
|
|
243
|
-
yield (
|
|
244
|
-
ethQuery: this.ethQuery,
|
|
245
|
-
providerConfig: this.getNetworkState().providerConfig,
|
|
246
|
-
txMeta: transactionMeta,
|
|
247
|
-
});
|
|
248
|
-
yield (0, gas_fees_1.updateGasFees)({
|
|
249
|
-
eip1559: isEIP1559Compatible,
|
|
250
|
-
ethQuery: this.ethQuery,
|
|
251
|
-
getGasFeeEstimates: this.getGasFeeEstimates.bind(this),
|
|
252
|
-
txMeta: transactionMeta,
|
|
253
|
-
});
|
|
282
|
+
yield this.updateGasProperties(transactionMeta);
|
|
254
283
|
// Checks if a transaction already exists with a given actionId
|
|
255
284
|
if (!existingTransactionMeta) {
|
|
256
285
|
// Set security provider response
|
|
@@ -265,16 +294,19 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
265
294
|
if (!this.isHistoryDisabled) {
|
|
266
295
|
(0, history_1.addInitialHistorySnapshot)(transactionMeta);
|
|
267
296
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
297
|
+
yield (0, swaps_1.updateSwapsTransaction)(transactionMeta, transactionType, swaps, {
|
|
298
|
+
isSwapsDisabled: this.isSwapsDisabled,
|
|
299
|
+
cancelTransaction: this.cancelTransaction.bind(this),
|
|
300
|
+
controllerHubEmitter: this.hub.emit.bind(this.hub),
|
|
271
301
|
});
|
|
302
|
+
this.addMetadata(transactionMeta);
|
|
272
303
|
this.hub.emit(`unapprovedTransaction`, transactionMeta);
|
|
273
304
|
}
|
|
274
305
|
return {
|
|
275
306
|
result: this.processApproval(transactionMeta, {
|
|
276
307
|
isExisting: Boolean(existingTransactionMeta),
|
|
277
308
|
requireApproval,
|
|
309
|
+
actionId,
|
|
278
310
|
}),
|
|
279
311
|
transactionMeta,
|
|
280
312
|
};
|
|
@@ -291,22 +323,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
291
323
|
yield this.incomingTransactionHelper.update();
|
|
292
324
|
});
|
|
293
325
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Creates approvals for all unapproved transactions persisted.
|
|
296
|
-
*/
|
|
297
|
-
initApprovals() {
|
|
298
|
-
const chainId = this.getChainId();
|
|
299
|
-
const unapprovedTxs = this.state.transactions.filter((transaction) => transaction.status === types_1.TransactionStatus.unapproved &&
|
|
300
|
-
transaction.chainId === chainId);
|
|
301
|
-
for (const txMeta of unapprovedTxs) {
|
|
302
|
-
this.processApproval(txMeta, {
|
|
303
|
-
shouldShowRequest: false,
|
|
304
|
-
}).catch((error) => {
|
|
305
|
-
/* istanbul ignore next */
|
|
306
|
-
console.error('Error during persisted transaction approval', error);
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
326
|
/**
|
|
311
327
|
* Attempts to cancel a transaction based on its ID by setting its status to "rejected"
|
|
312
328
|
* and emitting a `<tx.id>:finished` hub event.
|
|
@@ -314,15 +330,22 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
314
330
|
* @param transactionId - The ID of the transaction to cancel.
|
|
315
331
|
* @param gasValues - The gas values to use for the cancellation transaction.
|
|
316
332
|
* @param options - The options for the cancellation transaction.
|
|
333
|
+
* @param options.actionId - Unique ID to prevent duplicate requests.
|
|
317
334
|
* @param options.estimatedBaseFee - The estimated base fee of the transaction.
|
|
318
335
|
*/
|
|
319
|
-
stopTransaction(transactionId, gasValues, { estimatedBaseFee } = {}) {
|
|
336
|
+
stopTransaction(transactionId, gasValues, { estimatedBaseFee, actionId, } = {}) {
|
|
320
337
|
var _a, _b;
|
|
321
338
|
return __awaiter(this, void 0, void 0, function* () {
|
|
339
|
+
// If transaction is found for same action id, do not create a cancel transaction.
|
|
340
|
+
if (this.getTransactionWithActionId(actionId)) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
322
343
|
if (gasValues) {
|
|
344
|
+
// Not good practice to reassign a parameter but temporarily avoiding a larger refactor.
|
|
345
|
+
gasValues = (0, utils_1.normalizeGasFeeValues)(gasValues);
|
|
323
346
|
(0, utils_1.validateGasValues)(gasValues);
|
|
324
347
|
}
|
|
325
|
-
const transactionMeta = this.
|
|
348
|
+
const transactionMeta = this.getTransaction(transactionId);
|
|
326
349
|
if (!transactionMeta) {
|
|
327
350
|
return;
|
|
328
351
|
}
|
|
@@ -349,13 +372,13 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
349
372
|
const newMaxPriorityFeePerGas = (maxPriorityFeePerGasValues &&
|
|
350
373
|
(0, utils_1.validateMinimumIncrease)(maxPriorityFeePerGasValues, minMaxPriorityFeePerGas)) ||
|
|
351
374
|
(existingMaxPriorityFeePerGas && minMaxPriorityFeePerGas);
|
|
352
|
-
const
|
|
375
|
+
const newTxParams = newMaxFeePerGas && newMaxPriorityFeePerGas
|
|
353
376
|
? {
|
|
354
377
|
from: transactionMeta.txParams.from,
|
|
355
378
|
gasLimit: transactionMeta.txParams.gas,
|
|
356
379
|
maxFeePerGas: newMaxFeePerGas,
|
|
357
380
|
maxPriorityFeePerGas: newMaxPriorityFeePerGas,
|
|
358
|
-
type:
|
|
381
|
+
type: types_1.TransactionEnvelopeType.feeMarket,
|
|
359
382
|
nonce: transactionMeta.txParams.nonce,
|
|
360
383
|
to: transactionMeta.txParams.from,
|
|
361
384
|
value: '0x0',
|
|
@@ -368,14 +391,33 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
368
391
|
to: transactionMeta.txParams.from,
|
|
369
392
|
value: '0x0',
|
|
370
393
|
};
|
|
371
|
-
const unsignedEthTx = this.prepareUnsignedEthTx(
|
|
394
|
+
const unsignedEthTx = this.prepareUnsignedEthTx(newTxParams);
|
|
372
395
|
const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
|
|
373
|
-
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
374
396
|
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
375
|
-
yield
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
397
|
+
const hash = yield this.publishTransaction(rawTx);
|
|
398
|
+
const cancelTransactionMeta = {
|
|
399
|
+
actionId,
|
|
400
|
+
chainId: transactionMeta.chainId,
|
|
401
|
+
estimatedBaseFee,
|
|
402
|
+
hash,
|
|
403
|
+
id: (0, uuid_1.v1)(),
|
|
404
|
+
originalGasEstimate: transactionMeta.txParams.gas,
|
|
405
|
+
status: types_1.TransactionStatus.submitted,
|
|
406
|
+
time: Date.now(),
|
|
407
|
+
type: types_1.TransactionType.cancel,
|
|
408
|
+
txParams: newTxParams,
|
|
409
|
+
};
|
|
410
|
+
this.addMetadata(cancelTransactionMeta);
|
|
411
|
+
// stopTransaction has no approval request, so we assume the user has already approved the transaction
|
|
412
|
+
this.hub.emit('transaction-approved', {
|
|
413
|
+
transactionMeta: cancelTransactionMeta,
|
|
414
|
+
actionId,
|
|
415
|
+
});
|
|
416
|
+
this.hub.emit('transaction-submitted', {
|
|
417
|
+
transactionMeta: cancelTransactionMeta,
|
|
418
|
+
actionId,
|
|
419
|
+
});
|
|
420
|
+
this.hub.emit(`${cancelTransactionMeta.id}:finished`, cancelTransactionMeta);
|
|
379
421
|
});
|
|
380
422
|
}
|
|
381
423
|
/**
|
|
@@ -395,6 +437,8 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
395
437
|
return;
|
|
396
438
|
}
|
|
397
439
|
if (gasValues) {
|
|
440
|
+
// Not good practice to reassign a parameter but temporarily avoiding a larger refactor.
|
|
441
|
+
gasValues = (0, utils_1.normalizeGasFeeValues)(gasValues);
|
|
398
442
|
(0, utils_1.validateGasValues)(gasValues);
|
|
399
443
|
}
|
|
400
444
|
const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
|
|
@@ -406,7 +450,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
406
450
|
if (!this.sign) {
|
|
407
451
|
throw new Error('No sign method defined.');
|
|
408
452
|
}
|
|
409
|
-
const { transactions } = this.state;
|
|
410
453
|
// gasPrice (legacy non EIP1559)
|
|
411
454
|
const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.txParams.gasPrice, exports.SPEED_UP_RATE);
|
|
412
455
|
const gasPriceFromValues = (0, utils_1.isGasPriceValue)(gasValues) && gasValues.gasPrice;
|
|
@@ -428,18 +471,26 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
428
471
|
(0, utils_1.validateMinimumIncrease)(maxPriorityFeePerGasValues, minMaxPriorityFeePerGas)) ||
|
|
429
472
|
(existingMaxPriorityFeePerGas && minMaxPriorityFeePerGas);
|
|
430
473
|
const txParams = newMaxFeePerGas && newMaxPriorityFeePerGas
|
|
431
|
-
? Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas, type:
|
|
474
|
+
? Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas, type: types_1.TransactionEnvelopeType.feeMarket }) : Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, gasPrice: newGasPrice });
|
|
432
475
|
const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
|
|
433
476
|
const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
|
|
434
477
|
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
435
478
|
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
436
479
|
const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
|
|
437
480
|
const baseTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), hash,
|
|
438
|
-
actionId, originalGasEstimate: transactionMeta.txParams.gas, type: types_1.TransactionType.retry });
|
|
481
|
+
actionId, originalGasEstimate: transactionMeta.txParams.gas, type: types_1.TransactionType.retry, originalType: transactionMeta.type });
|
|
439
482
|
const newTransactionMeta = newMaxFeePerGas && newMaxPriorityFeePerGas
|
|
440
483
|
? Object.assign(Object.assign({}, baseTransactionMeta), { txParams: Object.assign(Object.assign({}, transactionMeta.txParams), { maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas }) }) : Object.assign(Object.assign({}, baseTransactionMeta), { txParams: Object.assign(Object.assign({}, transactionMeta.txParams), { gasPrice: newGasPrice }) });
|
|
441
|
-
|
|
442
|
-
|
|
484
|
+
this.addMetadata(newTransactionMeta);
|
|
485
|
+
// speedUpTransaction has no approval request, so we assume the user has already approved the transaction
|
|
486
|
+
this.hub.emit('transaction-approved', {
|
|
487
|
+
transactionMeta: newTransactionMeta,
|
|
488
|
+
actionId,
|
|
489
|
+
});
|
|
490
|
+
this.hub.emit('transaction-submitted', {
|
|
491
|
+
transactionMeta: newTransactionMeta,
|
|
492
|
+
actionId,
|
|
493
|
+
});
|
|
443
494
|
this.hub.emit(`${transactionMeta.id}:speedup`, newTransactionMeta);
|
|
444
495
|
});
|
|
445
496
|
}
|
|
@@ -455,6 +506,22 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
455
506
|
return { gas: estimatedGas, simulationFails };
|
|
456
507
|
});
|
|
457
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* Estimates required gas for a given transaction and add additional gas buffer with the given multiplier.
|
|
511
|
+
*
|
|
512
|
+
* @param transaction - The transaction params to estimate gas for.
|
|
513
|
+
* @param multiplier - The multiplier to use for the gas buffer.
|
|
514
|
+
*/
|
|
515
|
+
estimateGasBuffered(transaction, multiplier) {
|
|
516
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
517
|
+
const { blockGasLimit, estimatedGas, simulationFails } = yield (0, gas_1.estimateGas)(transaction, this.ethQuery);
|
|
518
|
+
const gas = (0, gas_1.addGasBuffer)(estimatedGas, blockGasLimit, multiplier);
|
|
519
|
+
return {
|
|
520
|
+
gas,
|
|
521
|
+
simulationFails,
|
|
522
|
+
};
|
|
523
|
+
});
|
|
524
|
+
}
|
|
458
525
|
/**
|
|
459
526
|
* Updates an existing transaction in state.
|
|
460
527
|
*
|
|
@@ -472,6 +539,23 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
472
539
|
transactions[index] = transactionMeta;
|
|
473
540
|
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
474
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* Update the security alert response for a transaction.
|
|
544
|
+
*
|
|
545
|
+
* @param transactionId - ID of the transaction.
|
|
546
|
+
* @param securityAlertResponse - The new security alert response for the transaction.
|
|
547
|
+
*/
|
|
548
|
+
updateSecurityAlertResponse(transactionId, securityAlertResponse) {
|
|
549
|
+
if (!securityAlertResponse) {
|
|
550
|
+
throw new Error('updateSecurityAlertResponse: securityAlertResponse should not be null');
|
|
551
|
+
}
|
|
552
|
+
const transactionMeta = this.getTransaction(transactionId);
|
|
553
|
+
if (!transactionMeta) {
|
|
554
|
+
throw new Error(`Cannot update security alert response as no transaction metadata found`);
|
|
555
|
+
}
|
|
556
|
+
const updatedMeta = (0, lodash_1.merge)(transactionMeta, { securityAlertResponse });
|
|
557
|
+
this.updateTransaction(updatedMeta, 'TransactionController:updatesecurityAlertResponse - securityAlertResponse updated');
|
|
558
|
+
}
|
|
475
559
|
/**
|
|
476
560
|
* Removes all transactions from state, optionally based on the current network.
|
|
477
561
|
*
|
|
@@ -529,9 +613,16 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
529
613
|
this.markNonceDuplicatesDropped(transactionId);
|
|
530
614
|
// Update external provided transaction with updated gas values and confirmed status.
|
|
531
615
|
this.updateTransaction(transactionMeta, 'TransactionController:confirmExternalTransaction - Add external transaction');
|
|
616
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
617
|
+
// Intentional given potential duration of process.
|
|
618
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
619
|
+
this.updatePostBalance(transactionMeta);
|
|
620
|
+
this.hub.emit('transaction-confirmed', {
|
|
621
|
+
transactionMeta,
|
|
622
|
+
});
|
|
532
623
|
}
|
|
533
624
|
catch (error) {
|
|
534
|
-
console.error(error);
|
|
625
|
+
console.error('Failed to confirm external transaction', error);
|
|
535
626
|
}
|
|
536
627
|
});
|
|
537
628
|
}
|
|
@@ -610,6 +701,36 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
610
701
|
this.updateTransaction(updatedMeta, 'TransactionController:updateTransactionGasFees - gas values updated');
|
|
611
702
|
return this.getTransaction(transactionId);
|
|
612
703
|
}
|
|
704
|
+
/**
|
|
705
|
+
* Update the previous gas values of a transaction.
|
|
706
|
+
*
|
|
707
|
+
* @param transactionId - The ID of the transaction to update.
|
|
708
|
+
* @param previousGas - Previous gas values to update.
|
|
709
|
+
* @param previousGas.gasLimit - Maxmimum number of units of gas to use for this transaction.
|
|
710
|
+
* @param previousGas.maxFeePerGas - Maximum amount per gas to pay for the transaction, including the priority fee.
|
|
711
|
+
* @param previousGas.maxPriorityFeePerGas - Maximum amount per gas to give to validator as incentive.
|
|
712
|
+
* @returns The updated transactionMeta.
|
|
713
|
+
*/
|
|
714
|
+
updatePreviousGasParams(transactionId, { gasLimit, maxFeePerGas, maxPriorityFeePerGas, }) {
|
|
715
|
+
const transactionMeta = this.getTransaction(transactionId);
|
|
716
|
+
if (!transactionMeta) {
|
|
717
|
+
throw new Error(`Cannot update transaction as no transaction metadata found`);
|
|
718
|
+
}
|
|
719
|
+
(0, utils_1.validateIfTransactionUnapproved)(transactionMeta, 'updatePreviousGasParams');
|
|
720
|
+
const transactionPreviousGas = {
|
|
721
|
+
previousGas: {
|
|
722
|
+
gasLimit,
|
|
723
|
+
maxFeePerGas,
|
|
724
|
+
maxPriorityFeePerGas,
|
|
725
|
+
},
|
|
726
|
+
};
|
|
727
|
+
// only update what is defined
|
|
728
|
+
transactionPreviousGas.previousGas = (0, lodash_1.pickBy)(transactionPreviousGas.previousGas);
|
|
729
|
+
// merge updated previous gas values with existing transaction meta
|
|
730
|
+
const updatedMeta = (0, lodash_1.merge)(transactionMeta, transactionPreviousGas);
|
|
731
|
+
this.updateTransaction(updatedMeta, 'TransactionController:updatePreviousGasParams - Previous gas values updated');
|
|
732
|
+
return this.getTransaction(transactionId);
|
|
733
|
+
}
|
|
613
734
|
/**
|
|
614
735
|
* Gets the next nonce according to the nonce-tracker.
|
|
615
736
|
* Ensure `releaseLock` is called once processing of the `nonce` value is complete.
|
|
@@ -622,7 +743,312 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
622
743
|
return this.nonceTracker.getNonceLock(address);
|
|
623
744
|
});
|
|
624
745
|
}
|
|
625
|
-
|
|
746
|
+
/**
|
|
747
|
+
* Updates the editable parameters of a transaction.
|
|
748
|
+
*
|
|
749
|
+
* @param txId - The ID of the transaction to update.
|
|
750
|
+
* @param params - The editable parameters to update.
|
|
751
|
+
* @param params.data - Data to pass with the transaction.
|
|
752
|
+
* @param params.gas - Maximum number of units of gas to use for the transaction.
|
|
753
|
+
* @param params.gasPrice - Price per gas for legacy transactions.
|
|
754
|
+
* @param params.from - Address to send the transaction from.
|
|
755
|
+
* @param params.to - Address to send the transaction to.
|
|
756
|
+
* @param params.value - Value associated with the transaction.
|
|
757
|
+
* @returns The updated transaction metadata.
|
|
758
|
+
*/
|
|
759
|
+
updateEditableParams(txId, { data, gas, gasPrice, from, to, value, }) {
|
|
760
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
761
|
+
const transactionMeta = this.getTransaction(txId);
|
|
762
|
+
if (!transactionMeta) {
|
|
763
|
+
throw new Error(`Cannot update editable params as no transaction metadata found`);
|
|
764
|
+
}
|
|
765
|
+
(0, utils_1.validateIfTransactionUnapproved)(transactionMeta, 'updateEditableParams');
|
|
766
|
+
const editableParams = {
|
|
767
|
+
txParams: {
|
|
768
|
+
data,
|
|
769
|
+
from,
|
|
770
|
+
to,
|
|
771
|
+
value,
|
|
772
|
+
gas,
|
|
773
|
+
gasPrice,
|
|
774
|
+
},
|
|
775
|
+
};
|
|
776
|
+
editableParams.txParams = (0, lodash_1.pickBy)(editableParams.txParams);
|
|
777
|
+
const updatedTransaction = (0, lodash_1.merge)(transactionMeta, editableParams);
|
|
778
|
+
const { type } = yield (0, transaction_type_1.determineTransactionType)(updatedTransaction.txParams, this.ethQuery);
|
|
779
|
+
updatedTransaction.type = type;
|
|
780
|
+
this.updateTransaction(updatedTransaction, `Update Editable Params for ${txId}`);
|
|
781
|
+
return this.getTransaction(txId);
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Signs and returns the raw transaction data for provided transaction params list.
|
|
786
|
+
*
|
|
787
|
+
* @param listOfTxParams - The list of transaction params to approve.
|
|
788
|
+
* @returns The raw transactions.
|
|
789
|
+
*/
|
|
790
|
+
approveTransactionsWithSameNonce(listOfTxParams = []) {
|
|
791
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
792
|
+
if (listOfTxParams.length === 0) {
|
|
793
|
+
return '';
|
|
794
|
+
}
|
|
795
|
+
const initialTx = listOfTxParams[0];
|
|
796
|
+
const common = this.getCommonConfiguration();
|
|
797
|
+
const initialTxAsEthTx = tx_1.TransactionFactory.fromTxData(initialTx, {
|
|
798
|
+
common,
|
|
799
|
+
});
|
|
800
|
+
const initialTxAsSerializedHex = (0, ethereumjs_util_1.bufferToHex)(initialTxAsEthTx.serialize());
|
|
801
|
+
if (this.inProcessOfSigning.has(initialTxAsSerializedHex)) {
|
|
802
|
+
return '';
|
|
803
|
+
}
|
|
804
|
+
this.inProcessOfSigning.add(initialTxAsSerializedHex);
|
|
805
|
+
let rawTransactions, nonceLock;
|
|
806
|
+
try {
|
|
807
|
+
// TODO: we should add a check to verify that all transactions have the same from address
|
|
808
|
+
const fromAddress = initialTx.from;
|
|
809
|
+
nonceLock = yield this.nonceTracker.getNonceLock(fromAddress);
|
|
810
|
+
const nonce = nonceLock.nextNonce;
|
|
811
|
+
rawTransactions = yield Promise.all(listOfTxParams.map((txParams) => {
|
|
812
|
+
txParams.nonce = (0, ethereumjs_util_1.addHexPrefix)(nonce.toString(16));
|
|
813
|
+
return this.signExternalTransaction(txParams);
|
|
814
|
+
}));
|
|
815
|
+
}
|
|
816
|
+
catch (err) {
|
|
817
|
+
(0, logger_1.projectLogger)('Error while signing transactions with same nonce', err);
|
|
818
|
+
// Must set transaction to submitted/failed before releasing lock
|
|
819
|
+
// continue with error chain
|
|
820
|
+
throw err;
|
|
821
|
+
}
|
|
822
|
+
finally {
|
|
823
|
+
if (nonceLock) {
|
|
824
|
+
nonceLock.releaseLock();
|
|
825
|
+
}
|
|
826
|
+
this.inProcessOfSigning.delete(initialTxAsSerializedHex);
|
|
827
|
+
}
|
|
828
|
+
return rawTransactions;
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Update a custodial transaction.
|
|
833
|
+
*
|
|
834
|
+
* @param transactionId - The ID of the transaction to update.
|
|
835
|
+
* @param options - The custodial transaction options to update.
|
|
836
|
+
* @param options.errorMessage - The error message to be assigned in case transaction status update to failed.
|
|
837
|
+
* @param options.hash - The new hash value to be assigned.
|
|
838
|
+
* @param options.status - The new status value to be assigned.
|
|
839
|
+
*/
|
|
840
|
+
updateCustodialTransaction(transactionId, { errorMessage, hash, status, }) {
|
|
841
|
+
const transactionMeta = this.getTransaction(transactionId);
|
|
842
|
+
if (!transactionMeta) {
|
|
843
|
+
throw new Error(`Cannot update custodial transaction as no transaction metadata found`);
|
|
844
|
+
}
|
|
845
|
+
if (!transactionMeta.custodyId) {
|
|
846
|
+
throw new Error('Transaction must be a custodian transaction');
|
|
847
|
+
}
|
|
848
|
+
if (status &&
|
|
849
|
+
![
|
|
850
|
+
types_1.TransactionStatus.submitted,
|
|
851
|
+
types_1.TransactionStatus.signed,
|
|
852
|
+
types_1.TransactionStatus.failed,
|
|
853
|
+
].includes(status)) {
|
|
854
|
+
throw new Error(`Cannot update custodial transaction with status: ${status}`);
|
|
855
|
+
}
|
|
856
|
+
const updatedTransactionMeta = (0, lodash_1.merge)(transactionMeta, (0, lodash_1.pickBy)({ hash, status }));
|
|
857
|
+
if (status === types_1.TransactionStatus.submitted) {
|
|
858
|
+
updatedTransactionMeta.submittedTime = new Date().getTime();
|
|
859
|
+
}
|
|
860
|
+
if (status === types_1.TransactionStatus.failed) {
|
|
861
|
+
updatedTransactionMeta.error = (0, utils_1.normalizeTxError)(new Error(errorMessage));
|
|
862
|
+
}
|
|
863
|
+
this.updateTransaction(updatedTransactionMeta, `TransactionController:updateCustodialTransaction - Custodial transaction updated`);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Creates approvals for all unapproved transactions persisted.
|
|
867
|
+
*/
|
|
868
|
+
initApprovals() {
|
|
869
|
+
const chainId = this.getChainId();
|
|
870
|
+
const unapprovedTxs = this.state.transactions.filter((transaction) => transaction.status === types_1.TransactionStatus.unapproved &&
|
|
871
|
+
transaction.chainId === chainId);
|
|
872
|
+
for (const txMeta of unapprovedTxs) {
|
|
873
|
+
this.processApproval(txMeta, {
|
|
874
|
+
shouldShowRequest: false,
|
|
875
|
+
}).catch((error) => {
|
|
876
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === rpc_errors_1.errorCodes.provider.userRejectedRequest) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
console.error('Error during persisted transaction approval', error);
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Search transaction metadata for matching entries.
|
|
885
|
+
*
|
|
886
|
+
* @param opts - Options bag.
|
|
887
|
+
* @param opts.searchCriteria - An object containing values or functions for transaction properties to filter transactions with.
|
|
888
|
+
* @param opts.initialList - The transactions to search. Defaults to the current state.
|
|
889
|
+
* @param opts.filterToCurrentNetwork - Whether to filter the results to the current network. Defaults to true.
|
|
890
|
+
* @param opts.limit - The maximum number of transactions to return. No limit by default.
|
|
891
|
+
* @returns An array of transactions matching the provided options.
|
|
892
|
+
*/
|
|
893
|
+
getTransactions({ searchCriteria = {}, initialList, filterToCurrentNetwork = true, limit, } = {}) {
|
|
894
|
+
const chainId = this.getChainId();
|
|
895
|
+
// searchCriteria is an object that might have values that aren't predicate
|
|
896
|
+
// methods. When providing any other value type (string, number, etc), we
|
|
897
|
+
// consider this shorthand for "check the value at key for strict equality
|
|
898
|
+
// with the provided value". To conform this object to be only methods, we
|
|
899
|
+
// mapValues (lodash) such that every value on the object is a method that
|
|
900
|
+
// returns a boolean.
|
|
901
|
+
const predicateMethods = (0, lodash_1.mapValues)(searchCriteria, (predicate) => {
|
|
902
|
+
return typeof predicate === 'function'
|
|
903
|
+
? predicate
|
|
904
|
+
: (v) => v === predicate;
|
|
905
|
+
});
|
|
906
|
+
const transactionsToFilter = initialList !== null && initialList !== void 0 ? initialList : this.state.transactions;
|
|
907
|
+
// Combine sortBy and pickBy to transform our state object into an array of
|
|
908
|
+
// matching transactions that are sorted by time.
|
|
909
|
+
const filteredTransactions = (0, lodash_1.sortBy)((0, lodash_1.pickBy)(transactionsToFilter, (transaction) => {
|
|
910
|
+
if (filterToCurrentNetwork && transaction.chainId !== chainId) {
|
|
911
|
+
return false;
|
|
912
|
+
}
|
|
913
|
+
// iterate over the predicateMethods keys to check if the transaction
|
|
914
|
+
// matches the searchCriteria
|
|
915
|
+
for (const [key, predicate] of Object.entries(predicateMethods)) {
|
|
916
|
+
// We return false early as soon as we know that one of the specified
|
|
917
|
+
// search criteria do not match the transaction. This prevents
|
|
918
|
+
// needlessly checking all criteria when we already know the criteria
|
|
919
|
+
// are not fully satisfied. We check both txParams and the base
|
|
920
|
+
// object as predicate keys can be either.
|
|
921
|
+
if (key in transaction.txParams) {
|
|
922
|
+
if (predicate(transaction.txParams[key]) === false) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
else if (predicate(transaction[key]) === false) {
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
return true;
|
|
931
|
+
}), 'time');
|
|
932
|
+
if (limit !== undefined) {
|
|
933
|
+
// We need to have all transactions of a given nonce in order to display
|
|
934
|
+
// necessary details in the UI. We use the size of this set to determine
|
|
935
|
+
// whether we have reached the limit provided, thus ensuring that all
|
|
936
|
+
// transactions of nonces we include will be sent to the UI.
|
|
937
|
+
const nonces = new Set();
|
|
938
|
+
const txs = [];
|
|
939
|
+
// By default, the transaction list we filter from is sorted by time ASC.
|
|
940
|
+
// To ensure that filtered results prefers the newest transactions we
|
|
941
|
+
// iterate from right to left, inserting transactions into front of a new
|
|
942
|
+
// array. The original order is preserved, but we ensure that newest txs
|
|
943
|
+
// are preferred.
|
|
944
|
+
for (let i = filteredTransactions.length - 1; i > -1; i--) {
|
|
945
|
+
const txMeta = filteredTransactions[i];
|
|
946
|
+
const { nonce } = txMeta.txParams;
|
|
947
|
+
if (!nonces.has(nonce)) {
|
|
948
|
+
if (nonces.size < limit) {
|
|
949
|
+
nonces.add(nonce);
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
// Push transaction into the beginning of our array to ensure the
|
|
956
|
+
// original order is preserved.
|
|
957
|
+
txs.unshift(txMeta);
|
|
958
|
+
}
|
|
959
|
+
return txs;
|
|
960
|
+
}
|
|
961
|
+
return filteredTransactions;
|
|
962
|
+
}
|
|
963
|
+
signExternalTransaction(transactionParams) {
|
|
964
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
965
|
+
if (!this.sign) {
|
|
966
|
+
throw new Error('No sign method defined.');
|
|
967
|
+
}
|
|
968
|
+
const normalizedTransactionParams = (0, utils_1.normalizeTxParams)(transactionParams);
|
|
969
|
+
const chainId = this.getChainId();
|
|
970
|
+
const type = (0, utils_1.isEIP1559Transaction)(normalizedTransactionParams)
|
|
971
|
+
? types_1.TransactionEnvelopeType.feeMarket
|
|
972
|
+
: types_1.TransactionEnvelopeType.legacy;
|
|
973
|
+
const updatedTransactionParams = Object.assign(Object.assign({}, normalizedTransactionParams), { type, gasLimit: normalizedTransactionParams.gas, chainId });
|
|
974
|
+
const { from } = updatedTransactionParams;
|
|
975
|
+
const common = this.getCommonConfiguration();
|
|
976
|
+
const unsignedTransaction = tx_1.TransactionFactory.fromTxData(updatedTransactionParams, { common });
|
|
977
|
+
const signedTransaction = yield this.sign(unsignedTransaction, from);
|
|
978
|
+
const rawTransaction = (0, ethereumjs_util_1.bufferToHex)(signedTransaction.serialize());
|
|
979
|
+
return rawTransaction;
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Removes unapproved transactions from state.
|
|
984
|
+
*/
|
|
985
|
+
clearUnapprovedTransactions() {
|
|
986
|
+
const transactions = this.state.transactions.filter(({ status }) => status !== types_1.TransactionStatus.unapproved);
|
|
987
|
+
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
988
|
+
}
|
|
989
|
+
addMetadata(transactionMeta) {
|
|
990
|
+
const { transactions } = this.state;
|
|
991
|
+
transactions.push(transactionMeta);
|
|
992
|
+
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
993
|
+
}
|
|
994
|
+
updateGasProperties(transactionMeta) {
|
|
995
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
996
|
+
const isEIP1559Compatible = (yield this.getEIP1559Compatibility()) &&
|
|
997
|
+
transactionMeta.txParams.type !== types_1.TransactionEnvelopeType.legacy;
|
|
998
|
+
const chainId = this.getChainId();
|
|
999
|
+
yield (0, gas_1.updateGas)({
|
|
1000
|
+
ethQuery: this.ethQuery,
|
|
1001
|
+
providerConfig: this.getNetworkState().providerConfig,
|
|
1002
|
+
txMeta: transactionMeta,
|
|
1003
|
+
});
|
|
1004
|
+
yield (0, gas_fees_1.updateGasFees)({
|
|
1005
|
+
eip1559: isEIP1559Compatible,
|
|
1006
|
+
ethQuery: this.ethQuery,
|
|
1007
|
+
getSavedGasFees: this.getSavedGasFees.bind(this, chainId),
|
|
1008
|
+
getGasFeeEstimates: this.getGasFeeEstimates.bind(this),
|
|
1009
|
+
txMeta: transactionMeta,
|
|
1010
|
+
});
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
getCurrentChainTransactionsByStatus(status) {
|
|
1014
|
+
const chainId = this.getChainId();
|
|
1015
|
+
return this.state.transactions.filter((transaction) => transaction.status === status && transaction.chainId === chainId);
|
|
1016
|
+
}
|
|
1017
|
+
onBootCleanup() {
|
|
1018
|
+
this.submitApprovedTransactions();
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Create approvals for all unapproved transactions on current chain.
|
|
1022
|
+
*/
|
|
1023
|
+
createApprovalsForUnapprovedTransactions() {
|
|
1024
|
+
const unapprovedTransactions = this.getCurrentChainTransactionsByStatus(types_1.TransactionStatus.unapproved);
|
|
1025
|
+
for (const transactionMeta of unapprovedTransactions) {
|
|
1026
|
+
this.processApproval(transactionMeta, {
|
|
1027
|
+
shouldShowRequest: false,
|
|
1028
|
+
}).catch((error) => {
|
|
1029
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === rpc_errors_1.errorCodes.provider.userRejectedRequest) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
/* istanbul ignore next */
|
|
1033
|
+
console.error('Error during persisted transaction approval', error);
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Force to submit approved transactions on current chain.
|
|
1039
|
+
*/
|
|
1040
|
+
submitApprovedTransactions() {
|
|
1041
|
+
const approvedTransactions = this.getCurrentChainTransactionsByStatus(types_1.TransactionStatus.approved);
|
|
1042
|
+
for (const transactionMeta of approvedTransactions) {
|
|
1043
|
+
if (this.beforeApproveOnInit(transactionMeta)) {
|
|
1044
|
+
this.approveTransaction(transactionMeta.id).catch((error) => {
|
|
1045
|
+
/* istanbul ignore next */
|
|
1046
|
+
console.error('Error while submitting persisted transaction', error);
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
processApproval(transactionMeta, { isExisting = false, requireApproval, shouldShowRequest = true, actionId, }) {
|
|
626
1052
|
return __awaiter(this, void 0, void 0, function* () {
|
|
627
1053
|
const transactionId = transactionMeta.id;
|
|
628
1054
|
let resultCallbacks;
|
|
@@ -637,21 +1063,33 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
637
1063
|
shouldShowRequest,
|
|
638
1064
|
});
|
|
639
1065
|
resultCallbacks = acceptResult.resultCallbacks;
|
|
1066
|
+
if (resultCallbacks) {
|
|
1067
|
+
this.hub.once(`${transactionId}:publish-skip`, () => {
|
|
1068
|
+
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.success();
|
|
1069
|
+
// Remove the reference to prevent additional reports once submitted.
|
|
1070
|
+
resultCallbacks = undefined;
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
640
1073
|
}
|
|
641
1074
|
const { isCompleted: isTxCompleted } = this.isTransactionCompleted(transactionId);
|
|
642
1075
|
if (!isTxCompleted) {
|
|
643
1076
|
yield this.approveTransaction(transactionId);
|
|
1077
|
+
const updatedTransactionMeta = this.getTransaction(transactionId);
|
|
1078
|
+
this.hub.emit('transaction-approved', {
|
|
1079
|
+
transactionMeta: updatedTransactionMeta,
|
|
1080
|
+
actionId,
|
|
1081
|
+
});
|
|
644
1082
|
}
|
|
645
1083
|
}
|
|
646
1084
|
catch (error) {
|
|
647
1085
|
const { isCompleted: isTxCompleted } = this.isTransactionCompleted(transactionId);
|
|
648
1086
|
if (!isTxCompleted) {
|
|
649
|
-
if (error.code === rpc_errors_1.errorCodes.provider.userRejectedRequest) {
|
|
650
|
-
this.cancelTransaction(transactionId);
|
|
651
|
-
throw rpc_errors_1.providerErrors.userRejectedRequest('User
|
|
1087
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === rpc_errors_1.errorCodes.provider.userRejectedRequest) {
|
|
1088
|
+
this.cancelTransaction(transactionId, actionId);
|
|
1089
|
+
throw rpc_errors_1.providerErrors.userRejectedRequest('MetaMask Tx Signature: User denied transaction signature.');
|
|
652
1090
|
}
|
|
653
1091
|
else {
|
|
654
|
-
this.failTransaction(meta, error);
|
|
1092
|
+
this.failTransaction(meta, error, actionId);
|
|
655
1093
|
}
|
|
656
1094
|
}
|
|
657
1095
|
}
|
|
@@ -661,10 +1099,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
661
1099
|
case types_1.TransactionStatus.failed:
|
|
662
1100
|
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.error(finalMeta.error);
|
|
663
1101
|
throw rpc_errors_1.rpcErrors.internal(finalMeta.error.message);
|
|
664
|
-
case types_1.TransactionStatus.cancelled:
|
|
665
|
-
const cancelError = rpc_errors_1.rpcErrors.internal('User cancelled the transaction');
|
|
666
|
-
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.error(cancelError);
|
|
667
|
-
throw cancelError;
|
|
668
1102
|
case types_1.TransactionStatus.submitted:
|
|
669
1103
|
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.success();
|
|
670
1104
|
return finalMeta.hash;
|
|
@@ -703,7 +1137,10 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
703
1137
|
this.failTransaction(transactionMeta, new Error('No chainId defined.'));
|
|
704
1138
|
return;
|
|
705
1139
|
}
|
|
706
|
-
|
|
1140
|
+
if (this.inProcessOfSigning.has(transactionId)) {
|
|
1141
|
+
(0, logger_1.projectLogger)('Skipping approval as signing in progress', transactionId);
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
707
1144
|
let nonceToUse = nonce;
|
|
708
1145
|
// if a nonce already exists on the transactionMeta it means this is a speedup or cancel transaction
|
|
709
1146
|
// so we want to reuse that nonce and hope that it beats the previous attempt to chain. Otherwise use a new locked nonce
|
|
@@ -711,38 +1148,40 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
711
1148
|
nonceLock = yield this.nonceTracker.getNonceLock(from);
|
|
712
1149
|
nonceToUse = (0, ethereumjs_util_1.addHexPrefix)(nonceLock.nextNonce.toString(16));
|
|
713
1150
|
}
|
|
714
|
-
transactionMeta.status =
|
|
1151
|
+
transactionMeta.status = types_1.TransactionStatus.approved;
|
|
715
1152
|
transactionMeta.txParams.nonce = nonceToUse;
|
|
716
1153
|
transactionMeta.txParams.chainId = chainId;
|
|
717
1154
|
const baseTxParams = Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas });
|
|
1155
|
+
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction approved');
|
|
1156
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
718
1157
|
const isEIP1559 = (0, utils_1.isEIP1559Transaction)(transactionMeta.txParams);
|
|
719
1158
|
const txParams = isEIP1559
|
|
720
|
-
? Object.assign(Object.assign({}, baseTxParams), {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
1159
|
+
? Object.assign(Object.assign({}, baseTxParams), { estimatedBaseFee: transactionMeta.txParams.estimatedBaseFee, type: types_1.TransactionEnvelopeType.feeMarket }) : baseTxParams;
|
|
1160
|
+
const rawTx = yield this.signTransaction(transactionMeta, txParams);
|
|
1161
|
+
if (!this.beforePublish(transactionMeta)) {
|
|
1162
|
+
(0, logger_1.projectLogger)('Skipping publishing transaction based on hook');
|
|
1163
|
+
this.hub.emit(`${transactionMeta.id}:publish-skip`, transactionMeta);
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
if (!rawTx) {
|
|
1167
|
+
return;
|
|
726
1168
|
}
|
|
727
|
-
const
|
|
728
|
-
const signedTx = yield this.sign(unsignedEthTx, from);
|
|
729
|
-
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
730
|
-
transactionMeta.status = types_1.TransactionStatus.signed;
|
|
731
|
-
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction signed');
|
|
732
|
-
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
733
|
-
transactionMeta.rawTx = rawTx;
|
|
734
|
-
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - RawTransaction added');
|
|
735
|
-
const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
|
|
1169
|
+
const hash = yield this.publishTransaction(rawTx);
|
|
736
1170
|
transactionMeta.hash = hash;
|
|
737
1171
|
transactionMeta.status = types_1.TransactionStatus.submitted;
|
|
738
1172
|
transactionMeta.submittedTime = new Date().getTime();
|
|
739
1173
|
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction submitted');
|
|
1174
|
+
this.hub.emit('transaction-submitted', {
|
|
1175
|
+
transactionMeta,
|
|
1176
|
+
});
|
|
740
1177
|
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
1178
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
741
1179
|
}
|
|
742
1180
|
catch (error) {
|
|
743
1181
|
this.failTransaction(transactionMeta, error);
|
|
744
1182
|
}
|
|
745
1183
|
finally {
|
|
1184
|
+
this.inProcessOfSigning.delete(transactionId);
|
|
746
1185
|
// must set transaction to submitted/failed before releasing lock
|
|
747
1186
|
if (nonceLock) {
|
|
748
1187
|
nonceLock.releaseLock();
|
|
@@ -751,21 +1190,32 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
751
1190
|
}
|
|
752
1191
|
});
|
|
753
1192
|
}
|
|
1193
|
+
publishTransaction(rawTransaction) {
|
|
1194
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1195
|
+
return yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTransaction]);
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
754
1198
|
/**
|
|
755
1199
|
* Cancels a transaction based on its ID by setting its status to "rejected"
|
|
756
1200
|
* and emitting a `<tx.id>:finished` hub event.
|
|
757
1201
|
*
|
|
758
1202
|
* @param transactionId - The ID of the transaction to cancel.
|
|
1203
|
+
* @param actionId - The actionId passed from UI
|
|
759
1204
|
*/
|
|
760
|
-
cancelTransaction(transactionId) {
|
|
1205
|
+
cancelTransaction(transactionId, actionId) {
|
|
761
1206
|
const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
|
|
762
1207
|
if (!transactionMeta) {
|
|
763
1208
|
return;
|
|
764
1209
|
}
|
|
765
1210
|
transactionMeta.status = types_1.TransactionStatus.rejected;
|
|
766
|
-
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
767
1211
|
const transactions = this.state.transactions.filter(({ id }) => id !== transactionId);
|
|
768
1212
|
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
1213
|
+
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
1214
|
+
this.hub.emit('transaction-rejected', {
|
|
1215
|
+
transactionMeta,
|
|
1216
|
+
actionId,
|
|
1217
|
+
});
|
|
1218
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
769
1219
|
}
|
|
770
1220
|
/**
|
|
771
1221
|
* Trim the amount of transactions that are set on the state. Checks
|
|
@@ -776,7 +1226,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
776
1226
|
* representation, this function will not break apart transactions with the
|
|
777
1227
|
* same nonce, created on the same day, per network. Not accounting for transactions of the same
|
|
778
1228
|
* nonce, same day and network combo can result in confusing or broken experiences
|
|
779
|
-
* in the UI. The transactions are then updated using the
|
|
1229
|
+
* in the UI. The transactions are then updated using the BaseControllerV1 update.
|
|
780
1230
|
*
|
|
781
1231
|
* @param transactions - The transactions to be applied to the state.
|
|
782
1232
|
* @returns The trimmed list of transactions.
|
|
@@ -812,8 +1262,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
812
1262
|
isFinalState(status) {
|
|
813
1263
|
return (status === types_1.TransactionStatus.rejected ||
|
|
814
1264
|
status === types_1.TransactionStatus.confirmed ||
|
|
815
|
-
status === types_1.TransactionStatus.failed
|
|
816
|
-
status === types_1.TransactionStatus.cancelled);
|
|
1265
|
+
status === types_1.TransactionStatus.failed);
|
|
817
1266
|
}
|
|
818
1267
|
/**
|
|
819
1268
|
* Whether the transaction has at least completed all local processing.
|
|
@@ -823,7 +1272,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
823
1272
|
*/
|
|
824
1273
|
isLocalFinalState(status) {
|
|
825
1274
|
return [
|
|
826
|
-
types_1.TransactionStatus.cancelled,
|
|
827
1275
|
types_1.TransactionStatus.confirmed,
|
|
828
1276
|
types_1.TransactionStatus.failed,
|
|
829
1277
|
types_1.TransactionStatus.rejected,
|
|
@@ -910,10 +1358,6 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
910
1358
|
this.update({ lastFetchedBlockNumbers });
|
|
911
1359
|
this.hub.emit('incomingTransactionBlock', blockNumber);
|
|
912
1360
|
}
|
|
913
|
-
onPendingTransactionsUpdate(transactions) {
|
|
914
|
-
(0, logger_1.pendingTransactionsLogger)('Updated pending transactions');
|
|
915
|
-
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
916
|
-
}
|
|
917
1361
|
generateDappSuggestedGasFees(txParams, origin) {
|
|
918
1362
|
if (!origin || origin === controller_utils_1.ORIGIN_METAMASK) {
|
|
919
1363
|
return undefined;
|
|
@@ -946,25 +1390,23 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
946
1390
|
*/
|
|
947
1391
|
addExternalTransaction(transactionMeta) {
|
|
948
1392
|
var _a, _b;
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
if (!
|
|
960
|
-
|
|
961
|
-
(0, history_1.addInitialHistorySnapshot)(transactionMeta);
|
|
962
|
-
}
|
|
1393
|
+
const chainId = this.getChainId();
|
|
1394
|
+
const { transactions } = this.state;
|
|
1395
|
+
const fromAddress = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.from;
|
|
1396
|
+
const sameFromAndNetworkTransactions = transactions.filter((transaction) => transaction.txParams.from === fromAddress &&
|
|
1397
|
+
transaction.chainId === chainId);
|
|
1398
|
+
const confirmedTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.confirmed);
|
|
1399
|
+
const pendingTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.submitted);
|
|
1400
|
+
(0, external_transactions_1.validateConfirmedExternalTransaction)(transactionMeta, confirmedTxs, pendingTxs);
|
|
1401
|
+
// Make sure provided external transaction has non empty history array
|
|
1402
|
+
if (!((_b = transactionMeta.history) !== null && _b !== void 0 ? _b : []).length) {
|
|
1403
|
+
if (!this.isHistoryDisabled) {
|
|
1404
|
+
(0, history_1.addInitialHistorySnapshot)(transactionMeta);
|
|
963
1405
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1406
|
+
}
|
|
1407
|
+
const updatedTransactions = [...transactions, transactionMeta];
|
|
1408
|
+
this.update({
|
|
1409
|
+
transactions: this.trimTransactionsForState(updatedTransactions),
|
|
968
1410
|
});
|
|
969
1411
|
}
|
|
970
1412
|
/**
|
|
@@ -1005,7 +1447,11 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1005
1447
|
*/
|
|
1006
1448
|
setTransactionStatusDropped(transactionMeta) {
|
|
1007
1449
|
transactionMeta.status = types_1.TransactionStatus.dropped;
|
|
1450
|
+
this.hub.emit('transaction-dropped', {
|
|
1451
|
+
transactionMeta,
|
|
1452
|
+
});
|
|
1008
1453
|
this.updateTransaction(transactionMeta, 'TransactionController#setTransactionStatusDropped - Transaction dropped');
|
|
1454
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1009
1455
|
}
|
|
1010
1456
|
/**
|
|
1011
1457
|
* Get transaction with provided actionId.
|
|
@@ -1046,14 +1492,82 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
1046
1492
|
});
|
|
1047
1493
|
}
|
|
1048
1494
|
getEIP1559Compatibility() {
|
|
1049
|
-
var _a, _b;
|
|
1050
1495
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1051
1496
|
const currentNetworkIsEIP1559Compatible = yield this.getCurrentNetworkEIP1559Compatibility();
|
|
1052
|
-
const currentAccountIsEIP1559Compatible =
|
|
1497
|
+
const currentAccountIsEIP1559Compatible = yield this.getCurrentAccountEIP1559Compatibility();
|
|
1053
1498
|
return (currentNetworkIsEIP1559Compatible && currentAccountIsEIP1559Compatible);
|
|
1054
1499
|
});
|
|
1055
1500
|
}
|
|
1501
|
+
addPendingTransactionTrackerListeners() {
|
|
1502
|
+
this.pendingTransactionTracker.hub.on('transaction-confirmed', this.onConfirmedTransaction.bind(this));
|
|
1503
|
+
this.pendingTransactionTracker.hub.on('transaction-dropped', this.setTransactionStatusDropped.bind(this));
|
|
1504
|
+
this.pendingTransactionTracker.hub.on('transaction-failed', this.failTransaction.bind(this));
|
|
1505
|
+
this.pendingTransactionTracker.hub.on('transaction-updated', this.updateTransaction.bind(this));
|
|
1506
|
+
}
|
|
1507
|
+
signTransaction(transactionMeta, txParams) {
|
|
1508
|
+
var _a;
|
|
1509
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1510
|
+
(0, logger_1.projectLogger)('Signing transaction', txParams);
|
|
1511
|
+
const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
|
|
1512
|
+
this.inProcessOfSigning.add(transactionMeta.id);
|
|
1513
|
+
const signedTx = yield ((_a = this.sign) === null || _a === void 0 ? void 0 : _a.call(this, unsignedEthTx, txParams.from, ...this.getAdditionalSignArguments(transactionMeta)));
|
|
1514
|
+
if (!signedTx) {
|
|
1515
|
+
(0, logger_1.projectLogger)('Skipping signed status as no signed transaction');
|
|
1516
|
+
return undefined;
|
|
1517
|
+
}
|
|
1518
|
+
if (!this.afterSign(transactionMeta, signedTx)) {
|
|
1519
|
+
this.updateTransaction(transactionMeta, 'TransactionController#signTransaction - Update after sign');
|
|
1520
|
+
(0, logger_1.projectLogger)('Skipping signed status based on hook');
|
|
1521
|
+
return undefined;
|
|
1522
|
+
}
|
|
1523
|
+
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
1524
|
+
transactionMeta.status = types_1.TransactionStatus.signed;
|
|
1525
|
+
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction signed');
|
|
1526
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1527
|
+
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
1528
|
+
transactionMeta.rawTx = rawTx;
|
|
1529
|
+
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - RawTransaction added');
|
|
1530
|
+
return rawTx;
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1533
|
+
onTransactionStatusChange(transactionMeta) {
|
|
1534
|
+
this.hub.emit('transaction-status-update', { transactionMeta });
|
|
1535
|
+
}
|
|
1536
|
+
getNonceTrackerTransactions(status, address) {
|
|
1537
|
+
const currentChainId = this.getChainId();
|
|
1538
|
+
return (0, utils_1.getAndFormatTransactionsForNonceTracker)(currentChainId, address, status, this.state.transactions);
|
|
1539
|
+
}
|
|
1540
|
+
onConfirmedTransaction(transactionMeta) {
|
|
1541
|
+
(0, logger_1.projectLogger)('Processing confirmed transaction', transactionMeta.id);
|
|
1542
|
+
this.hub.emit('transaction-confirmed', { transactionMeta });
|
|
1543
|
+
this.hub.emit(`${transactionMeta.id}:confirmed`, transactionMeta);
|
|
1544
|
+
this.onTransactionStatusChange(transactionMeta);
|
|
1545
|
+
// Intentional given potential duration of process.
|
|
1546
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1547
|
+
this.updatePostBalance(transactionMeta);
|
|
1548
|
+
}
|
|
1549
|
+
updatePostBalance(transactionMeta) {
|
|
1550
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1551
|
+
try {
|
|
1552
|
+
if (transactionMeta.type !== types_1.TransactionType.swap) {
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
const { updatedTransactionMeta, approvalTransactionMeta } = yield (0, swaps_1.updatePostTransactionBalance)(transactionMeta, {
|
|
1556
|
+
ethQuery: this.ethQuery,
|
|
1557
|
+
getTransaction: this.getTransaction.bind(this),
|
|
1558
|
+
updateTransaction: this.updateTransaction.bind(this),
|
|
1559
|
+
});
|
|
1560
|
+
this.hub.emit('post-transaction-balance-updated', {
|
|
1561
|
+
transactionMeta: updatedTransactionMeta,
|
|
1562
|
+
approvalTransactionMeta,
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
catch (error) {
|
|
1566
|
+
/* istanbul ignore next */
|
|
1567
|
+
(0, logger_1.projectLogger)('Error while updating post transaction balance', error);
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1056
1571
|
}
|
|
1057
1572
|
exports.TransactionController = TransactionController;
|
|
1058
|
-
exports.default = TransactionController;
|
|
1059
1573
|
//# sourceMappingURL=TransactionController.js.map
|