@metamask/transaction-controller 9.2.0 → 11.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 +37 -1
- package/dist/EtherscanRemoteTransactionSource.d.ts +2 -2
- package/dist/EtherscanRemoteTransactionSource.d.ts.map +1 -1
- package/dist/EtherscanRemoteTransactionSource.js +42 -19
- package/dist/EtherscanRemoteTransactionSource.js.map +1 -1
- package/dist/IncomingTransactionHelper.d.ts +4 -3
- package/dist/IncomingTransactionHelper.d.ts.map +1 -1
- package/dist/IncomingTransactionHelper.js +40 -25
- package/dist/IncomingTransactionHelper.js.map +1 -1
- package/dist/TransactionController.d.ts +114 -26
- package/dist/TransactionController.d.ts.map +1 -1
- package/dist/TransactionController.js +377 -120
- package/dist/TransactionController.js.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +26 -26
- package/dist/constants.js.map +1 -1
- package/dist/etherscan.d.ts +5 -6
- package/dist/etherscan.d.ts.map +1 -1
- package/dist/etherscan.js +7 -14
- package/dist/etherscan.js.map +1 -1
- package/dist/external-transactions.d.ts +10 -0
- package/dist/external-transactions.d.ts.map +1 -0
- package/dist/external-transactions.js +36 -0
- package/dist/external-transactions.js.map +1 -0
- package/dist/history.d.ts +15 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +75 -0
- package/dist/history.js.map +1 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +8 -0
- package/dist/logger.js.map +1 -0
- package/dist/types.d.ts +129 -20
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +19 -10
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +49 -34
- package/dist/utils.js.map +1 -1
- package/package.json +5 -3
|
@@ -23,9 +23,12 @@ const eth_method_registry_1 = __importDefault(require("eth-method-registry"));
|
|
|
23
23
|
const eth_rpc_errors_1 = require("eth-rpc-errors");
|
|
24
24
|
const ethereumjs_util_1 = require("ethereumjs-util");
|
|
25
25
|
const events_1 = require("events");
|
|
26
|
+
const lodash_1 = require("lodash");
|
|
26
27
|
const nonce_tracker_1 = __importDefault(require("nonce-tracker"));
|
|
27
28
|
const uuid_1 = require("uuid");
|
|
28
29
|
const EtherscanRemoteTransactionSource_1 = require("./EtherscanRemoteTransactionSource");
|
|
30
|
+
const external_transactions_1 = require("./external-transactions");
|
|
31
|
+
const history_1 = require("./history");
|
|
29
32
|
const IncomingTransactionHelper_1 = require("./IncomingTransactionHelper");
|
|
30
33
|
const types_1 = require("./types");
|
|
31
34
|
const utils_1 = require("./utils");
|
|
@@ -51,20 +54,22 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
51
54
|
*
|
|
52
55
|
* @param options - The controller options.
|
|
53
56
|
* @param options.blockTracker - The block tracker used to poll for new blocks data.
|
|
57
|
+
* @param options.disableHistory - Whether to disable storing history in transaction metadata.
|
|
58
|
+
* @param options.disableSendFlowHistory - Explicitly disable transaction metadata history.
|
|
54
59
|
* @param options.getNetworkState - Gets the state of the network controller.
|
|
55
60
|
* @param options.getSelectedAddress - Gets the address of the currently selected account.
|
|
56
61
|
* @param options.incomingTransactions - Configuration options for incoming transaction support.
|
|
57
|
-
* @param options.incomingTransactions.apiKey - An optional API key to use when fetching remote transaction data.
|
|
58
62
|
* @param options.incomingTransactions.includeTokenTransfers - Whether or not to include ERC20 token transfers.
|
|
59
63
|
* @param options.incomingTransactions.isEnabled - Whether or not incoming transaction retrieval is enabled.
|
|
60
|
-
* @param options.incomingTransactions.
|
|
64
|
+
* @param options.incomingTransactions.queryEntireHistory - Whether to initially query the entire transaction history or only recent blocks.
|
|
65
|
+
* @param options.incomingTransactions.updateTransactions - Whether to update local transactions using remote transaction data.
|
|
61
66
|
* @param options.messenger - The controller messenger.
|
|
62
67
|
* @param options.onNetworkStateChange - Allows subscribing to network controller state changes.
|
|
63
68
|
* @param options.provider - The provider used to create the underlying EthQuery instance.
|
|
64
69
|
* @param config - Initial options used to configure this controller.
|
|
65
70
|
* @param state - Initial state to set on this controller.
|
|
66
71
|
*/
|
|
67
|
-
constructor({ blockTracker, getNetworkState, getSelectedAddress, incomingTransactions = {}, messenger, onNetworkStateChange, provider, }, config, state) {
|
|
72
|
+
constructor({ blockTracker, disableHistory, disableSendFlowHistory, getNetworkState, getSelectedAddress, incomingTransactions = {}, messenger, onNetworkStateChange, provider, }, config, state) {
|
|
68
73
|
super(config, state);
|
|
69
74
|
this.mutex = new async_mutex_1.Mutex();
|
|
70
75
|
/**
|
|
@@ -89,6 +94,8 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
89
94
|
this.messagingSystem = messenger;
|
|
90
95
|
this.getNetworkState = getNetworkState;
|
|
91
96
|
this.ethQuery = new eth_query_1.default(provider);
|
|
97
|
+
this.isSendFlowHistoryDisabled = disableSendFlowHistory !== null && disableSendFlowHistory !== void 0 ? disableSendFlowHistory : false;
|
|
98
|
+
this.isHistoryDisabled = disableHistory !== null && disableHistory !== void 0 ? disableHistory : false;
|
|
92
99
|
this.registry = new eth_method_registry_1.default({ provider });
|
|
93
100
|
this.nonceTracker = new nonce_tracker_1.default({
|
|
94
101
|
provider,
|
|
@@ -99,10 +106,11 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
99
106
|
this.incomingTransactionHelper = new IncomingTransactionHelper_1.IncomingTransactionHelper({
|
|
100
107
|
blockTracker,
|
|
101
108
|
getCurrentAccount: getSelectedAddress,
|
|
109
|
+
getLastFetchedBlockNumbers: () => this.state.lastFetchedBlockNumbers,
|
|
102
110
|
getNetworkState,
|
|
103
111
|
isEnabled: incomingTransactions.isEnabled,
|
|
112
|
+
queryEntireHistory: incomingTransactions.queryEntireHistory,
|
|
104
113
|
remoteTransactionSource: new EtherscanRemoteTransactionSource_1.EtherscanRemoteTransactionSource({
|
|
105
|
-
apiKey: incomingTransactions.apiKey,
|
|
106
114
|
includeTokenTransfers: incomingTransactions.includeTokenTransfers,
|
|
107
115
|
}),
|
|
108
116
|
transactionLimit: this.config.txHistoryLimit,
|
|
@@ -118,7 +126,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
118
126
|
}
|
|
119
127
|
failTransaction(transactionMeta, error) {
|
|
120
128
|
const newTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { error, status: types_1.TransactionStatus.failed });
|
|
121
|
-
this.updateTransaction(newTransactionMeta);
|
|
129
|
+
this.updateTransaction(newTransactionMeta, 'TransactionController#failTransaction - Add error message and set status to failed');
|
|
122
130
|
this.hub.emit(`${transactionMeta.id}:finished`, newTransactionMeta);
|
|
123
131
|
}
|
|
124
132
|
registryLookup(fourBytePrefix) {
|
|
@@ -174,48 +182,69 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
174
182
|
* unique transaction id will be generated, and gas and gasPrice will be calculated
|
|
175
183
|
* if not provided. If A `<tx.id>:unapproved` hub event will be emitted once added.
|
|
176
184
|
*
|
|
177
|
-
* @param
|
|
185
|
+
* @param txParams - Standard parameters for an Ethereum transaction.
|
|
178
186
|
* @param opts - Additional options to control how the transaction is added.
|
|
187
|
+
* @param opts.actionId - Unique ID to prevent duplicate requests.
|
|
179
188
|
* @param opts.deviceConfirmedOn - An enum to indicate what device confirmed the transaction.
|
|
180
189
|
* @param opts.origin - The origin of the transaction request, such as a dApp hostname.
|
|
181
190
|
* @param opts.requireApproval - Whether the transaction requires approval by the user, defaults to true unless explicitly disabled.
|
|
182
191
|
* @param opts.securityAlertResponse - Response from security validator.
|
|
192
|
+
* @param opts.sendFlowHistory - The sendFlowHistory entries to add.
|
|
183
193
|
* @returns Object containing a promise resolving to the transaction hash if approved.
|
|
184
194
|
*/
|
|
185
|
-
addTransaction(
|
|
195
|
+
addTransaction(txParams, { actionId, deviceConfirmedOn, origin, requireApproval, securityAlertResponse, sendFlowHistory, } = {}) {
|
|
186
196
|
return __awaiter(this, void 0, void 0, function* () {
|
|
187
197
|
const { chainId, networkId } = this.getChainAndNetworkId();
|
|
188
198
|
const { transactions } = this.state;
|
|
189
|
-
|
|
190
|
-
(0, utils_1.
|
|
191
|
-
const dappSuggestedGasFees = this.generateDappSuggestedGasFees(
|
|
192
|
-
const
|
|
199
|
+
txParams = (0, utils_1.normalizeTxParams)(txParams);
|
|
200
|
+
(0, utils_1.validateTxParams)(txParams);
|
|
201
|
+
const dappSuggestedGasFees = this.generateDappSuggestedGasFees(txParams, origin);
|
|
202
|
+
const existingTransactionMeta = this.getTransactionWithActionId(actionId);
|
|
203
|
+
// If a request to add a transaction with the same actionId is submitted again, a new transaction will not be created for it.
|
|
204
|
+
const transactionMeta = existingTransactionMeta || {
|
|
205
|
+
// Add actionId to txMeta to check if same actionId is seen again
|
|
206
|
+
actionId,
|
|
207
|
+
chainId,
|
|
208
|
+
dappSuggestedGasFees,
|
|
209
|
+
deviceConfirmedOn,
|
|
193
210
|
id: (0, uuid_1.v1)(),
|
|
194
211
|
networkID: networkId !== null && networkId !== void 0 ? networkId : undefined,
|
|
195
|
-
chainId,
|
|
196
212
|
origin,
|
|
213
|
+
securityAlertResponse,
|
|
197
214
|
status: types_1.TransactionStatus.unapproved,
|
|
198
215
|
time: Date.now(),
|
|
199
|
-
|
|
200
|
-
|
|
216
|
+
txParams,
|
|
217
|
+
userEditedGasLimit: false,
|
|
201
218
|
verifiedOnBlockchain: false,
|
|
202
|
-
dappSuggestedGasFees,
|
|
203
|
-
securityAlertResponse,
|
|
204
219
|
};
|
|
205
220
|
try {
|
|
206
|
-
const { gas, estimateGasError } = yield this.estimateGas(
|
|
207
|
-
|
|
208
|
-
|
|
221
|
+
const { gas, estimateGasError } = yield this.estimateGas(txParams);
|
|
222
|
+
txParams.gas = gas;
|
|
223
|
+
txParams.estimateGasError = estimateGasError;
|
|
224
|
+
transactionMeta.originalGasEstimate = gas;
|
|
209
225
|
}
|
|
210
226
|
catch (error) {
|
|
211
227
|
this.failTransaction(transactionMeta, error);
|
|
212
228
|
return Promise.reject(error);
|
|
213
229
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
230
|
+
// Checks if a transaction already exists with a given actionId
|
|
231
|
+
if (!existingTransactionMeta) {
|
|
232
|
+
if (!this.isSendFlowHistoryDisabled) {
|
|
233
|
+
transactionMeta.sendFlowHistory = sendFlowHistory !== null && sendFlowHistory !== void 0 ? sendFlowHistory : [];
|
|
234
|
+
}
|
|
235
|
+
// Initial history push
|
|
236
|
+
if (!this.isHistoryDisabled) {
|
|
237
|
+
(0, history_1.addInitialHistorySnapshot)(transactionMeta);
|
|
238
|
+
}
|
|
239
|
+
transactions.push(transactionMeta);
|
|
240
|
+
this.update({
|
|
241
|
+
transactions: this.trimTransactionsForState(transactions),
|
|
242
|
+
});
|
|
243
|
+
this.hub.emit(`unapprovedTransaction`, transactionMeta);
|
|
244
|
+
}
|
|
217
245
|
return {
|
|
218
246
|
result: this.processApproval(transactionMeta, {
|
|
247
|
+
isExisting: Boolean(existingTransactionMeta),
|
|
219
248
|
requireApproval,
|
|
220
249
|
}),
|
|
221
250
|
transactionMeta,
|
|
@@ -253,18 +282,18 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
253
282
|
* Attempts to cancel a transaction based on its ID by setting its status to "rejected"
|
|
254
283
|
* and emitting a `<tx.id>:finished` hub event.
|
|
255
284
|
*
|
|
256
|
-
* @param
|
|
285
|
+
* @param transactionId - The ID of the transaction to cancel.
|
|
257
286
|
* @param gasValues - The gas values to use for the cancellation transaction.
|
|
258
287
|
* @param options - The options for the cancellation transaction.
|
|
259
288
|
* @param options.estimatedBaseFee - The estimated base fee of the transaction.
|
|
260
289
|
*/
|
|
261
|
-
stopTransaction(
|
|
290
|
+
stopTransaction(transactionId, gasValues, { estimatedBaseFee } = {}) {
|
|
262
291
|
var _a, _b;
|
|
263
292
|
return __awaiter(this, void 0, void 0, function* () {
|
|
264
293
|
if (gasValues) {
|
|
265
294
|
(0, utils_1.validateGasValues)(gasValues);
|
|
266
295
|
}
|
|
267
|
-
const transactionMeta = this.state.transactions.find(({ id }) => id ===
|
|
296
|
+
const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
|
|
268
297
|
if (!transactionMeta) {
|
|
269
298
|
return;
|
|
270
299
|
}
|
|
@@ -272,20 +301,20 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
272
301
|
throw new Error('No sign method defined.');
|
|
273
302
|
}
|
|
274
303
|
// gasPrice (legacy non EIP1559)
|
|
275
|
-
const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.
|
|
304
|
+
const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.txParams.gasPrice, exports.CANCEL_RATE);
|
|
276
305
|
const gasPriceFromValues = (0, utils_1.isGasPriceValue)(gasValues) && gasValues.gasPrice;
|
|
277
306
|
const newGasPrice = (gasPriceFromValues &&
|
|
278
307
|
(0, utils_1.validateMinimumIncrease)(gasPriceFromValues, minGasPrice)) ||
|
|
279
308
|
minGasPrice;
|
|
280
309
|
// maxFeePerGas (EIP1559)
|
|
281
|
-
const existingMaxFeePerGas = (_a = transactionMeta.
|
|
310
|
+
const existingMaxFeePerGas = (_a = transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.maxFeePerGas;
|
|
282
311
|
const minMaxFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxFeePerGas, exports.CANCEL_RATE);
|
|
283
312
|
const maxFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxFeePerGas;
|
|
284
313
|
const newMaxFeePerGas = (maxFeePerGasValues &&
|
|
285
314
|
(0, utils_1.validateMinimumIncrease)(maxFeePerGasValues, minMaxFeePerGas)) ||
|
|
286
315
|
(existingMaxFeePerGas && minMaxFeePerGas);
|
|
287
316
|
// maxPriorityFeePerGas (EIP1559)
|
|
288
|
-
const existingMaxPriorityFeePerGas = (_b = transactionMeta.
|
|
317
|
+
const existingMaxPriorityFeePerGas = (_b = transactionMeta.txParams) === null || _b === void 0 ? void 0 : _b.maxPriorityFeePerGas;
|
|
289
318
|
const minMaxPriorityFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxPriorityFeePerGas, exports.CANCEL_RATE);
|
|
290
319
|
const maxPriorityFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxPriorityFeePerGas;
|
|
291
320
|
const newMaxPriorityFeePerGas = (maxPriorityFeePerGasValues &&
|
|
@@ -293,27 +322,28 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
293
322
|
(existingMaxPriorityFeePerGas && minMaxPriorityFeePerGas);
|
|
294
323
|
const txParams = newMaxFeePerGas && newMaxPriorityFeePerGas
|
|
295
324
|
? {
|
|
296
|
-
from: transactionMeta.
|
|
297
|
-
gasLimit: transactionMeta.
|
|
325
|
+
from: transactionMeta.txParams.from,
|
|
326
|
+
gasLimit: transactionMeta.txParams.gas,
|
|
298
327
|
maxFeePerGas: newMaxFeePerGas,
|
|
299
328
|
maxPriorityFeePerGas: newMaxPriorityFeePerGas,
|
|
300
329
|
type: 2,
|
|
301
|
-
nonce: transactionMeta.
|
|
302
|
-
to: transactionMeta.
|
|
330
|
+
nonce: transactionMeta.txParams.nonce,
|
|
331
|
+
to: transactionMeta.txParams.from,
|
|
303
332
|
value: '0x0',
|
|
304
333
|
}
|
|
305
334
|
: {
|
|
306
|
-
from: transactionMeta.
|
|
307
|
-
gasLimit: transactionMeta.
|
|
335
|
+
from: transactionMeta.txParams.from,
|
|
336
|
+
gasLimit: transactionMeta.txParams.gas,
|
|
308
337
|
gasPrice: newGasPrice,
|
|
309
|
-
nonce: transactionMeta.
|
|
310
|
-
to: transactionMeta.
|
|
338
|
+
nonce: transactionMeta.txParams.nonce,
|
|
339
|
+
to: transactionMeta.txParams.from,
|
|
311
340
|
value: '0x0',
|
|
312
341
|
};
|
|
313
342
|
const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
|
|
314
|
-
const signedTx = yield this.sign(unsignedEthTx, transactionMeta.
|
|
315
|
-
|
|
316
|
-
|
|
343
|
+
const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
|
|
344
|
+
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
345
|
+
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
346
|
+
yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
|
|
317
347
|
transactionMeta.estimatedBaseFee = estimatedBaseFee;
|
|
318
348
|
transactionMeta.status = types_1.TransactionStatus.cancelled;
|
|
319
349
|
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
@@ -322,18 +352,23 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
322
352
|
/**
|
|
323
353
|
* Attempts to speed up a transaction increasing transaction gasPrice by ten percent.
|
|
324
354
|
*
|
|
325
|
-
* @param
|
|
326
|
-
* @param gasValues - The gas values to use for the speed up
|
|
355
|
+
* @param transactionId - The ID of the transaction to speed up.
|
|
356
|
+
* @param gasValues - The gas values to use for the speed up transaction.
|
|
327
357
|
* @param options - The options for the speed up transaction.
|
|
358
|
+
* @param options.actionId - Unique ID to prevent duplicate requests
|
|
328
359
|
* @param options.estimatedBaseFee - The estimated base fee of the transaction.
|
|
329
360
|
*/
|
|
330
|
-
speedUpTransaction(
|
|
361
|
+
speedUpTransaction(transactionId, gasValues, { actionId, estimatedBaseFee, } = {}) {
|
|
331
362
|
var _a, _b;
|
|
332
363
|
return __awaiter(this, void 0, void 0, function* () {
|
|
364
|
+
// If transaction is found for same action id, do not create a new speed up transaction.
|
|
365
|
+
if (this.getTransactionWithActionId(actionId)) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
333
368
|
if (gasValues) {
|
|
334
369
|
(0, utils_1.validateGasValues)(gasValues);
|
|
335
370
|
}
|
|
336
|
-
const transactionMeta = this.state.transactions.find(({ id }) => id ===
|
|
371
|
+
const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
|
|
337
372
|
/* istanbul ignore next */
|
|
338
373
|
if (!transactionMeta) {
|
|
339
374
|
return;
|
|
@@ -344,36 +379,36 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
344
379
|
}
|
|
345
380
|
const { transactions } = this.state;
|
|
346
381
|
// gasPrice (legacy non EIP1559)
|
|
347
|
-
const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.
|
|
382
|
+
const minGasPrice = (0, utils_1.getIncreasedPriceFromExisting)(transactionMeta.txParams.gasPrice, exports.SPEED_UP_RATE);
|
|
348
383
|
const gasPriceFromValues = (0, utils_1.isGasPriceValue)(gasValues) && gasValues.gasPrice;
|
|
349
384
|
const newGasPrice = (gasPriceFromValues &&
|
|
350
385
|
(0, utils_1.validateMinimumIncrease)(gasPriceFromValues, minGasPrice)) ||
|
|
351
386
|
minGasPrice;
|
|
352
387
|
// maxFeePerGas (EIP1559)
|
|
353
|
-
const existingMaxFeePerGas = (_a = transactionMeta.
|
|
388
|
+
const existingMaxFeePerGas = (_a = transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.maxFeePerGas;
|
|
354
389
|
const minMaxFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxFeePerGas, exports.SPEED_UP_RATE);
|
|
355
390
|
const maxFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxFeePerGas;
|
|
356
391
|
const newMaxFeePerGas = (maxFeePerGasValues &&
|
|
357
392
|
(0, utils_1.validateMinimumIncrease)(maxFeePerGasValues, minMaxFeePerGas)) ||
|
|
358
393
|
(existingMaxFeePerGas && minMaxFeePerGas);
|
|
359
394
|
// maxPriorityFeePerGas (EIP1559)
|
|
360
|
-
const existingMaxPriorityFeePerGas = (_b = transactionMeta.
|
|
395
|
+
const existingMaxPriorityFeePerGas = (_b = transactionMeta.txParams) === null || _b === void 0 ? void 0 : _b.maxPriorityFeePerGas;
|
|
361
396
|
const minMaxPriorityFeePerGas = (0, utils_1.getIncreasedPriceFromExisting)(existingMaxPriorityFeePerGas, exports.SPEED_UP_RATE);
|
|
362
397
|
const maxPriorityFeePerGasValues = (0, utils_1.isFeeMarketEIP1559Values)(gasValues) && gasValues.maxPriorityFeePerGas;
|
|
363
398
|
const newMaxPriorityFeePerGas = (maxPriorityFeePerGasValues &&
|
|
364
399
|
(0, utils_1.validateMinimumIncrease)(maxPriorityFeePerGasValues, minMaxPriorityFeePerGas)) ||
|
|
365
400
|
(existingMaxPriorityFeePerGas && minMaxPriorityFeePerGas);
|
|
366
401
|
const txParams = newMaxFeePerGas && newMaxPriorityFeePerGas
|
|
367
|
-
? Object.assign(Object.assign({}, transactionMeta.
|
|
402
|
+
? Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, maxFeePerGas: newMaxFeePerGas, maxPriorityFeePerGas: newMaxPriorityFeePerGas, type: 2 }) : Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas, gasPrice: newGasPrice });
|
|
368
403
|
const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
|
|
369
|
-
const signedTx = yield this.sign(unsignedEthTx, transactionMeta.
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
404
|
+
const signedTx = yield this.sign(unsignedEthTx, transactionMeta.txParams.from);
|
|
405
|
+
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
406
|
+
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
407
|
+
const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
|
|
408
|
+
const baseTransactionMeta = Object.assign(Object.assign({}, transactionMeta), { estimatedBaseFee, id: (0, uuid_1.v1)(), time: Date.now(), hash,
|
|
409
|
+
actionId, originalGasEstimate: transactionMeta.txParams.gas });
|
|
375
410
|
const newTransactionMeta = newMaxFeePerGas && newMaxPriorityFeePerGas
|
|
376
|
-
? Object.assign(Object.assign({}, baseTransactionMeta), {
|
|
411
|
+
? 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 }) });
|
|
377
412
|
transactions.push(newTransactionMeta);
|
|
378
413
|
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
379
414
|
this.hub.emit(`${transactionMeta.id}:speedup`, newTransactionMeta);
|
|
@@ -403,7 +438,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
403
438
|
false,
|
|
404
439
|
]);
|
|
405
440
|
// 2. If to is not defined or this is not a contract address, and there is no data use 0x5208 / 21000.
|
|
406
|
-
// If the
|
|
441
|
+
// If the network is a custom network then bypass this check and fetch 'estimateGas'.
|
|
407
442
|
/* istanbul ignore next */
|
|
408
443
|
const code = to ? yield (0, controller_utils_1.query)(this.ethQuery, 'getCode', [to]) : undefined;
|
|
409
444
|
/* istanbul ignore next */
|
|
@@ -484,11 +519,15 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
484
519
|
* Updates an existing transaction in state.
|
|
485
520
|
*
|
|
486
521
|
* @param transactionMeta - The new transaction to store in state.
|
|
522
|
+
* @param note - A note or update reason to include in the transaction history.
|
|
487
523
|
*/
|
|
488
|
-
updateTransaction(transactionMeta) {
|
|
524
|
+
updateTransaction(transactionMeta, note) {
|
|
489
525
|
const { transactions } = this.state;
|
|
490
|
-
transactionMeta.
|
|
491
|
-
(0, utils_1.
|
|
526
|
+
transactionMeta.txParams = (0, utils_1.normalizeTxParams)(transactionMeta.txParams);
|
|
527
|
+
(0, utils_1.validateTxParams)(transactionMeta.txParams);
|
|
528
|
+
if (!this.isHistoryDisabled) {
|
|
529
|
+
(0, history_1.updateTransactionHistory)(transactionMeta, note);
|
|
530
|
+
}
|
|
492
531
|
const index = transactions.findIndex(({ id }) => transactionMeta.id === id);
|
|
493
532
|
transactions[index] = transactionMeta;
|
|
494
533
|
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
@@ -508,7 +547,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
508
547
|
return;
|
|
509
548
|
}
|
|
510
549
|
const { chainId: currentChainId, networkId: currentNetworkID } = this.getChainAndNetworkId();
|
|
511
|
-
const newTransactions = this.state.transactions.filter(({ networkID, chainId,
|
|
550
|
+
const newTransactions = this.state.transactions.filter(({ networkID, chainId, txParams }) => {
|
|
512
551
|
var _a;
|
|
513
552
|
// Using fallback to networkID only when there is no chainId present. Should be removed when networkID is completely removed.
|
|
514
553
|
const isMatchingNetwork = ignoreNetwork ||
|
|
@@ -517,7 +556,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
517
556
|
if (!isMatchingNetwork) {
|
|
518
557
|
return true;
|
|
519
558
|
}
|
|
520
|
-
const isMatchingAddress = !address || ((_a =
|
|
559
|
+
const isMatchingAddress = !address || ((_a = txParams.from) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === address.toLowerCase();
|
|
521
560
|
return !isMatchingAddress;
|
|
522
561
|
});
|
|
523
562
|
this.update({
|
|
@@ -530,35 +569,145 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
530
569
|
stopIncomingTransactionProcessing() {
|
|
531
570
|
this.incomingTransactionHelper.stop();
|
|
532
571
|
}
|
|
533
|
-
|
|
572
|
+
/**
|
|
573
|
+
* Adds external provided transaction to state as confirmed transaction.
|
|
574
|
+
*
|
|
575
|
+
* @param transactionMeta - TransactionMeta to add transactions.
|
|
576
|
+
* @param transactionReceipt - TransactionReceipt of the external transaction.
|
|
577
|
+
* @param baseFeePerGas - Base fee per gas of the external transaction.
|
|
578
|
+
*/
|
|
579
|
+
confirmExternalTransaction(transactionMeta, transactionReceipt, baseFeePerGas) {
|
|
534
580
|
return __awaiter(this, void 0, void 0, function* () {
|
|
535
|
-
|
|
536
|
-
|
|
581
|
+
// Run validation and add external transaction to state.
|
|
582
|
+
this.addExternalTransaction(transactionMeta);
|
|
537
583
|
try {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
const { meta, isCompleted } = this.isTransactionCompleted(transactionId);
|
|
545
|
-
if (meta && !isCompleted) {
|
|
546
|
-
yield this.approveTransaction(transactionId);
|
|
584
|
+
const transactionId = transactionMeta.id;
|
|
585
|
+
// Make sure status is confirmed and define gasUsed as in receipt.
|
|
586
|
+
transactionMeta.status = types_1.TransactionStatus.confirmed;
|
|
587
|
+
transactionMeta.txReceipt = transactionReceipt;
|
|
588
|
+
if (baseFeePerGas) {
|
|
589
|
+
transactionMeta.baseFeePerGas = baseFeePerGas;
|
|
547
590
|
}
|
|
591
|
+
// Update same nonce local transactions as dropped and define replacedBy properties.
|
|
592
|
+
this.markNonceDuplicatesDropped(transactionId);
|
|
593
|
+
// Update external provided transaction with updated gas values and confirmed status.
|
|
594
|
+
this.updateTransaction(transactionMeta, 'TransactionController:confirmExternalTransaction - Add external transaction');
|
|
548
595
|
}
|
|
549
596
|
catch (error) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
597
|
+
console.error(error);
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Append new send flow history to a transaction.
|
|
603
|
+
*
|
|
604
|
+
* @param transactionID - The ID of the transaction to update.
|
|
605
|
+
* @param currentSendFlowHistoryLength - The length of the current sendFlowHistory array.
|
|
606
|
+
* @param sendFlowHistoryToAdd - The sendFlowHistory entries to add.
|
|
607
|
+
* @returns The updated transactionMeta.
|
|
608
|
+
*/
|
|
609
|
+
updateTransactionSendFlowHistory(transactionID, currentSendFlowHistoryLength, sendFlowHistoryToAdd) {
|
|
610
|
+
var _a, _b;
|
|
611
|
+
if (this.isSendFlowHistoryDisabled) {
|
|
612
|
+
throw new Error('Send flow history is disabled for the current transaction controller');
|
|
613
|
+
}
|
|
614
|
+
const transactionMeta = this.getTransaction(transactionID);
|
|
615
|
+
if (!transactionMeta) {
|
|
616
|
+
throw new Error(`Cannot update send flow history as no transaction metadata found`);
|
|
617
|
+
}
|
|
618
|
+
(0, utils_1.validateIfTransactionUnapproved)(transactionMeta, 'updateTransactionSendFlowHistory');
|
|
619
|
+
if (currentSendFlowHistoryLength ===
|
|
620
|
+
(((_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.sendFlowHistory) === null || _a === void 0 ? void 0 : _a.length) || 0)) {
|
|
621
|
+
transactionMeta.sendFlowHistory = [
|
|
622
|
+
...((_b = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.sendFlowHistory) !== null && _b !== void 0 ? _b : []),
|
|
623
|
+
...sendFlowHistoryToAdd,
|
|
624
|
+
];
|
|
625
|
+
this.updateTransaction(transactionMeta, 'TransactionController:updateTransactionSendFlowHistory - sendFlowHistory updated');
|
|
626
|
+
}
|
|
627
|
+
return this.getTransaction(transactionID);
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Update the gas values of a transaction.
|
|
631
|
+
*
|
|
632
|
+
* @param transactionId - The ID of the transaction to update.
|
|
633
|
+
* @param gasValues - Gas values to update.
|
|
634
|
+
* @param gasValues.gas - Same as transaction.gasLimit.
|
|
635
|
+
* @param gasValues.gasLimit - Maxmimum number of units of gas to use for this transaction.
|
|
636
|
+
* @param gasValues.gasPrice - Price per gas for legacy transactions.
|
|
637
|
+
* @param gasValues.maxPriorityFeePerGas - Maximum amount per gas to give to validator as incentive.
|
|
638
|
+
* @param gasValues.maxFeePerGas - Maximum amount per gas to pay for the transaction, including the priority fee.
|
|
639
|
+
* @param gasValues.estimateUsed - Which estimate level was used.
|
|
640
|
+
* @param gasValues.estimateSuggested - Which estimate level that the API suggested.
|
|
641
|
+
* @param gasValues.defaultGasEstimates - The default estimate for gas.
|
|
642
|
+
* @param gasValues.originalGasEstimate - Original estimate for gas.
|
|
643
|
+
* @param gasValues.userEditedGasLimit - The gas limit supplied by user.
|
|
644
|
+
* @param gasValues.userFeeLevel - Estimate level user selected.
|
|
645
|
+
* @returns The updated transactionMeta.
|
|
646
|
+
*/
|
|
647
|
+
updateTransactionGasFees(transactionId, { defaultGasEstimates, estimateUsed, estimateSuggested, gas, gasLimit, gasPrice, maxPriorityFeePerGas, maxFeePerGas, originalGasEstimate, userEditedGasLimit, userFeeLevel, }) {
|
|
648
|
+
const transactionMeta = this.getTransaction(transactionId);
|
|
649
|
+
if (!transactionMeta) {
|
|
650
|
+
throw new Error(`Cannot update transaction as no transaction metadata found`);
|
|
651
|
+
}
|
|
652
|
+
(0, utils_1.validateIfTransactionUnapproved)(transactionMeta, 'updateTransactionGasFees');
|
|
653
|
+
let transactionGasFees = {
|
|
654
|
+
txParams: {
|
|
655
|
+
gas,
|
|
656
|
+
gasLimit,
|
|
657
|
+
gasPrice,
|
|
658
|
+
maxPriorityFeePerGas,
|
|
659
|
+
maxFeePerGas,
|
|
660
|
+
},
|
|
661
|
+
defaultGasEstimates,
|
|
662
|
+
estimateUsed,
|
|
663
|
+
estimateSuggested,
|
|
664
|
+
originalGasEstimate,
|
|
665
|
+
userEditedGasLimit,
|
|
666
|
+
userFeeLevel,
|
|
667
|
+
};
|
|
668
|
+
// only update what is defined
|
|
669
|
+
transactionGasFees.txParams = (0, lodash_1.pickBy)(transactionGasFees.txParams);
|
|
670
|
+
transactionGasFees = (0, lodash_1.pickBy)(transactionGasFees);
|
|
671
|
+
// merge updated gas values with existing transaction meta
|
|
672
|
+
const updatedMeta = (0, lodash_1.merge)(transactionMeta, transactionGasFees);
|
|
673
|
+
this.updateTransaction(updatedMeta, 'TransactionController:updateTransactionGasFees - gas values updated');
|
|
674
|
+
return this.getTransaction(transactionId);
|
|
675
|
+
}
|
|
676
|
+
processApproval(transactionMeta, { isExisting = false, requireApproval, shouldShowRequest = true, }) {
|
|
677
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
678
|
+
const transactionId = transactionMeta.id;
|
|
679
|
+
let resultCallbacks;
|
|
680
|
+
const { meta, isCompleted } = this.isTransactionCompleted(transactionId);
|
|
681
|
+
const finishedPromise = isCompleted
|
|
682
|
+
? Promise.resolve(meta)
|
|
683
|
+
: this.waitForTransactionFinished(transactionId);
|
|
684
|
+
if (meta && !isExisting && !isCompleted) {
|
|
685
|
+
try {
|
|
686
|
+
if (requireApproval !== false) {
|
|
687
|
+
const acceptResult = yield this.requestApproval(transactionMeta, {
|
|
688
|
+
shouldShowRequest,
|
|
689
|
+
});
|
|
690
|
+
resultCallbacks = acceptResult.resultCallbacks;
|
|
555
691
|
}
|
|
556
|
-
|
|
557
|
-
|
|
692
|
+
const { isCompleted: isTxCompleted } = this.isTransactionCompleted(transactionId);
|
|
693
|
+
if (!isTxCompleted) {
|
|
694
|
+
yield this.approveTransaction(transactionId);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
const { isCompleted: isTxCompleted } = this.isTransactionCompleted(transactionId);
|
|
699
|
+
if (!isTxCompleted) {
|
|
700
|
+
if (error.code === eth_rpc_errors_1.errorCodes.provider.userRejectedRequest) {
|
|
701
|
+
this.cancelTransaction(transactionId);
|
|
702
|
+
throw eth_rpc_errors_1.ethErrors.provider.userRejectedRequest('User rejected the transaction');
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
this.failTransaction(meta, error);
|
|
706
|
+
}
|
|
558
707
|
}
|
|
559
708
|
}
|
|
560
709
|
}
|
|
561
|
-
const finalMeta =
|
|
710
|
+
const finalMeta = yield finishedPromise;
|
|
562
711
|
switch (finalMeta === null || finalMeta === void 0 ? void 0 : finalMeta.status) {
|
|
563
712
|
case types_1.TransactionStatus.failed:
|
|
564
713
|
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.error(finalMeta.error);
|
|
@@ -569,7 +718,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
569
718
|
throw cancelError;
|
|
570
719
|
case types_1.TransactionStatus.submitted:
|
|
571
720
|
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.success();
|
|
572
|
-
return finalMeta.
|
|
721
|
+
return finalMeta.hash;
|
|
573
722
|
default:
|
|
574
723
|
const internalError = eth_rpc_errors_1.ethErrors.rpc.internal(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finalMeta || transactionId)}`);
|
|
575
724
|
resultCallbacks === null || resultCallbacks === void 0 ? void 0 : resultCallbacks.error(internalError);
|
|
@@ -583,16 +732,16 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
583
732
|
* using the sign configuration property, then published to the blockchain.
|
|
584
733
|
* A `<tx.id>:finished` hub event is fired after success or failure.
|
|
585
734
|
*
|
|
586
|
-
* @param
|
|
735
|
+
* @param transactionId - The ID of the transaction to approve.
|
|
587
736
|
*/
|
|
588
|
-
approveTransaction(
|
|
737
|
+
approveTransaction(transactionId) {
|
|
589
738
|
return __awaiter(this, void 0, void 0, function* () {
|
|
590
739
|
const { transactions } = this.state;
|
|
591
740
|
const releaseLock = yield this.mutex.acquire();
|
|
592
741
|
const { chainId } = this.getChainAndNetworkId();
|
|
593
|
-
const index = transactions.findIndex(({ id }) =>
|
|
742
|
+
const index = transactions.findIndex(({ id }) => transactionId === id);
|
|
594
743
|
const transactionMeta = transactions[index];
|
|
595
|
-
const {
|
|
744
|
+
const { txParams: { nonce, from }, } = transactionMeta;
|
|
596
745
|
let nonceLock;
|
|
597
746
|
try {
|
|
598
747
|
if (!this.sign) {
|
|
@@ -614,12 +763,12 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
614
763
|
nonceToUse = (0, ethereumjs_util_1.addHexPrefix)(nonceLock.nextNonce.toString(16));
|
|
615
764
|
}
|
|
616
765
|
transactionMeta.status = status;
|
|
617
|
-
transactionMeta.
|
|
618
|
-
transactionMeta.
|
|
619
|
-
const baseTxParams = Object.assign(Object.assign({}, transactionMeta.
|
|
620
|
-
const isEIP1559 = (0, utils_1.isEIP1559Transaction)(transactionMeta.
|
|
766
|
+
transactionMeta.txParams.nonce = nonceToUse;
|
|
767
|
+
transactionMeta.txParams.chainId = chainId;
|
|
768
|
+
const baseTxParams = Object.assign(Object.assign({}, transactionMeta.txParams), { gasLimit: transactionMeta.txParams.gas });
|
|
769
|
+
const isEIP1559 = (0, utils_1.isEIP1559Transaction)(transactionMeta.txParams);
|
|
621
770
|
const txParams = isEIP1559
|
|
622
|
-
? Object.assign(Object.assign({}, baseTxParams), { maxFeePerGas: transactionMeta.
|
|
771
|
+
? Object.assign(Object.assign({}, baseTxParams), { maxFeePerGas: transactionMeta.txParams.maxFeePerGas, maxPriorityFeePerGas: transactionMeta.txParams.maxPriorityFeePerGas, estimatedBaseFee: transactionMeta.txParams.estimatedBaseFee,
|
|
623
772
|
// specify type 2 if maxFeePerGas and maxPriorityFeePerGas are set
|
|
624
773
|
type: 2 }) : baseTxParams;
|
|
625
774
|
// delete gasPrice if maxFeePerGas and maxPriorityFeePerGas are set
|
|
@@ -628,17 +777,17 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
628
777
|
}
|
|
629
778
|
const unsignedEthTx = this.prepareUnsignedEthTx(txParams);
|
|
630
779
|
const signedTx = yield this.sign(unsignedEthTx, from);
|
|
780
|
+
yield this.updateTransactionMetaRSV(transactionMeta, signedTx);
|
|
631
781
|
transactionMeta.status = types_1.TransactionStatus.signed;
|
|
632
|
-
this.updateTransaction(transactionMeta);
|
|
633
|
-
const
|
|
634
|
-
transactionMeta.
|
|
635
|
-
this.updateTransaction(transactionMeta);
|
|
636
|
-
const
|
|
637
|
-
|
|
638
|
-
]);
|
|
639
|
-
transactionMeta.transactionHash = transactionHash;
|
|
782
|
+
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction signed');
|
|
783
|
+
const rawTx = (0, ethereumjs_util_1.bufferToHex)(signedTx.serialize());
|
|
784
|
+
transactionMeta.rawTx = rawTx;
|
|
785
|
+
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - RawTransaction added');
|
|
786
|
+
const hash = yield (0, controller_utils_1.query)(this.ethQuery, 'sendRawTransaction', [rawTx]);
|
|
787
|
+
transactionMeta.hash = hash;
|
|
640
788
|
transactionMeta.status = types_1.TransactionStatus.submitted;
|
|
641
|
-
|
|
789
|
+
transactionMeta.submittedTime = new Date().getTime();
|
|
790
|
+
this.updateTransaction(transactionMeta, 'TransactionController#approveTransaction - Transaction submitted');
|
|
642
791
|
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
643
792
|
}
|
|
644
793
|
catch (error) {
|
|
@@ -657,16 +806,16 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
657
806
|
* Cancels a transaction based on its ID by setting its status to "rejected"
|
|
658
807
|
* and emitting a `<tx.id>:finished` hub event.
|
|
659
808
|
*
|
|
660
|
-
* @param
|
|
809
|
+
* @param transactionId - The ID of the transaction to cancel.
|
|
661
810
|
*/
|
|
662
|
-
cancelTransaction(
|
|
663
|
-
const transactionMeta = this.state.transactions.find(({ id }) => id ===
|
|
811
|
+
cancelTransaction(transactionId) {
|
|
812
|
+
const transactionMeta = this.state.transactions.find(({ id }) => id === transactionId);
|
|
664
813
|
if (!transactionMeta) {
|
|
665
814
|
return;
|
|
666
815
|
}
|
|
667
816
|
transactionMeta.status = types_1.TransactionStatus.rejected;
|
|
668
817
|
this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta);
|
|
669
|
-
const transactions = this.state.transactions.filter(({ id }) => id !==
|
|
818
|
+
const transactions = this.state.transactions.filter(({ id }) => id !== transactionId);
|
|
670
819
|
this.update({ transactions: this.trimTransactionsForState(transactions) });
|
|
671
820
|
}
|
|
672
821
|
/**
|
|
@@ -685,10 +834,12 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
685
834
|
*/
|
|
686
835
|
trimTransactionsForState(transactions) {
|
|
687
836
|
const nonceNetworkSet = new Set();
|
|
688
|
-
const txsToKeep = transactions
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
837
|
+
const txsToKeep = transactions
|
|
838
|
+
.sort((a, b) => (a.time > b.time ? -1 : 1)) // Descending time order
|
|
839
|
+
.filter((tx) => {
|
|
840
|
+
const { chainId, networkID, status, txParams, time } = tx;
|
|
841
|
+
if (txParams) {
|
|
842
|
+
const key = `${txParams.nonce}-${chainId ? (0, controller_utils_1.convertHexToDecimal)(chainId) : networkID}-${new Date(time).toDateString()}`;
|
|
692
843
|
if (nonceNetworkSet.has(key)) {
|
|
693
844
|
return true;
|
|
694
845
|
}
|
|
@@ -700,7 +851,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
700
851
|
}
|
|
701
852
|
return false;
|
|
702
853
|
});
|
|
703
|
-
txsToKeep.reverse();
|
|
854
|
+
txsToKeep.reverse(); // Ascending time order
|
|
704
855
|
return txsToKeep;
|
|
705
856
|
}
|
|
706
857
|
/**
|
|
@@ -738,11 +889,11 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
738
889
|
*/
|
|
739
890
|
blockchainTransactionStateReconciler(meta) {
|
|
740
891
|
return __awaiter(this, void 0, void 0, function* () {
|
|
741
|
-
const { status,
|
|
892
|
+
const { status, hash } = meta;
|
|
742
893
|
switch (status) {
|
|
743
894
|
case types_1.TransactionStatus.confirmed:
|
|
744
895
|
const txReceipt = yield (0, controller_utils_1.query)(this.ethQuery, 'getTransactionReceipt', [
|
|
745
|
-
|
|
896
|
+
hash,
|
|
746
897
|
]);
|
|
747
898
|
if (!txReceipt) {
|
|
748
899
|
return [meta, false];
|
|
@@ -751,7 +902,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
751
902
|
txReceipt.blockHash,
|
|
752
903
|
]);
|
|
753
904
|
meta.verifiedOnBlockchain = true;
|
|
754
|
-
meta.
|
|
905
|
+
meta.txParams.gasUsed = txReceipt.gasUsed;
|
|
755
906
|
meta.txReceipt = txReceipt;
|
|
756
907
|
meta.baseFeePerGas = txBlock === null || txBlock === void 0 ? void 0 : txBlock.baseFeePerGas;
|
|
757
908
|
meta.blockTimestamp = txBlock === null || txBlock === void 0 ? void 0 : txBlock.timestamp;
|
|
@@ -765,10 +916,10 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
765
916
|
return [meta, true];
|
|
766
917
|
case types_1.TransactionStatus.submitted:
|
|
767
918
|
const txObj = yield (0, controller_utils_1.query)(this.ethQuery, 'getTransactionByHash', [
|
|
768
|
-
|
|
919
|
+
hash,
|
|
769
920
|
]);
|
|
770
921
|
if (!txObj) {
|
|
771
|
-
const receiptShowsFailedStatus = yield this.checkTxReceiptStatusIsFailed(
|
|
922
|
+
const receiptShowsFailedStatus = yield this.checkTxReceiptStatusIsFailed(hash);
|
|
772
923
|
// Case the txObj is evaluated as false, a second check will
|
|
773
924
|
// determine if the tx failed or it is pending or confirmed
|
|
774
925
|
if (receiptShowsFailedStatus) {
|
|
@@ -824,15 +975,15 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
824
975
|
}, shouldShowRequest));
|
|
825
976
|
});
|
|
826
977
|
}
|
|
827
|
-
getTransaction(
|
|
978
|
+
getTransaction(transactionId) {
|
|
828
979
|
const { transactions } = this.state;
|
|
829
|
-
return transactions.find(({ id }) => id ===
|
|
980
|
+
return transactions.find(({ id }) => id === transactionId);
|
|
830
981
|
}
|
|
831
982
|
getApprovalId(txMeta) {
|
|
832
983
|
return String(txMeta.id);
|
|
833
984
|
}
|
|
834
|
-
isTransactionCompleted(
|
|
835
|
-
const transaction = this.getTransaction(
|
|
985
|
+
isTransactionCompleted(transactionId) {
|
|
986
|
+
const transaction = this.getTransaction(transactionId);
|
|
836
987
|
if (!transaction) {
|
|
837
988
|
return { meta: undefined, isCompleted: false };
|
|
838
989
|
}
|
|
@@ -879,7 +1030,7 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
879
1030
|
const updatedTransactions = [
|
|
880
1031
|
...added,
|
|
881
1032
|
...currentTransactions.map((originalTransaction) => {
|
|
882
|
-
const updatedTransaction = updated.find(({
|
|
1033
|
+
const updatedTransaction = updated.find(({ hash }) => hash === originalTransaction.hash);
|
|
883
1034
|
return updatedTransaction !== null && updatedTransaction !== void 0 ? updatedTransaction : originalTransaction;
|
|
884
1035
|
}),
|
|
885
1036
|
];
|
|
@@ -891,11 +1042,11 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
891
1042
|
this.update({ lastFetchedBlockNumbers });
|
|
892
1043
|
this.hub.emit('incomingTransactionBlock', blockNumber);
|
|
893
1044
|
}
|
|
894
|
-
generateDappSuggestedGasFees(
|
|
1045
|
+
generateDappSuggestedGasFees(txParams, origin) {
|
|
895
1046
|
if (!origin || origin === controller_utils_1.ORIGIN_METAMASK) {
|
|
896
1047
|
return undefined;
|
|
897
1048
|
}
|
|
898
|
-
const { gasPrice, maxFeePerGas, maxPriorityFeePerGas, gas } =
|
|
1049
|
+
const { gasPrice, maxFeePerGas, maxPriorityFeePerGas, gas } = txParams;
|
|
899
1050
|
if (gasPrice === undefined &&
|
|
900
1051
|
maxFeePerGas === undefined &&
|
|
901
1052
|
maxPriorityFeePerGas === undefined &&
|
|
@@ -916,6 +1067,112 @@ class TransactionController extends base_controller_1.BaseController {
|
|
|
916
1067
|
}
|
|
917
1068
|
return dappSuggestedGasFees;
|
|
918
1069
|
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Validates and adds external provided transaction to state.
|
|
1072
|
+
*
|
|
1073
|
+
* @param transactionMeta - Nominated external transaction to be added to state.
|
|
1074
|
+
*/
|
|
1075
|
+
addExternalTransaction(transactionMeta) {
|
|
1076
|
+
var _a, _b;
|
|
1077
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1078
|
+
const { networkId, chainId } = this.getChainAndNetworkId();
|
|
1079
|
+
const { transactions } = this.state;
|
|
1080
|
+
const fromAddress = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.from;
|
|
1081
|
+
const sameFromAndNetworkTransactions = transactions.filter((transaction) => transaction.txParams.from === fromAddress &&
|
|
1082
|
+
(0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
|
|
1083
|
+
const confirmedTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.confirmed);
|
|
1084
|
+
const pendingTxs = sameFromAndNetworkTransactions.filter((transaction) => transaction.status === types_1.TransactionStatus.submitted);
|
|
1085
|
+
(0, external_transactions_1.validateConfirmedExternalTransaction)(transactionMeta, confirmedTxs, pendingTxs);
|
|
1086
|
+
// Make sure provided external transaction has non empty history array
|
|
1087
|
+
if (!((_b = transactionMeta.history) !== null && _b !== void 0 ? _b : []).length) {
|
|
1088
|
+
if (!this.isHistoryDisabled) {
|
|
1089
|
+
(0, history_1.addInitialHistorySnapshot)(transactionMeta);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
const updatedTransactions = [...transactions, transactionMeta];
|
|
1093
|
+
this.update({
|
|
1094
|
+
transactions: this.trimTransactionsForState(updatedTransactions),
|
|
1095
|
+
});
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Sets other txMeta statuses to dropped if the txMeta that has been confirmed has other transactions
|
|
1100
|
+
* in the transactions have the same nonce.
|
|
1101
|
+
*
|
|
1102
|
+
* @param transactionId - Used to identify original transaction.
|
|
1103
|
+
*/
|
|
1104
|
+
markNonceDuplicatesDropped(transactionId) {
|
|
1105
|
+
var _a, _b;
|
|
1106
|
+
const { networkId, chainId } = this.getChainAndNetworkId();
|
|
1107
|
+
const transactionMeta = this.getTransaction(transactionId);
|
|
1108
|
+
const nonce = (_a = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _a === void 0 ? void 0 : _a.nonce;
|
|
1109
|
+
const from = (_b = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.txParams) === null || _b === void 0 ? void 0 : _b.from;
|
|
1110
|
+
const sameNonceTxs = this.state.transactions.filter((transaction) => transaction.txParams.from === from &&
|
|
1111
|
+
transaction.txParams.nonce === nonce &&
|
|
1112
|
+
(0, utils_1.transactionMatchesNetwork)(transaction, chainId, networkId));
|
|
1113
|
+
if (!sameNonceTxs.length) {
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
// Mark all same nonce transactions as dropped and give it a replacedBy hash
|
|
1117
|
+
for (const transaction of sameNonceTxs) {
|
|
1118
|
+
if (transaction.id === transactionId) {
|
|
1119
|
+
continue;
|
|
1120
|
+
}
|
|
1121
|
+
transaction.replacedBy = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.hash;
|
|
1122
|
+
transaction.replacedById = transactionMeta === null || transactionMeta === void 0 ? void 0 : transactionMeta.id;
|
|
1123
|
+
// Drop any transaction that wasn't previously failed (off chain failure)
|
|
1124
|
+
if (transaction.status !== types_1.TransactionStatus.failed) {
|
|
1125
|
+
this.setTransactionStatusDropped(transaction);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Method to set transaction status to dropped.
|
|
1131
|
+
*
|
|
1132
|
+
* @param transactionMeta - TransactionMeta of transaction to be marked as dropped.
|
|
1133
|
+
*/
|
|
1134
|
+
setTransactionStatusDropped(transactionMeta) {
|
|
1135
|
+
transactionMeta.status = types_1.TransactionStatus.dropped;
|
|
1136
|
+
this.updateTransaction(transactionMeta, 'TransactionController#setTransactionStatusDropped - Transaction dropped');
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Get transaction with provided actionId.
|
|
1140
|
+
*
|
|
1141
|
+
* @param actionId - Unique ID to prevent duplicate requests
|
|
1142
|
+
* @returns the filtered transaction
|
|
1143
|
+
*/
|
|
1144
|
+
getTransactionWithActionId(actionId) {
|
|
1145
|
+
return this.state.transactions.find((transaction) => actionId && transaction.actionId === actionId);
|
|
1146
|
+
}
|
|
1147
|
+
waitForTransactionFinished(transactionId) {
|
|
1148
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1149
|
+
return new Promise((resolve) => {
|
|
1150
|
+
this.hub.once(`${transactionId}:finished`, (txMeta) => {
|
|
1151
|
+
resolve(txMeta);
|
|
1152
|
+
});
|
|
1153
|
+
});
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Updates the r, s, and v properties of a TransactionMeta object
|
|
1158
|
+
* with values from a signed transaction.
|
|
1159
|
+
*
|
|
1160
|
+
* @param transactionMeta - The TransactionMeta object to update.
|
|
1161
|
+
* @param signedTx - The encompassing type for all transaction types containing r, s, and v values.
|
|
1162
|
+
*/
|
|
1163
|
+
updateTransactionMetaRSV(transactionMeta, signedTx) {
|
|
1164
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1165
|
+
if (signedTx.r) {
|
|
1166
|
+
transactionMeta.r = (0, ethereumjs_util_1.addHexPrefix)(signedTx.r.toString(16));
|
|
1167
|
+
}
|
|
1168
|
+
if (signedTx.s) {
|
|
1169
|
+
transactionMeta.s = (0, ethereumjs_util_1.addHexPrefix)(signedTx.s.toString(16));
|
|
1170
|
+
}
|
|
1171
|
+
if (signedTx.v) {
|
|
1172
|
+
transactionMeta.v = (0, ethereumjs_util_1.addHexPrefix)(signedTx.v.toString(16));
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
919
1176
|
}
|
|
920
1177
|
exports.TransactionController = TransactionController;
|
|
921
1178
|
exports.default = TransactionController;
|