@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
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,SAAS,GAAG;IACvB,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,KAAK;IACb,GAAG,EAAE,MAAM;IACX,WAAW,EAAE,MAAM;IACnB,QAAQ,EAAE,KAAK;IACf,gBAAgB,EAAE,OAAO;IACzB,OAAO,EAAE,MAAM;IACf,eAAe,EAAE,SAAS;IAC1B,SAAS,EAAE,QAAQ;IACnB,iBAAiB,EAAE,QAAQ;IAC3B,MAAM,EAAE,MAAM;IACd,cAAc,EAAE,OAAO;IACvB,OAAO,EAAE,UAAU;IACnB,YAAY,EAAE,QAAQ;IACtB,aAAa,EAAE,QAAQ;IACvB,QAAQ,EAAE,OAAO;IACjB,gBAAgB,EAAE,OAAO;IACzB,SAAS,EAAE,OAAO;IAClB,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,OAAO;CACX,CAAC;AAEE,QAAA,wBAAwB,GAAG,cAAc,CAAC;AAC1C,QAAA,kCAAkC,GAAG,KAAK,CAAC;AAE3C,QAAA,4BAA4B,GAAG;IAC1C,CAAC,iBAAS,CAAC,MAAM,CAAC,EAAE;QAClB,MAAM,EAAE,gCAAwB;QAChC,SAAS,EAAE,GAAG,0CAAkC,SAAS;KAC1D;IACD,CAAC,iBAAS,CAAC,OAAO,CAAC,EAAE;QACnB,MAAM,EAAE,gCAAwB;QAChC,SAAS,EAAE,0CAAkC;KAC9C;IACD,CAAC,iBAAS,CAAC,OAAO,CAAC,EAAE;QACnB,MAAM,EAAE,gCAAwB;QAChC,SAAS,EAAE,GAAG,0CAAkC,UAAU;KAC3D;IACD,CAAC,iBAAS,CAAC,YAAY,CAAC,EAAE;QACxB,MAAM,EAAE,iBAAiB;QACzB,SAAS,EAAE,QAAQ;KACpB;IACD,CAAC,iBAAS,CAAC,aAAa,CAAC,EAAE;QACzB,MAAM,EAAE,iBAAiB;QACzB,SAAS,EAAE,0CAAkC;KAC9C;IACD,CAAC,iBAAS,CAAC,GAAG,CAAC,EAAE;QACf,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,0CAAkC;KAC9C;IACD,CAAC,iBAAS,CAAC,WAAW,CAAC,EAAE;QACvB,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,GAAG,0CAAkC,UAAU;KAC3D;IACD,CAAC,iBAAS,CAAC,QAAQ,CAAC,EAAE;QACpB,MAAM,EAAE,gCAAwB;QAChC,SAAS,EAAE,GAAG,0CAAkC,aAAa;KAC9D;IACD,CAAC,iBAAS,CAAC,gBAAgB,CAAC,EAAE;QAC5B,MAAM,EAAE,gCAAwB;QAChC,SAAS,EAAE,GAAG,0CAAkC,oBAAoB;KACrE;IACD,CAAC,iBAAS,CAAC,OAAO,CAAC,EAAE;QACnB,MAAM,EAAE,iBAAiB;QACzB,SAAS,EAAE,0CAAkC;KAC9C;IACD,CAAC,iBAAS,CAAC,eAAe,CAAC,EAAE;QAC3B,MAAM,EAAE,iBAAiB;QACzB,SAAS,EAAE,GAAG,0CAAkC,SAAS;KAC1D;IACD,CAAC,iBAAS,CAAC,SAAS,CAAC,EAAE;QACrB,MAAM,EAAE,cAAc;QACtB,SAAS,EAAE,0CAAkC;KAC9C;IACD,CAAC,iBAAS,CAAC,iBAAiB,CAAC,EAAE;QAC7B,MAAM,EAAE,cAAc;QACtB,SAAS,EAAE,GAAG,0CAAkC,UAAU;KAC3D;IACD,CAAC,iBAAS,CAAC,MAAM,CAAC,EAAE;QAClB,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,0CAAkC;KAC9C;IACD,CAAC,iBAAS,CAAC,cAAc,CAAC,EAAE;QAC1B,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,GAAG,0CAAkC,UAAU;KAC3D;IACD,CAAC,iBAAS,CAAC,QAAQ,CAAC,EAAE;QACpB,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,GAAG,0CAAkC,WAAW;KAC5D;IACD,CAAC,iBAAS,CAAC,gBAAgB,CAAC,EAAE;QAC5B,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,GAAG,0CAAkC,WAAW;KAC5D;IACD,CAAC,iBAAS,CAAC,SAAS,CAAC,EAAE;QACrB,MAAM,EAAE,aAAa;QACrB,SAAS,EAAE,GAAG,0CAAkC,YAAY;KAC7D;IACD,CAAC,iBAAS,CAAC,MAAM,CAAC,EAAE;QAClB,MAAM,EAAE,eAAe;QACvB,SAAS,EAAE,GAAG,0CAAkC,SAAS;KAC1D;CACF,CAAC","sourcesContent":["export const CHAIN_IDS = {\n MAINNET: '0x1',\n GOERLI: '0x5',\n BSC: '0x38',\n BSC_TESTNET: '0x61',\n OPTIMISM: '0xa',\n OPTIMISM_TESTNET: '0x1a4',\n POLYGON: '0x89',\n POLYGON_TESTNET: '0x13881',\n AVALANCHE: '0xa86a',\n AVALANCHE_TESTNET: '0xa869',\n FANTOM: '0xfa',\n FANTOM_TESTNET: '0xfa2',\n SEPOLIA: '0xaa36a7',\n LINEA_GOERLI: '0xe704',\n LINEA_MAINNET: '0xe708',\n MOONBEAM: '0x504',\n MOONBEAM_TESTNET: '0x507',\n MOONRIVER: '0x505',\n GNOSIS: '0x64',\n ARBITRUM: '0xa4b1',\n ZKSYNC_ERA: '0x144',\n} as const;\n\nexport const DEFAULT_ETHERSCAN_DOMAIN = 'etherscan.io';\nexport const DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX = 'api';\n\nexport const ETHERSCAN_SUPPORTED_NETWORKS = {\n [CHAIN_IDS.GOERLI]: {\n domain: DEFAULT_ETHERSCAN_DOMAIN,\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-goerli`,\n },\n [CHAIN_IDS.MAINNET]: {\n domain: DEFAULT_ETHERSCAN_DOMAIN,\n subdomain: DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX,\n },\n [CHAIN_IDS.SEPOLIA]: {\n domain: DEFAULT_ETHERSCAN_DOMAIN,\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-sepolia`,\n },\n [CHAIN_IDS.LINEA_GOERLI]: {\n domain: 'lineascan.build',\n subdomain: 'goerli',\n },\n [CHAIN_IDS.LINEA_MAINNET]: {\n domain: 'lineascan.build',\n subdomain: DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX,\n },\n [CHAIN_IDS.BSC]: {\n domain: 'bscscan.com',\n subdomain: DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX,\n },\n [CHAIN_IDS.BSC_TESTNET]: {\n domain: 'bscscan.com',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-testnet`,\n },\n [CHAIN_IDS.OPTIMISM]: {\n domain: DEFAULT_ETHERSCAN_DOMAIN,\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-optimistic`,\n },\n [CHAIN_IDS.OPTIMISM_TESTNET]: {\n domain: DEFAULT_ETHERSCAN_DOMAIN,\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-goerli-optimistic`,\n },\n [CHAIN_IDS.POLYGON]: {\n domain: 'polygonscan.com',\n subdomain: DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX,\n },\n [CHAIN_IDS.POLYGON_TESTNET]: {\n domain: 'polygonscan.com',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-mumbai`,\n },\n [CHAIN_IDS.AVALANCHE]: {\n domain: 'snowtrace.io',\n subdomain: DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX,\n },\n [CHAIN_IDS.AVALANCHE_TESTNET]: {\n domain: 'snowtrace.io',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-testnet`,\n },\n [CHAIN_IDS.FANTOM]: {\n domain: 'ftmscan.com',\n subdomain: DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX,\n },\n [CHAIN_IDS.FANTOM_TESTNET]: {\n domain: 'ftmscan.com',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-testnet`,\n },\n [CHAIN_IDS.MOONBEAM]: {\n domain: 'moonscan.io',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-moonbeam`,\n },\n [CHAIN_IDS.MOONBEAM_TESTNET]: {\n domain: 'moonscan.io',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-moonbase`,\n },\n [CHAIN_IDS.MOONRIVER]: {\n domain: 'moonscan.io',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-moonriver`,\n },\n [CHAIN_IDS.GNOSIS]: {\n domain: 'gnosisscan.io',\n subdomain: `${DEFAULT_ETHERSCAN_SUBDOMAIN_PREFIX}-gnosis`,\n },\n};\n"]}
|
|
@@ -2,19 +2,37 @@
|
|
|
2
2
|
import type EthQuery from '@metamask/eth-query';
|
|
3
3
|
import type { BlockTracker } from '@metamask/network-controller';
|
|
4
4
|
import EventEmitter from 'events';
|
|
5
|
-
import type NonceTracker from 'nonce-tracker';
|
|
5
|
+
import type { NonceTracker } from 'nonce-tracker';
|
|
6
|
+
import type { TransactionState } from '../TransactionController';
|
|
6
7
|
import type { TransactionMeta } from '../types';
|
|
8
|
+
declare type Events = {
|
|
9
|
+
'transaction-confirmed': [txMeta: TransactionMeta];
|
|
10
|
+
'transaction-dropped': [txMeta: TransactionMeta];
|
|
11
|
+
'transaction-failed': [txMeta: TransactionMeta, error: Error];
|
|
12
|
+
'transaction-updated': [txMeta: TransactionMeta, note: string];
|
|
13
|
+
};
|
|
14
|
+
export interface PendingTransactionTrackerEventEmitter extends EventEmitter {
|
|
15
|
+
on<T extends keyof Events>(eventName: T, listener: (...args: Events[T]) => void): this;
|
|
16
|
+
emit<T extends keyof Events>(eventName: T, ...args: Events[T]): boolean;
|
|
17
|
+
}
|
|
7
18
|
export declare class PendingTransactionTracker {
|
|
8
19
|
#private;
|
|
9
|
-
hub:
|
|
10
|
-
constructor({
|
|
20
|
+
hub: PendingTransactionTrackerEventEmitter;
|
|
21
|
+
constructor({ approveTransaction, blockTracker, getChainId, getEthQuery, getTransactions, isResubmitEnabled, nonceTracker, onStateChange, publishTransaction, hooks, }: {
|
|
22
|
+
approveTransaction: (transactionId: string) => Promise<void>;
|
|
11
23
|
blockTracker: BlockTracker;
|
|
12
|
-
failTransaction: (txMeta: TransactionMeta, error: Error) => void;
|
|
13
24
|
getChainId: () => string;
|
|
14
25
|
getEthQuery: () => EthQuery;
|
|
15
26
|
getTransactions: () => TransactionMeta[];
|
|
27
|
+
isResubmitEnabled?: boolean;
|
|
16
28
|
nonceTracker: NonceTracker;
|
|
29
|
+
onStateChange: (listener: (state: TransactionState) => void) => void;
|
|
30
|
+
publishTransaction: (rawTx: string) => Promise<string>;
|
|
31
|
+
hooks?: {
|
|
32
|
+
beforeCheckPendingTransaction?: (transactionMeta: TransactionMeta) => boolean;
|
|
33
|
+
beforePublish?: (transactionMeta: TransactionMeta) => boolean;
|
|
34
|
+
};
|
|
17
35
|
});
|
|
18
|
-
start(): void;
|
|
19
36
|
}
|
|
37
|
+
export {};
|
|
20
38
|
//# sourceMappingURL=PendingTransactionTracker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PendingTransactionTracker.d.ts","sourceRoot":"","sources":["../../src/helpers/PendingTransactionTracker.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"PendingTransactionTracker.d.ts","sourceRoot":"","sources":["../../src/helpers/PendingTransactionTracker.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,UAAU,CAAC;AA2BpE,aAAK,MAAM,GAAG;IACZ,uBAAuB,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACnD,qBAAqB,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACjD,oBAAoB,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9D,qBAAqB,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;CAChE,CAAC;AAKF,MAAM,WAAW,qCAAsC,SAAQ,YAAY;IACzE,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EACvB,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,GACrC,IAAI,CAAC;IAER,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACzE;AAED,qBAAa,yBAAyB;;IACpC,GAAG,EAAE,qCAAqC,CAAC;gBA8B/B,EACV,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,KAAK,GACN,EAAE;QACD,kBAAkB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7D,YAAY,EAAE,YAAY,CAAC;QAC3B,UAAU,EAAE,MAAM,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,QAAQ,CAAC;QAC5B,eAAe,EAAE,MAAM,eAAe,EAAE,CAAC;QACzC,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,YAAY,EAAE,YAAY,CAAC;QAC3B,aAAa,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,KAAK,IAAI,CAAC;QACrE,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,KAAK,CAAC,EAAE;YACN,6BAA6B,CAAC,EAAE,CAC9B,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC;YACb,aAAa,CAAC,EAAE,CAAC,eAAe,EAAE,eAAe,KAAK,OAAO,CAAC;SAC/D,CAAC;KACH;CAgZF"}
|
|
@@ -22,153 +22,308 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
22
22
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
23
23
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
24
|
};
|
|
25
|
-
var _PendingTransactionTracker_instances, _PendingTransactionTracker_blockTracker,
|
|
25
|
+
var _PendingTransactionTracker_instances, _PendingTransactionTracker_approveTransaction, _PendingTransactionTracker_blockTracker, _PendingTransactionTracker_droppedBlockCountByHash, _PendingTransactionTracker_getChainId, _PendingTransactionTracker_getEthQuery, _PendingTransactionTracker_getTransactions, _PendingTransactionTracker_isResubmitEnabled, _PendingTransactionTracker_listener, _PendingTransactionTracker_nonceTracker, _PendingTransactionTracker_onStateChange, _PendingTransactionTracker_publishTransaction, _PendingTransactionTracker_running, _PendingTransactionTracker_beforeCheckPendingTransaction, _PendingTransactionTracker_beforePublish, _PendingTransactionTracker_start, _PendingTransactionTracker_stop, _PendingTransactionTracker_onLatestBlock, _PendingTransactionTracker_checkTransactions, _PendingTransactionTracker_resubmitTransactions, _PendingTransactionTracker_isKnownTransactionError, _PendingTransactionTracker_resubmitTransaction, _PendingTransactionTracker_isResubmitDue, _PendingTransactionTracker_checkTransaction, _PendingTransactionTracker_onTransactionConfirmed, _PendingTransactionTracker_isTransactionDropped, _PendingTransactionTracker_isNonceTaken, _PendingTransactionTracker_getPendingTransactions, _PendingTransactionTracker_warnTransaction, _PendingTransactionTracker_failTransaction, _PendingTransactionTracker_dropTransaction, _PendingTransactionTracker_updateTransaction, _PendingTransactionTracker_getTransactionReceipt, _PendingTransactionTracker_getBlockByHash, _PendingTransactionTracker_getNetworkTransactionCount;
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
27
|
exports.PendingTransactionTracker = void 0;
|
|
28
28
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
29
|
+
const utils_1 = require("@metamask/utils");
|
|
29
30
|
const events_1 = __importDefault(require("events"));
|
|
30
31
|
const logger_1 = require("../logger");
|
|
31
32
|
const types_1 = require("../types");
|
|
33
|
+
/**
|
|
34
|
+
* We wait this many blocks before emitting a 'transaction-dropped' event
|
|
35
|
+
* This is because we could be talking to a node that is out of sync
|
|
36
|
+
*/
|
|
37
|
+
const DROPPED_BLOCK_COUNT = 3;
|
|
38
|
+
const MAX_RETRY_BLOCK_DISTANCE = 50;
|
|
39
|
+
const KNOWN_TRANSACTION_ERRORS = [
|
|
40
|
+
'replacement transaction underpriced',
|
|
41
|
+
'known transaction',
|
|
42
|
+
'gas price too low to replace',
|
|
43
|
+
'transaction with the same hash was already imported',
|
|
44
|
+
'gateway timeout',
|
|
45
|
+
'nonce too low',
|
|
46
|
+
];
|
|
47
|
+
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'pending-transactions');
|
|
32
48
|
class PendingTransactionTracker {
|
|
33
|
-
constructor({
|
|
49
|
+
constructor({ approveTransaction, blockTracker, getChainId, getEthQuery, getTransactions, isResubmitEnabled, nonceTracker, onStateChange, publishTransaction, hooks, }) {
|
|
50
|
+
var _a, _b;
|
|
34
51
|
_PendingTransactionTracker_instances.add(this);
|
|
52
|
+
_PendingTransactionTracker_approveTransaction.set(this, void 0);
|
|
35
53
|
_PendingTransactionTracker_blockTracker.set(this, void 0);
|
|
36
|
-
|
|
54
|
+
_PendingTransactionTracker_droppedBlockCountByHash.set(this, void 0);
|
|
37
55
|
_PendingTransactionTracker_getChainId.set(this, void 0);
|
|
38
56
|
_PendingTransactionTracker_getEthQuery.set(this, void 0);
|
|
39
57
|
_PendingTransactionTracker_getTransactions.set(this, void 0);
|
|
58
|
+
_PendingTransactionTracker_isResubmitEnabled.set(this, void 0);
|
|
59
|
+
_PendingTransactionTracker_listener.set(this, void 0);
|
|
40
60
|
_PendingTransactionTracker_nonceTracker.set(this, void 0);
|
|
61
|
+
_PendingTransactionTracker_onStateChange.set(this, void 0);
|
|
62
|
+
_PendingTransactionTracker_publishTransaction.set(this, void 0);
|
|
63
|
+
_PendingTransactionTracker_running.set(this, void 0);
|
|
64
|
+
_PendingTransactionTracker_beforeCheckPendingTransaction.set(this, void 0);
|
|
65
|
+
_PendingTransactionTracker_beforePublish.set(this, void 0);
|
|
41
66
|
this.hub = new events_1.default();
|
|
67
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_approveTransaction, approveTransaction, "f");
|
|
42
68
|
__classPrivateFieldSet(this, _PendingTransactionTracker_blockTracker, blockTracker, "f");
|
|
43
|
-
__classPrivateFieldSet(this,
|
|
69
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_droppedBlockCountByHash, new Map(), "f");
|
|
44
70
|
__classPrivateFieldSet(this, _PendingTransactionTracker_getChainId, getChainId, "f");
|
|
45
71
|
__classPrivateFieldSet(this, _PendingTransactionTracker_getEthQuery, getEthQuery, "f");
|
|
46
72
|
__classPrivateFieldSet(this, _PendingTransactionTracker_getTransactions, getTransactions, "f");
|
|
73
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_isResubmitEnabled, isResubmitEnabled !== null && isResubmitEnabled !== void 0 ? isResubmitEnabled : true, "f");
|
|
74
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_listener, __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_onLatestBlock).bind(this), "f");
|
|
47
75
|
__classPrivateFieldSet(this, _PendingTransactionTracker_nonceTracker, nonceTracker, "f");
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/* istanbul ignore next */
|
|
58
|
-
(0, logger_1.pendingTransactionsLogger)('Error checking the status of submitted transactions', error);
|
|
76
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_onStateChange, onStateChange, "f");
|
|
77
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_publishTransaction, publishTransaction, "f");
|
|
78
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_running, false, "f");
|
|
79
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_beforePublish, (_a = hooks === null || hooks === void 0 ? void 0 : hooks.beforePublish) !== null && _a !== void 0 ? _a : (() => true), "f");
|
|
80
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_beforeCheckPendingTransaction, (_b = hooks === null || hooks === void 0 ? void 0 : hooks.beforeCheckPendingTransaction) !== null && _b !== void 0 ? _b : (() => true), "f");
|
|
81
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_onStateChange, "f").call(this, (state) => {
|
|
82
|
+
const pendingTransactions = __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_getPendingTransactions).call(this, state.transactions);
|
|
83
|
+
if (pendingTransactions.length) {
|
|
84
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_start).call(this);
|
|
59
85
|
}
|
|
60
|
-
|
|
61
|
-
|
|
86
|
+
else {
|
|
87
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_stop).call(this);
|
|
62
88
|
}
|
|
63
|
-
})
|
|
89
|
+
});
|
|
64
90
|
}
|
|
65
91
|
}
|
|
66
92
|
exports.PendingTransactionTracker = PendingTransactionTracker;
|
|
67
|
-
_PendingTransactionTracker_blockTracker = new WeakMap(),
|
|
93
|
+
_PendingTransactionTracker_approveTransaction = new WeakMap(), _PendingTransactionTracker_blockTracker = new WeakMap(), _PendingTransactionTracker_droppedBlockCountByHash = new WeakMap(), _PendingTransactionTracker_getChainId = new WeakMap(), _PendingTransactionTracker_getEthQuery = new WeakMap(), _PendingTransactionTracker_getTransactions = new WeakMap(), _PendingTransactionTracker_isResubmitEnabled = new WeakMap(), _PendingTransactionTracker_listener = new WeakMap(), _PendingTransactionTracker_nonceTracker = new WeakMap(), _PendingTransactionTracker_onStateChange = new WeakMap(), _PendingTransactionTracker_publishTransaction = new WeakMap(), _PendingTransactionTracker_running = new WeakMap(), _PendingTransactionTracker_beforeCheckPendingTransaction = new WeakMap(), _PendingTransactionTracker_beforePublish = new WeakMap(), _PendingTransactionTracker_instances = new WeakSet(), _PendingTransactionTracker_start = function _PendingTransactionTracker_start() {
|
|
94
|
+
if (__classPrivateFieldGet(this, _PendingTransactionTracker_running, "f")) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_blockTracker, "f").on('latest', __classPrivateFieldGet(this, _PendingTransactionTracker_listener, "f"));
|
|
98
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_running, true, "f");
|
|
99
|
+
log('Started polling');
|
|
100
|
+
}, _PendingTransactionTracker_stop = function _PendingTransactionTracker_stop() {
|
|
101
|
+
if (!__classPrivateFieldGet(this, _PendingTransactionTracker_running, "f")) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_blockTracker, "f").removeListener('latest', __classPrivateFieldGet(this, _PendingTransactionTracker_listener, "f"));
|
|
105
|
+
__classPrivateFieldSet(this, _PendingTransactionTracker_running, false, "f");
|
|
106
|
+
log('Stopped polling');
|
|
107
|
+
}, _PendingTransactionTracker_onLatestBlock = function _PendingTransactionTracker_onLatestBlock(latestBlockNumber) {
|
|
68
108
|
return __awaiter(this, void 0, void 0, function* () {
|
|
69
|
-
(
|
|
70
|
-
const transactions = __classPrivateFieldGet(this, _PendingTransactionTracker_getTransactions, "f").call(this);
|
|
71
|
-
const currentChainId = __classPrivateFieldGet(this, _PendingTransactionTracker_getChainId, "f").call(this);
|
|
72
|
-
(0, logger_1.pendingTransactionsLogger)('Current state', {
|
|
73
|
-
transactionCount: transactions.length,
|
|
74
|
-
currentChainId,
|
|
75
|
-
});
|
|
76
|
-
let gotUpdates = false;
|
|
109
|
+
const nonceGlobalLock = yield __classPrivateFieldGet(this, _PendingTransactionTracker_nonceTracker, "f").getGlobalLock();
|
|
77
110
|
try {
|
|
78
|
-
yield
|
|
79
|
-
if (!meta.verifiedOnBlockchain && meta.chainId === currentChainId) {
|
|
80
|
-
const [reconciledTx, updateRequired] = yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_blockchainTransactionStateReconciler).call(this, meta);
|
|
81
|
-
if (updateRequired) {
|
|
82
|
-
transactions[index] = reconciledTx;
|
|
83
|
-
gotUpdates = updateRequired;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
})));
|
|
111
|
+
yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_checkTransactions).call(this);
|
|
87
112
|
}
|
|
88
113
|
catch (error) {
|
|
89
|
-
|
|
114
|
+
/* istanbul ignore next */
|
|
115
|
+
log('Failed to check transactions', error);
|
|
90
116
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
117
|
+
finally {
|
|
118
|
+
nonceGlobalLock.releaseLock();
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_resubmitTransactions).call(this, latestBlockNumber);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
/* istanbul ignore next */
|
|
125
|
+
log('Failed to resubmit transactions', error);
|
|
94
126
|
}
|
|
95
127
|
});
|
|
96
|
-
},
|
|
128
|
+
}, _PendingTransactionTracker_checkTransactions = function _PendingTransactionTracker_checkTransactions() {
|
|
97
129
|
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
const txObj = yield (0, controller_utils_1.query)(__classPrivateFieldGet(this, _PendingTransactionTracker_getEthQuery, "f").call(this), 'getTransactionByHash', [
|
|
133
|
-
hash,
|
|
134
|
-
]);
|
|
135
|
-
if (!txObj) {
|
|
136
|
-
const receiptShowsFailedStatus = yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_checkTxReceiptStatusIsFailed).call(this, hash);
|
|
137
|
-
// Case the txObj is evaluated as false, a second check will
|
|
138
|
-
// determine if the tx failed or it is pending or confirmed
|
|
139
|
-
if (receiptShowsFailedStatus) {
|
|
140
|
-
const error = new Error('Transaction failed. The transaction was dropped or replaced by a new one');
|
|
141
|
-
__classPrivateFieldGet(this, _PendingTransactionTracker_failTransaction, "f").call(this, meta, error);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
130
|
+
log('Checking transactions');
|
|
131
|
+
const pendingTransactions = __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_getPendingTransactions).call(this);
|
|
132
|
+
if (!pendingTransactions.length) {
|
|
133
|
+
log('No pending transactions to check');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
log('Found pending transactions to check', {
|
|
137
|
+
count: pendingTransactions.length,
|
|
138
|
+
ids: pendingTransactions.map((tx) => tx.id),
|
|
139
|
+
});
|
|
140
|
+
yield Promise.all(pendingTransactions.map((tx) => __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_checkTransaction).call(this, tx)));
|
|
141
|
+
});
|
|
142
|
+
}, _PendingTransactionTracker_resubmitTransactions = function _PendingTransactionTracker_resubmitTransactions(latestBlockNumber) {
|
|
143
|
+
var _a, _b;
|
|
144
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
if (!__classPrivateFieldGet(this, _PendingTransactionTracker_isResubmitEnabled, "f") || !__classPrivateFieldGet(this, _PendingTransactionTracker_running, "f")) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
log('Resubmitting transactions');
|
|
149
|
+
const pendingTransactions = __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_getPendingTransactions).call(this);
|
|
150
|
+
if (!pendingTransactions.length) {
|
|
151
|
+
log('No pending transactions to resubmit');
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
log('Found pending transactions to resubmit', {
|
|
155
|
+
count: pendingTransactions.length,
|
|
156
|
+
ids: pendingTransactions.map((tx) => tx.id),
|
|
157
|
+
});
|
|
158
|
+
for (const txMeta of pendingTransactions) {
|
|
159
|
+
try {
|
|
160
|
+
yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_resubmitTransaction).call(this, txMeta, latestBlockNumber);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
144
163
|
/* istanbul ignore next */
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (txStatusFailed) {
|
|
150
|
-
const error = new Error('Transaction failed. The transaction was reversed');
|
|
151
|
-
__classPrivateFieldGet(this, _PendingTransactionTracker_failTransaction, "f").call(this, meta, error);
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
meta.status = types_1.TransactionStatus.confirmed;
|
|
155
|
-
this.hub.emit('transaction-confirmed', meta);
|
|
156
|
-
return [meta, true];
|
|
157
|
-
}
|
|
164
|
+
const errorMessage = ((_b = (_a = error.value) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.toLowerCase()) || error.message.toLowerCase();
|
|
165
|
+
if (__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_isKnownTransactionError).call(this, errorMessage)) {
|
|
166
|
+
log('Ignoring known transaction error', errorMessage);
|
|
167
|
+
return;
|
|
158
168
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
169
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_warnTransaction).call(this, txMeta, error.message, 'There was an error when resubmitting this transaction.');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}, _PendingTransactionTracker_isKnownTransactionError = function _PendingTransactionTracker_isKnownTransactionError(errorMessage) {
|
|
174
|
+
return KNOWN_TRANSACTION_ERRORS.some((knownError) => errorMessage.includes(knownError));
|
|
175
|
+
}, _PendingTransactionTracker_resubmitTransaction = function _PendingTransactionTracker_resubmitTransaction(txMeta, latestBlockNumber) {
|
|
176
|
+
var _a;
|
|
177
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
178
|
+
if (!__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_isResubmitDue).call(this, txMeta, latestBlockNumber)) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
log('Resubmitting transaction', txMeta.id);
|
|
182
|
+
const { rawTx } = txMeta;
|
|
183
|
+
if (!__classPrivateFieldGet(this, _PendingTransactionTracker_beforePublish, "f").call(this, txMeta)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!(rawTx === null || rawTx === void 0 ? void 0 : rawTx.length)) {
|
|
187
|
+
log('Approving transaction as no raw value');
|
|
188
|
+
yield __classPrivateFieldGet(this, _PendingTransactionTracker_approveTransaction, "f").call(this, txMeta.id);
|
|
189
|
+
return;
|
|
162
190
|
}
|
|
191
|
+
yield __classPrivateFieldGet(this, _PendingTransactionTracker_publishTransaction, "f").call(this, rawTx);
|
|
192
|
+
txMeta.retryCount = ((_a = txMeta.retryCount) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
193
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_updateTransaction).call(this, txMeta, 'PendingTransactionTracker:transaction-retry - Retry count increased');
|
|
163
194
|
});
|
|
164
|
-
},
|
|
195
|
+
}, _PendingTransactionTracker_isResubmitDue = function _PendingTransactionTracker_isResubmitDue(txMeta, latestBlockNumber) {
|
|
196
|
+
if (!txMeta.firstRetryBlockNumber) {
|
|
197
|
+
txMeta.firstRetryBlockNumber = latestBlockNumber;
|
|
198
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_updateTransaction).call(this, txMeta, 'PendingTransactionTracker:#isResubmitDue - First retry block number set');
|
|
199
|
+
}
|
|
200
|
+
const firstRetryBlockNumber = txMeta.firstRetryBlockNumber || latestBlockNumber;
|
|
201
|
+
const blocksSinceFirstRetry = Number.parseInt(latestBlockNumber, 16) -
|
|
202
|
+
Number.parseInt(firstRetryBlockNumber, 16);
|
|
203
|
+
const retryCount = txMeta.retryCount || 0;
|
|
204
|
+
// Exponential backoff to limit retries at publishing
|
|
205
|
+
// Capped at ~15 minutes between retries
|
|
206
|
+
const requiredBlocksSinceFirstRetry = Math.min(MAX_RETRY_BLOCK_DISTANCE, Math.pow(2, retryCount));
|
|
207
|
+
return blocksSinceFirstRetry >= requiredBlocksSinceFirstRetry;
|
|
208
|
+
}, _PendingTransactionTracker_checkTransaction = function _PendingTransactionTracker_checkTransaction(txMeta) {
|
|
165
209
|
return __awaiter(this, void 0, void 0, function* () {
|
|
166
|
-
const
|
|
167
|
-
if (!
|
|
168
|
-
|
|
210
|
+
const { hash, id } = txMeta;
|
|
211
|
+
if (!hash && __classPrivateFieldGet(this, _PendingTransactionTracker_beforeCheckPendingTransaction, "f").call(this, txMeta)) {
|
|
212
|
+
const error = new Error('We had an error while submitting this transaction, please try again.');
|
|
213
|
+
error.name = 'NoTxHashError';
|
|
214
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_failTransaction).call(this, txMeta, error);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_isNonceTaken).call(this, txMeta)) {
|
|
218
|
+
log('Nonce already taken', id);
|
|
219
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_dropTransaction).call(this, txMeta);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const receipt = yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_getTransactionReceipt).call(this, hash);
|
|
224
|
+
const isSuccess = (receipt === null || receipt === void 0 ? void 0 : receipt.status) === '0x1';
|
|
225
|
+
if (receipt && !isSuccess) {
|
|
226
|
+
log('Transaction receipt has failed status');
|
|
227
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_failTransaction).call(this, txMeta, new Error('Transaction dropped or replaced'));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const { blockNumber, blockHash } = receipt || {};
|
|
231
|
+
if (isSuccess && blockNumber && blockHash) {
|
|
232
|
+
yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_onTransactionConfirmed).call(this, txMeta, Object.assign(Object.assign({}, receipt), { blockNumber,
|
|
233
|
+
blockHash }));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
log('Failed to check transaction', id, error);
|
|
239
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_warnTransaction).call(this, txMeta, error.message, 'There was a problem loading this transaction.');
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_isTransactionDropped).call(this, txMeta)) {
|
|
243
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_dropTransaction).call(this, txMeta);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}, _PendingTransactionTracker_onTransactionConfirmed = function _PendingTransactionTracker_onTransactionConfirmed(txMeta, receipt) {
|
|
247
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
248
|
+
const { id } = txMeta;
|
|
249
|
+
const { blockHash } = receipt;
|
|
250
|
+
log('Transaction confirmed', id);
|
|
251
|
+
const { baseFeePerGas, timestamp: blockTimestamp } = yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_getBlockByHash).call(this, blockHash, false);
|
|
252
|
+
txMeta.baseFeePerGas = baseFeePerGas;
|
|
253
|
+
txMeta.blockTimestamp = blockTimestamp;
|
|
254
|
+
txMeta.status = types_1.TransactionStatus.confirmed;
|
|
255
|
+
txMeta.txParams.gasUsed = receipt.gasUsed;
|
|
256
|
+
txMeta.txReceipt = receipt;
|
|
257
|
+
txMeta.verifiedOnBlockchain = true;
|
|
258
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_updateTransaction).call(this, txMeta, 'PendingTransactionTracker:#onTransactionConfirmed - Transaction confirmed');
|
|
259
|
+
this.hub.emit('transaction-confirmed', txMeta);
|
|
260
|
+
});
|
|
261
|
+
}, _PendingTransactionTracker_isTransactionDropped = function _PendingTransactionTracker_isTransactionDropped(txMeta) {
|
|
262
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
263
|
+
const { hash, id, txParams: { nonce, from }, } = txMeta;
|
|
264
|
+
/* istanbul ignore next */
|
|
265
|
+
if (!nonce || !hash) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
const networkNextNonceHex = yield __classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_getNetworkTransactionCount).call(this, from);
|
|
269
|
+
const networkNextNonceNumber = parseInt(networkNextNonceHex, 16);
|
|
270
|
+
const nonceNumber = parseInt(nonce, 16);
|
|
271
|
+
if (nonceNumber >= networkNextNonceNumber) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
let droppedBlockCount = __classPrivateFieldGet(this, _PendingTransactionTracker_droppedBlockCountByHash, "f").get(hash);
|
|
275
|
+
if (droppedBlockCount === undefined) {
|
|
276
|
+
droppedBlockCount = 0;
|
|
277
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_droppedBlockCountByHash, "f").set(hash, droppedBlockCount);
|
|
278
|
+
}
|
|
279
|
+
if (droppedBlockCount < DROPPED_BLOCK_COUNT) {
|
|
280
|
+
log('Incrementing dropped block count', { id, droppedBlockCount });
|
|
281
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_droppedBlockCountByHash, "f").set(hash, droppedBlockCount + 1);
|
|
169
282
|
return false;
|
|
170
283
|
}
|
|
171
|
-
|
|
284
|
+
log('Hit dropped block count', id);
|
|
285
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_droppedBlockCountByHash, "f").delete(hash);
|
|
286
|
+
return true;
|
|
287
|
+
});
|
|
288
|
+
}, _PendingTransactionTracker_isNonceTaken = function _PendingTransactionTracker_isNonceTaken(txMeta) {
|
|
289
|
+
const { id, txParams } = txMeta;
|
|
290
|
+
return __classPrivateFieldGet(this, _PendingTransactionTracker_getTransactions, "f").call(this).some((tx) => tx.id !== id &&
|
|
291
|
+
tx.txParams.from === txParams.from &&
|
|
292
|
+
tx.status === types_1.TransactionStatus.confirmed &&
|
|
293
|
+
tx.txParams.nonce === txParams.nonce);
|
|
294
|
+
}, _PendingTransactionTracker_getPendingTransactions = function _PendingTransactionTracker_getPendingTransactions(transactions) {
|
|
295
|
+
const currentChainId = __classPrivateFieldGet(this, _PendingTransactionTracker_getChainId, "f").call(this);
|
|
296
|
+
return (transactions !== null && transactions !== void 0 ? transactions : __classPrivateFieldGet(this, _PendingTransactionTracker_getTransactions, "f").call(this)).filter((tx) => tx.status === types_1.TransactionStatus.submitted &&
|
|
297
|
+
tx.chainId === currentChainId &&
|
|
298
|
+
!tx.verifiedOnBlockchain);
|
|
299
|
+
}, _PendingTransactionTracker_warnTransaction = function _PendingTransactionTracker_warnTransaction(txMeta, error, message) {
|
|
300
|
+
txMeta.warning = {
|
|
301
|
+
error,
|
|
302
|
+
message,
|
|
303
|
+
};
|
|
304
|
+
__classPrivateFieldGet(this, _PendingTransactionTracker_instances, "m", _PendingTransactionTracker_updateTransaction).call(this, txMeta, 'PendingTransactionTracker:#warnTransaction - Warning added');
|
|
305
|
+
}, _PendingTransactionTracker_failTransaction = function _PendingTransactionTracker_failTransaction(txMeta, error) {
|
|
306
|
+
log('Transaction failed', txMeta.id, error);
|
|
307
|
+
this.hub.emit('transaction-failed', txMeta, error);
|
|
308
|
+
}, _PendingTransactionTracker_dropTransaction = function _PendingTransactionTracker_dropTransaction(txMeta) {
|
|
309
|
+
log('Transaction dropped', txMeta.id);
|
|
310
|
+
this.hub.emit('transaction-dropped', txMeta);
|
|
311
|
+
}, _PendingTransactionTracker_updateTransaction = function _PendingTransactionTracker_updateTransaction(txMeta, note) {
|
|
312
|
+
this.hub.emit('transaction-updated', txMeta, note);
|
|
313
|
+
}, _PendingTransactionTracker_getTransactionReceipt = function _PendingTransactionTracker_getTransactionReceipt(txHash) {
|
|
314
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
315
|
+
return yield (0, controller_utils_1.query)(__classPrivateFieldGet(this, _PendingTransactionTracker_getEthQuery, "f").call(this), 'getTransactionReceipt', [txHash]);
|
|
316
|
+
});
|
|
317
|
+
}, _PendingTransactionTracker_getBlockByHash = function _PendingTransactionTracker_getBlockByHash(blockHash, includeTransactionDetails) {
|
|
318
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
319
|
+
return yield (0, controller_utils_1.query)(__classPrivateFieldGet(this, _PendingTransactionTracker_getEthQuery, "f").call(this), 'getBlockByHash', [
|
|
320
|
+
blockHash,
|
|
321
|
+
includeTransactionDetails,
|
|
322
|
+
]);
|
|
323
|
+
});
|
|
324
|
+
}, _PendingTransactionTracker_getNetworkTransactionCount = function _PendingTransactionTracker_getNetworkTransactionCount(address) {
|
|
325
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
326
|
+
return yield (0, controller_utils_1.query)(__classPrivateFieldGet(this, _PendingTransactionTracker_getEthQuery, "f").call(this), 'getTransactionCount', [address]);
|
|
172
327
|
});
|
|
173
328
|
};
|
|
174
329
|
//# sourceMappingURL=PendingTransactionTracker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PendingTransactionTracker.js","sourceRoot":"","sources":["../../src/helpers/PendingTransactionTracker.ts"],"names":[],"mappings":"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","sourcesContent":["import { query } from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport type { BlockTracker } from '@metamask/network-controller';\nimport EventEmitter from 'events';\nimport type NonceTracker from 'nonce-tracker';\n\nimport { pendingTransactionsLogger as log } from '../logger';\nimport type { TransactionMeta } from '../types';\nimport { TransactionStatus } from '../types';\n\nexport class PendingTransactionTracker {\n hub: EventEmitter;\n\n #blockTracker: BlockTracker;\n\n #failTransaction: (txMeta: TransactionMeta, error: Error) => void;\n\n #getChainId: () => string;\n\n #getEthQuery: () => EthQuery;\n\n #getTransactions: () => TransactionMeta[];\n\n #nonceTracker: NonceTracker;\n\n constructor({\n blockTracker,\n failTransaction,\n getChainId,\n getEthQuery,\n getTransactions,\n nonceTracker,\n }: {\n blockTracker: BlockTracker;\n failTransaction: (txMeta: TransactionMeta, error: Error) => void;\n getChainId: () => string;\n getEthQuery: () => EthQuery;\n getTransactions: () => TransactionMeta[];\n nonceTracker: NonceTracker;\n }) {\n this.hub = new EventEmitter();\n\n this.#blockTracker = blockTracker;\n this.#failTransaction = failTransaction;\n this.#getChainId = getChainId;\n this.#getEthQuery = getEthQuery;\n this.#getTransactions = getTransactions;\n this.#nonceTracker = nonceTracker;\n }\n\n start() {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#blockTracker.addListener('latest', async () => {\n const nonceGlobalLock = await this.#nonceTracker.getGlobalLock();\n\n try {\n await this.#onLatestBlock();\n } catch (error) {\n /* istanbul ignore next */\n log('Error checking the status of submitted transactions', error);\n } finally {\n nonceGlobalLock.releaseLock();\n }\n });\n }\n\n /**\n * Check the status of submitted transactions on the network to determine whether they have\n * been included in a block. Any that have been included in a block are marked as confirmed.\n */\n async #onLatestBlock() {\n log('Checking transactions');\n\n const transactions = this.#getTransactions();\n const currentChainId = this.#getChainId();\n\n log('Current state', {\n transactionCount: transactions.length,\n currentChainId,\n });\n\n let gotUpdates = false;\n\n try {\n await Promise.all(\n transactions.map(async (meta, index) => {\n if (!meta.verifiedOnBlockchain && meta.chainId === currentChainId) {\n const [reconciledTx, updateRequired] =\n await this.#blockchainTransactionStateReconciler(meta);\n\n if (updateRequired) {\n transactions[index] = reconciledTx;\n gotUpdates = updateRequired;\n }\n }\n }),\n );\n } catch (error) {\n log('Error checking pending transactions', error);\n }\n\n /* istanbul ignore else */\n if (gotUpdates) {\n this.hub.emit('transactions', transactions);\n }\n }\n\n /**\n * Method to verify the state of a transaction using the Blockchain as a source of truth.\n *\n * @param meta - The local transaction to verify on the blockchain.\n * @returns A tuple containing the updated transaction, and whether or not an update was required.\n */\n async #blockchainTransactionStateReconciler(\n meta: TransactionMeta,\n ): Promise<[TransactionMeta, boolean]> {\n const {\n status,\n hash,\n id,\n chainId,\n txParams: { to },\n } = meta;\n\n switch (status) {\n case TransactionStatus.confirmed:\n log('Checking confirmed transaction', {\n id,\n chainId,\n to,\n });\n\n const txReceipt = await query(\n this.#getEthQuery(),\n 'getTransactionReceipt',\n [hash],\n );\n\n if (!txReceipt) {\n return [meta, false];\n }\n\n const txBlock = await query(this.#getEthQuery(), 'getBlockByHash', [\n txReceipt.blockHash,\n ]);\n\n meta.verifiedOnBlockchain = true;\n meta.txParams.gasUsed = txReceipt.gasUsed;\n meta.txReceipt = txReceipt;\n meta.baseFeePerGas = txBlock?.baseFeePerGas;\n meta.blockTimestamp = txBlock?.timestamp;\n\n // According to the Web3 docs:\n // TRUE if the transaction was successful, FALSE if the EVM reverted the transaction.\n if (Number(txReceipt.status) === 0) {\n const error: Error = new Error(\n 'Transaction failed. The transaction was reversed',\n );\n this.#failTransaction(meta, error);\n return [meta, false];\n }\n\n return [meta, true];\n case TransactionStatus.submitted:\n log('Checking submitted transaction', {\n id,\n chainId,\n to,\n });\n\n const txObj = await query(this.#getEthQuery(), 'getTransactionByHash', [\n hash,\n ]);\n\n if (!txObj) {\n const receiptShowsFailedStatus =\n await this.#checkTxReceiptStatusIsFailed(hash);\n\n // Case the txObj is evaluated as false, a second check will\n // determine if the tx failed or it is pending or confirmed\n if (receiptShowsFailedStatus) {\n const error: Error = new Error(\n 'Transaction failed. The transaction was dropped or replaced by a new one',\n );\n this.#failTransaction(meta, error);\n }\n }\n\n /* istanbul ignore next */\n if (txObj?.blockNumber) {\n // transactions can be added to a block and still fail,\n // check the transaction status before emitting the confirmed event\n const txStatusFailed = await this.#checkTxReceiptStatusIsFailed(hash);\n if (txStatusFailed) {\n const error = new Error(\n 'Transaction failed. The transaction was reversed',\n );\n this.#failTransaction(meta, error);\n } else {\n meta.status = TransactionStatus.confirmed;\n this.hub.emit('transaction-confirmed', meta);\n return [meta, true];\n }\n }\n\n return [meta, false];\n default:\n return [meta, false];\n }\n }\n\n /**\n * Method to check if a tx has failed according to their receipt\n * According to the Web3 docs:\n * TRUE if the transaction was successful, FALSE if the EVM reverted the transaction.\n * The receipt is not available for pending transactions and returns null.\n *\n * @param txHash - The transaction hash.\n * @returns Whether the transaction has failed.\n */\n async #checkTxReceiptStatusIsFailed(\n txHash: string | undefined,\n ): Promise<boolean> {\n const txReceipt = await query(\n this.#getEthQuery(),\n 'getTransactionReceipt',\n [txHash],\n );\n if (!txReceipt) {\n // Transaction is pending\n return false;\n }\n return Number(txReceipt.status) === 0;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"PendingTransactionTracker.js","sourceRoot":"","sources":["../../src/helpers/PendingTransactionTracker.ts"],"names":[],"mappings":"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","sourcesContent":["import { query } from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport type { BlockTracker } from '@metamask/network-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport EventEmitter from 'events';\nimport type { NonceTracker } from 'nonce-tracker';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionState } from '../TransactionController';\nimport type { TransactionMeta, TransactionReceipt } from '../types';\nimport { TransactionStatus } from '../types';\n\n/**\n * We wait this many blocks before emitting a 'transaction-dropped' event\n * This is because we could be talking to a node that is out of sync\n */\nconst DROPPED_BLOCK_COUNT = 3;\n\nconst MAX_RETRY_BLOCK_DISTANCE = 50;\n\nconst KNOWN_TRANSACTION_ERRORS = [\n 'replacement transaction underpriced',\n 'known transaction',\n 'gas price too low to replace',\n 'transaction with the same hash was already imported',\n 'gateway timeout',\n 'nonce too low',\n];\n\nconst log = createModuleLogger(projectLogger, 'pending-transactions');\n\ntype SuccessfulTransactionReceipt = TransactionReceipt & {\n blockNumber: string;\n blockHash: string;\n};\n\ntype Events = {\n 'transaction-confirmed': [txMeta: TransactionMeta];\n 'transaction-dropped': [txMeta: TransactionMeta];\n 'transaction-failed': [txMeta: TransactionMeta, error: Error];\n 'transaction-updated': [txMeta: TransactionMeta, note: string];\n};\n\n// This interface was created before this ESLint rule was added.\n// Convert to a `type` in a future major version.\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface PendingTransactionTrackerEventEmitter extends EventEmitter {\n on<T extends keyof Events>(\n eventName: T,\n listener: (...args: Events[T]) => void,\n ): this;\n\n emit<T extends keyof Events>(eventName: T, ...args: Events[T]): boolean;\n}\n\nexport class PendingTransactionTracker {\n hub: PendingTransactionTrackerEventEmitter;\n\n #approveTransaction: (transactionId: string) => Promise<void>;\n\n #blockTracker: BlockTracker;\n\n #droppedBlockCountByHash: Map<string, number>;\n\n #getChainId: () => string;\n\n #getEthQuery: () => EthQuery;\n\n #getTransactions: () => TransactionMeta[];\n\n #isResubmitEnabled: boolean;\n\n #listener: any;\n\n #nonceTracker: NonceTracker;\n\n #onStateChange: (listener: (state: TransactionState) => void) => void;\n\n #publishTransaction: (rawTx: string) => Promise<string>;\n\n #running: boolean;\n\n #beforeCheckPendingTransaction: (transactionMeta: TransactionMeta) => boolean;\n\n #beforePublish: (transactionMeta: TransactionMeta) => boolean;\n\n constructor({\n approveTransaction,\n blockTracker,\n getChainId,\n getEthQuery,\n getTransactions,\n isResubmitEnabled,\n nonceTracker,\n onStateChange,\n publishTransaction,\n hooks,\n }: {\n approveTransaction: (transactionId: string) => Promise<void>;\n blockTracker: BlockTracker;\n getChainId: () => string;\n getEthQuery: () => EthQuery;\n getTransactions: () => TransactionMeta[];\n isResubmitEnabled?: boolean;\n nonceTracker: NonceTracker;\n onStateChange: (listener: (state: TransactionState) => void) => void;\n publishTransaction: (rawTx: string) => Promise<string>;\n hooks?: {\n beforeCheckPendingTransaction?: (\n transactionMeta: TransactionMeta,\n ) => boolean;\n beforePublish?: (transactionMeta: TransactionMeta) => boolean;\n };\n }) {\n this.hub = new EventEmitter() as PendingTransactionTrackerEventEmitter;\n\n this.#approveTransaction = approveTransaction;\n this.#blockTracker = blockTracker;\n this.#droppedBlockCountByHash = new Map();\n this.#getChainId = getChainId;\n this.#getEthQuery = getEthQuery;\n this.#getTransactions = getTransactions;\n this.#isResubmitEnabled = isResubmitEnabled ?? true;\n this.#listener = this.#onLatestBlock.bind(this);\n this.#nonceTracker = nonceTracker;\n this.#onStateChange = onStateChange;\n this.#publishTransaction = publishTransaction;\n this.#running = false;\n this.#beforePublish = hooks?.beforePublish ?? (() => true);\n this.#beforeCheckPendingTransaction =\n hooks?.beforeCheckPendingTransaction ?? (() => true);\n\n this.#onStateChange((state) => {\n const pendingTransactions = this.#getPendingTransactions(\n state.transactions,\n );\n\n if (pendingTransactions.length) {\n this.#start();\n } else {\n this.#stop();\n }\n });\n }\n\n #start() {\n if (this.#running) {\n return;\n }\n\n this.#blockTracker.on('latest', this.#listener);\n this.#running = true;\n\n log('Started polling');\n }\n\n #stop() {\n if (!this.#running) {\n return;\n }\n\n this.#blockTracker.removeListener('latest', this.#listener);\n this.#running = false;\n\n log('Stopped polling');\n }\n\n async #onLatestBlock(latestBlockNumber: string) {\n const nonceGlobalLock = await this.#nonceTracker.getGlobalLock();\n\n try {\n await this.#checkTransactions();\n } catch (error) {\n /* istanbul ignore next */\n log('Failed to check transactions', error);\n } finally {\n nonceGlobalLock.releaseLock();\n }\n\n try {\n await this.#resubmitTransactions(latestBlockNumber);\n } catch (error) {\n /* istanbul ignore next */\n log('Failed to resubmit transactions', error);\n }\n }\n\n async #checkTransactions() {\n log('Checking transactions');\n\n const pendingTransactions = this.#getPendingTransactions();\n\n if (!pendingTransactions.length) {\n log('No pending transactions to check');\n return;\n }\n\n log('Found pending transactions to check', {\n count: pendingTransactions.length,\n ids: pendingTransactions.map((tx) => tx.id),\n });\n\n await Promise.all(\n pendingTransactions.map((tx) => this.#checkTransaction(tx)),\n );\n }\n\n async #resubmitTransactions(latestBlockNumber: string) {\n if (!this.#isResubmitEnabled || !this.#running) {\n return;\n }\n\n log('Resubmitting transactions');\n\n const pendingTransactions = this.#getPendingTransactions();\n\n if (!pendingTransactions.length) {\n log('No pending transactions to resubmit');\n return;\n }\n\n log('Found pending transactions to resubmit', {\n count: pendingTransactions.length,\n ids: pendingTransactions.map((tx) => tx.id),\n });\n\n for (const txMeta of pendingTransactions) {\n try {\n await this.#resubmitTransaction(txMeta, latestBlockNumber);\n } catch (error: any) {\n /* istanbul ignore next */\n const errorMessage =\n error.value?.message?.toLowerCase() || error.message.toLowerCase();\n\n if (this.#isKnownTransactionError(errorMessage)) {\n log('Ignoring known transaction error', errorMessage);\n return;\n }\n\n this.#warnTransaction(\n txMeta,\n error.message,\n 'There was an error when resubmitting this transaction.',\n );\n }\n }\n }\n\n #isKnownTransactionError(errorMessage: string) {\n return KNOWN_TRANSACTION_ERRORS.some((knownError) =>\n errorMessage.includes(knownError),\n );\n }\n\n async #resubmitTransaction(\n txMeta: TransactionMeta,\n latestBlockNumber: string,\n ) {\n if (!this.#isResubmitDue(txMeta, latestBlockNumber)) {\n return;\n }\n\n log('Resubmitting transaction', txMeta.id);\n\n const { rawTx } = txMeta;\n\n if (!this.#beforePublish(txMeta)) {\n return;\n }\n\n if (!rawTx?.length) {\n log('Approving transaction as no raw value');\n await this.#approveTransaction(txMeta.id);\n return;\n }\n\n await this.#publishTransaction(rawTx);\n\n txMeta.retryCount = (txMeta.retryCount ?? 0) + 1;\n\n this.#updateTransaction(\n txMeta,\n 'PendingTransactionTracker:transaction-retry - Retry count increased',\n );\n }\n\n #isResubmitDue(txMeta: TransactionMeta, latestBlockNumber: string): boolean {\n if (!txMeta.firstRetryBlockNumber) {\n txMeta.firstRetryBlockNumber = latestBlockNumber;\n\n this.#updateTransaction(\n txMeta,\n 'PendingTransactionTracker:#isResubmitDue - First retry block number set',\n );\n }\n\n const firstRetryBlockNumber =\n txMeta.firstRetryBlockNumber || latestBlockNumber;\n\n const blocksSinceFirstRetry =\n Number.parseInt(latestBlockNumber, 16) -\n Number.parseInt(firstRetryBlockNumber, 16);\n\n const retryCount = txMeta.retryCount || 0;\n\n // Exponential backoff to limit retries at publishing\n // Capped at ~15 minutes between retries\n const requiredBlocksSinceFirstRetry = Math.min(\n MAX_RETRY_BLOCK_DISTANCE,\n Math.pow(2, retryCount),\n );\n\n return blocksSinceFirstRetry >= requiredBlocksSinceFirstRetry;\n }\n\n async #checkTransaction(txMeta: TransactionMeta) {\n const { hash, id } = txMeta;\n\n if (!hash && this.#beforeCheckPendingTransaction(txMeta)) {\n const error = new Error(\n 'We had an error while submitting this transaction, please try again.',\n );\n\n error.name = 'NoTxHashError';\n\n this.#failTransaction(txMeta, error);\n\n return;\n }\n\n if (this.#isNonceTaken(txMeta)) {\n log('Nonce already taken', id);\n this.#dropTransaction(txMeta);\n return;\n }\n\n try {\n const receipt = await this.#getTransactionReceipt(hash);\n const isSuccess = receipt?.status === '0x1';\n\n if (receipt && !isSuccess) {\n log('Transaction receipt has failed status');\n\n this.#failTransaction(\n txMeta,\n new Error('Transaction dropped or replaced'),\n );\n\n return;\n }\n\n const { blockNumber, blockHash } = receipt || {};\n\n if (isSuccess && blockNumber && blockHash) {\n await this.#onTransactionConfirmed(txMeta, {\n ...receipt,\n blockNumber,\n blockHash,\n });\n\n return;\n }\n } catch (error: any) {\n log('Failed to check transaction', id, error);\n\n this.#warnTransaction(\n txMeta,\n error.message,\n 'There was a problem loading this transaction.',\n );\n\n return;\n }\n\n if (await this.#isTransactionDropped(txMeta)) {\n this.#dropTransaction(txMeta);\n }\n }\n\n async #onTransactionConfirmed(\n txMeta: TransactionMeta,\n receipt: SuccessfulTransactionReceipt,\n ) {\n const { id } = txMeta;\n const { blockHash } = receipt;\n\n log('Transaction confirmed', id);\n\n const { baseFeePerGas, timestamp: blockTimestamp } =\n await this.#getBlockByHash(blockHash, false);\n\n txMeta.baseFeePerGas = baseFeePerGas;\n txMeta.blockTimestamp = blockTimestamp;\n txMeta.status = TransactionStatus.confirmed;\n txMeta.txParams.gasUsed = receipt.gasUsed;\n txMeta.txReceipt = receipt;\n txMeta.verifiedOnBlockchain = true;\n\n this.#updateTransaction(\n txMeta,\n 'PendingTransactionTracker:#onTransactionConfirmed - Transaction confirmed',\n );\n\n this.hub.emit('transaction-confirmed', txMeta);\n }\n\n async #isTransactionDropped(txMeta: TransactionMeta) {\n const {\n hash,\n id,\n txParams: { nonce, from },\n } = txMeta;\n\n /* istanbul ignore next */\n if (!nonce || !hash) {\n return false;\n }\n\n const networkNextNonceHex = await this.#getNetworkTransactionCount(from);\n const networkNextNonceNumber = parseInt(networkNextNonceHex, 16);\n const nonceNumber = parseInt(nonce, 16);\n\n if (nonceNumber >= networkNextNonceNumber) {\n return false;\n }\n\n let droppedBlockCount = this.#droppedBlockCountByHash.get(hash);\n\n if (droppedBlockCount === undefined) {\n droppedBlockCount = 0;\n this.#droppedBlockCountByHash.set(hash, droppedBlockCount);\n }\n\n if (droppedBlockCount < DROPPED_BLOCK_COUNT) {\n log('Incrementing dropped block count', { id, droppedBlockCount });\n this.#droppedBlockCountByHash.set(hash, droppedBlockCount + 1);\n return false;\n }\n\n log('Hit dropped block count', id);\n\n this.#droppedBlockCountByHash.delete(hash);\n return true;\n }\n\n #isNonceTaken(txMeta: TransactionMeta): boolean {\n const { id, txParams } = txMeta;\n\n return this.#getTransactions().some(\n (tx) =>\n tx.id !== id &&\n tx.txParams.from === txParams.from &&\n tx.status === TransactionStatus.confirmed &&\n tx.txParams.nonce === txParams.nonce,\n );\n }\n\n #getPendingTransactions(transactions?: TransactionMeta[]): TransactionMeta[] {\n const currentChainId = this.#getChainId();\n\n return (transactions ?? this.#getTransactions()).filter(\n (tx) =>\n tx.status === TransactionStatus.submitted &&\n tx.chainId === currentChainId &&\n !tx.verifiedOnBlockchain,\n );\n }\n\n #warnTransaction(txMeta: TransactionMeta, error: string, message: string) {\n txMeta.warning = {\n error,\n message,\n };\n\n this.#updateTransaction(\n txMeta,\n 'PendingTransactionTracker:#warnTransaction - Warning added',\n );\n }\n\n #failTransaction(txMeta: TransactionMeta, error: Error) {\n log('Transaction failed', txMeta.id, error);\n this.hub.emit('transaction-failed', txMeta, error);\n }\n\n #dropTransaction(txMeta: TransactionMeta) {\n log('Transaction dropped', txMeta.id);\n this.hub.emit('transaction-dropped', txMeta);\n }\n\n #updateTransaction(txMeta: TransactionMeta, note: string) {\n this.hub.emit('transaction-updated', txMeta, note);\n }\n\n async #getTransactionReceipt(\n txHash?: string,\n ): Promise<TransactionReceipt | undefined> {\n return await query(this.#getEthQuery(), 'getTransactionReceipt', [txHash]);\n }\n\n async #getBlockByHash(\n blockHash: string,\n includeTransactionDetails: boolean,\n ): Promise<any> {\n return await query(this.#getEthQuery(), 'getBlockByHash', [\n blockHash,\n includeTransactionDetails,\n ]);\n }\n\n async #getNetworkTransactionCount(address: string): Promise<string> {\n return await query(this.#getEthQuery(), 'getTransactionCount', [address]);\n }\n}\n"]}
|
package/dist/logger.d.ts
CHANGED
|
@@ -2,6 +2,5 @@
|
|
|
2
2
|
import { createModuleLogger } from '@metamask/utils';
|
|
3
3
|
export declare const projectLogger: import("debug").Debugger;
|
|
4
4
|
export declare const incomingTransactionsLogger: import("debug").Debugger;
|
|
5
|
-
export declare const pendingTransactionsLogger: import("debug").Debugger;
|
|
6
5
|
export { createModuleLogger };
|
|
7
6
|
//# sourceMappingURL=logger.d.ts.map
|