@metamask/transaction-controller 7.1.0 → 8.0.1
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 +12 -1
- package/dist/EtherscanRemoteTransactionSource.d.ts +15 -0
- package/dist/EtherscanRemoteTransactionSource.d.ts.map +1 -0
- package/dist/EtherscanRemoteTransactionSource.js +87 -0
- package/dist/EtherscanRemoteTransactionSource.js.map +1 -0
- package/dist/IncomingTransactionHelper.d.ts +23 -0
- package/dist/IncomingTransactionHelper.d.ts.map +1 -0
- package/dist/IncomingTransactionHelper.js +144 -0
- package/dist/IncomingTransactionHelper.js.map +1 -0
- package/dist/TransactionController.d.ts +14 -214
- package/dist/TransactionController.d.ts.map +1 -1
- package/dist/TransactionController.js +57 -258
- package/dist/TransactionController.js.map +1 -1
- package/dist/etherscan.d.ts +66 -0
- package/dist/etherscan.d.ts.map +1 -0
- package/dist/etherscan.js +114 -0
- package/dist/etherscan.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +139 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +29 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +2 -24
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -78
- package/dist/utils.js.map +1 -1
- package/package.json +13 -12
- package/dist/mocks/txsMock.d.ts +0 -64
- package/dist/mocks/txsMock.d.ts.map +0 -1
- package/dist/mocks/txsMock.js +0 -516
- package/dist/mocks/txsMock.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [8.0.1]
|
|
10
|
+
### Changed
|
|
11
|
+
- Replace `eth-query` ^2.1.2 with `@metamask/eth-query` ^3.0.1 ([#1546](https://github.com/MetaMask/core/pull/1546))
|
|
12
|
+
|
|
13
|
+
## [8.0.0]
|
|
14
|
+
### Changed
|
|
15
|
+
- **BREAKING**: Change `babel-runtime` from a `dependency` to a `peerDependency` ([#1504](https://github.com/MetaMask/core/pull/1504))
|
|
16
|
+
- Update `@metamask/utils` to `^6.2.0` ([#1514](https://github.com/MetaMask/core/pull/1514))
|
|
17
|
+
|
|
9
18
|
## [7.1.0]
|
|
10
19
|
### Added
|
|
11
20
|
- Expose `HARDFORK` constant ([#1423](https://github.com/MetaMask/core/pull/1423))
|
|
@@ -89,7 +98,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
89
98
|
|
|
90
99
|
All changes listed after this point were applied to this package following the monorepo conversion.
|
|
91
100
|
|
|
92
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@
|
|
101
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@8.0.1...HEAD
|
|
102
|
+
[8.0.1]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@8.0.0...@metamask/transaction-controller@8.0.1
|
|
103
|
+
[8.0.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@7.1.0...@metamask/transaction-controller@8.0.0
|
|
93
104
|
[7.1.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@7.0.0...@metamask/transaction-controller@7.1.0
|
|
94
105
|
[7.0.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@6.1.0...@metamask/transaction-controller@7.0.0
|
|
95
106
|
[6.1.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@6.0.0...@metamask/transaction-controller@6.1.0
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RemoteTransactionSource, RemoteTransactionSourceRequest, TransactionMeta } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* A RemoteTransactionSource that fetches transaction data from Etherscan.
|
|
4
|
+
*/
|
|
5
|
+
export declare class EtherscanRemoteTransactionSource implements RemoteTransactionSource {
|
|
6
|
+
#private;
|
|
7
|
+
/**
|
|
8
|
+
* Retrieve transaction data from Etherscan.
|
|
9
|
+
*
|
|
10
|
+
* @param request - The configuration required to fetch Etherscan transaction data.
|
|
11
|
+
* @returns An array of transaction metadata.
|
|
12
|
+
*/
|
|
13
|
+
fetchTransactions(request: RemoteTransactionSourceRequest): Promise<TransactionMeta[]>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=EtherscanRemoteTransactionSource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EtherscanRemoteTransactionSource.d.ts","sourceRoot":"","sources":["../src/EtherscanRemoteTransactionSource.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,uBAAuB,EACvB,8BAA8B,EAC9B,eAAe,EAChB,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,gCACX,YAAW,uBAAuB;;IAElC;;;;;OAKG;IACG,iBAAiB,CACrB,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,eAAe,EAAE,CAAC;CAqG9B"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
12
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
13
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
14
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
15
|
+
};
|
|
16
|
+
var _EtherscanRemoteTransactionSource_instances, _EtherscanRemoteTransactionSource_normalizeTransaction, _EtherscanRemoteTransactionSource_normalizeTokenTransaction, _EtherscanRemoteTransactionSource_normalizeTransactionBase;
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.EtherscanRemoteTransactionSource = void 0;
|
|
19
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
20
|
+
const ethereumjs_util_1 = require("ethereumjs-util");
|
|
21
|
+
const uuid_1 = require("uuid");
|
|
22
|
+
const etherscan_1 = require("./etherscan");
|
|
23
|
+
const types_1 = require("./types");
|
|
24
|
+
/**
|
|
25
|
+
* A RemoteTransactionSource that fetches transaction data from Etherscan.
|
|
26
|
+
*/
|
|
27
|
+
class EtherscanRemoteTransactionSource {
|
|
28
|
+
constructor() {
|
|
29
|
+
_EtherscanRemoteTransactionSource_instances.add(this);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Retrieve transaction data from Etherscan.
|
|
33
|
+
*
|
|
34
|
+
* @param request - The configuration required to fetch Etherscan transaction data.
|
|
35
|
+
* @returns An array of transaction metadata.
|
|
36
|
+
*/
|
|
37
|
+
fetchTransactions(request) {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
const [etherscanTransactions, etherscanTokenTransactions] = yield Promise.all([
|
|
40
|
+
(0, etherscan_1.fetchEtherscanTransactions)(request),
|
|
41
|
+
(0, etherscan_1.fetchEtherscanTokenTransactions)(request),
|
|
42
|
+
]);
|
|
43
|
+
const transactions = etherscanTransactions.result.map((tx) => __classPrivateFieldGet(this, _EtherscanRemoteTransactionSource_instances, "m", _EtherscanRemoteTransactionSource_normalizeTransaction).call(this, tx, request.currentNetworkId, request.currentChainId));
|
|
44
|
+
const tokenTransactions = etherscanTokenTransactions.result.map((tx) => __classPrivateFieldGet(this, _EtherscanRemoteTransactionSource_instances, "m", _EtherscanRemoteTransactionSource_normalizeTokenTransaction).call(this, tx, request.currentNetworkId, request.currentChainId));
|
|
45
|
+
return [...transactions, ...tokenTransactions];
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.EtherscanRemoteTransactionSource = EtherscanRemoteTransactionSource;
|
|
50
|
+
_EtherscanRemoteTransactionSource_instances = new WeakSet(), _EtherscanRemoteTransactionSource_normalizeTransaction = function _EtherscanRemoteTransactionSource_normalizeTransaction(txMeta, currentNetworkId, currentChainId) {
|
|
51
|
+
const base = __classPrivateFieldGet(this, _EtherscanRemoteTransactionSource_instances, "m", _EtherscanRemoteTransactionSource_normalizeTransactionBase).call(this, txMeta, currentNetworkId, currentChainId);
|
|
52
|
+
return Object.assign(Object.assign(Object.assign({}, base), { transaction: Object.assign(Object.assign({}, base.transaction), { data: txMeta.input }) }), (txMeta.isError === '0'
|
|
53
|
+
? { status: types_1.TransactionStatus.confirmed }
|
|
54
|
+
: {
|
|
55
|
+
error: new Error('Transaction failed'),
|
|
56
|
+
status: types_1.TransactionStatus.failed,
|
|
57
|
+
}));
|
|
58
|
+
}, _EtherscanRemoteTransactionSource_normalizeTokenTransaction = function _EtherscanRemoteTransactionSource_normalizeTokenTransaction(txMeta, currentNetworkId, currentChainId) {
|
|
59
|
+
const base = __classPrivateFieldGet(this, _EtherscanRemoteTransactionSource_instances, "m", _EtherscanRemoteTransactionSource_normalizeTransactionBase).call(this, txMeta, currentNetworkId, currentChainId);
|
|
60
|
+
return Object.assign(Object.assign({}, base), { isTransfer: true, transferInformation: {
|
|
61
|
+
contractAddress: txMeta.contractAddress,
|
|
62
|
+
decimals: Number(txMeta.tokenDecimal),
|
|
63
|
+
symbol: txMeta.tokenSymbol,
|
|
64
|
+
} });
|
|
65
|
+
}, _EtherscanRemoteTransactionSource_normalizeTransactionBase = function _EtherscanRemoteTransactionSource_normalizeTransactionBase(txMeta, currentNetworkId, currentChainId) {
|
|
66
|
+
const time = parseInt(txMeta.timeStamp, 10) * 1000;
|
|
67
|
+
return {
|
|
68
|
+
blockNumber: txMeta.blockNumber,
|
|
69
|
+
chainId: currentChainId,
|
|
70
|
+
id: (0, uuid_1.v1)({ msecs: time }),
|
|
71
|
+
networkID: currentNetworkId,
|
|
72
|
+
status: types_1.TransactionStatus.confirmed,
|
|
73
|
+
time,
|
|
74
|
+
transaction: {
|
|
75
|
+
from: txMeta.from,
|
|
76
|
+
gas: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.gas)),
|
|
77
|
+
gasPrice: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.gasPrice)),
|
|
78
|
+
gasUsed: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.gasUsed)),
|
|
79
|
+
nonce: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.nonce)),
|
|
80
|
+
to: txMeta.to,
|
|
81
|
+
value: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.value)),
|
|
82
|
+
},
|
|
83
|
+
transactionHash: txMeta.hash,
|
|
84
|
+
verifiedOnBlockchain: false,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=EtherscanRemoteTransactionSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EtherscanRemoteTransactionSource.js","sourceRoot":"","sources":["../src/EtherscanRemoteTransactionSource.ts"],"names":[],"mappings":"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","sourcesContent":["import { BNToHex } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\nimport { BN } from 'ethereumjs-util';\nimport { v1 as random } from 'uuid';\n\nimport type {\n EtherscanTokenTransactionMeta,\n EtherscanTransactionMeta,\n EtherscanTransactionMetaBase,\n} from './etherscan';\nimport {\n fetchEtherscanTokenTransactions,\n fetchEtherscanTransactions,\n} from './etherscan';\nimport type {\n RemoteTransactionSource,\n RemoteTransactionSourceRequest,\n TransactionMeta,\n} from './types';\nimport { TransactionStatus } from './types';\n\n/**\n * A RemoteTransactionSource that fetches transaction data from Etherscan.\n */\nexport class EtherscanRemoteTransactionSource\n implements RemoteTransactionSource\n{\n /**\n * Retrieve transaction data from Etherscan.\n *\n * @param request - The configuration required to fetch Etherscan transaction data.\n * @returns An array of transaction metadata.\n */\n async fetchTransactions(\n request: RemoteTransactionSourceRequest,\n ): Promise<TransactionMeta[]> {\n const [etherscanTransactions, etherscanTokenTransactions] =\n await Promise.all([\n fetchEtherscanTransactions(request),\n fetchEtherscanTokenTransactions(request),\n ]);\n\n const transactions = etherscanTransactions.result.map((tx) =>\n this.#normalizeTransaction(\n tx,\n request.currentNetworkId,\n request.currentChainId,\n ),\n );\n\n const tokenTransactions = etherscanTokenTransactions.result.map((tx) =>\n this.#normalizeTokenTransaction(\n tx,\n request.currentNetworkId,\n request.currentChainId,\n ),\n );\n\n return [...transactions, ...tokenTransactions];\n }\n\n #normalizeTransaction(\n txMeta: EtherscanTransactionMeta,\n currentNetworkId: string,\n currentChainId: Hex,\n ): TransactionMeta {\n const base = this.#normalizeTransactionBase(\n txMeta,\n currentNetworkId,\n currentChainId,\n );\n\n return {\n ...base,\n transaction: {\n ...base.transaction,\n data: txMeta.input,\n },\n ...(txMeta.isError === '0'\n ? { status: TransactionStatus.confirmed }\n : {\n error: new Error('Transaction failed'),\n status: TransactionStatus.failed,\n }),\n };\n }\n\n #normalizeTokenTransaction(\n txMeta: EtherscanTokenTransactionMeta,\n currentNetworkId: string,\n currentChainId: Hex,\n ): TransactionMeta {\n const base = this.#normalizeTransactionBase(\n txMeta,\n currentNetworkId,\n currentChainId,\n );\n\n return {\n ...base,\n isTransfer: true,\n transferInformation: {\n contractAddress: txMeta.contractAddress,\n decimals: Number(txMeta.tokenDecimal),\n symbol: txMeta.tokenSymbol,\n },\n };\n }\n\n #normalizeTransactionBase(\n txMeta: EtherscanTransactionMetaBase,\n currentNetworkId: string,\n currentChainId: Hex,\n ): TransactionMeta {\n const time = parseInt(txMeta.timeStamp, 10) * 1000;\n\n return {\n blockNumber: txMeta.blockNumber,\n chainId: currentChainId,\n id: random({ msecs: time }),\n networkID: currentNetworkId,\n status: TransactionStatus.confirmed,\n time,\n transaction: {\n from: txMeta.from,\n gas: BNToHex(new BN(txMeta.gas)),\n gasPrice: BNToHex(new BN(txMeta.gasPrice)),\n gasUsed: BNToHex(new BN(txMeta.gasUsed)),\n nonce: BNToHex(new BN(txMeta.nonce)),\n to: txMeta.to,\n value: BNToHex(new BN(txMeta.value)),\n },\n transactionHash: txMeta.hash,\n verifiedOnBlockchain: false,\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type EthQuery from '@metamask/eth-query';
|
|
2
|
+
import type { NetworkState } from '@metamask/network-controller';
|
|
3
|
+
import type { RemoteTransactionSource, TransactionMeta } from './types';
|
|
4
|
+
export declare class IncomingTransactionHelper {
|
|
5
|
+
#private;
|
|
6
|
+
constructor({ getNetworkState, getEthQuery, transactionLimit, remoteTransactionSource, }: {
|
|
7
|
+
getNetworkState: () => NetworkState;
|
|
8
|
+
getEthQuery: () => EthQuery;
|
|
9
|
+
transactionLimit: number;
|
|
10
|
+
remoteTransactionSource: RemoteTransactionSource;
|
|
11
|
+
});
|
|
12
|
+
reconcile({ address, localTransactions, fromBlock, apiKey, }: {
|
|
13
|
+
address: string;
|
|
14
|
+
localTransactions: TransactionMeta[];
|
|
15
|
+
fromBlock?: string;
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
updateRequired: boolean;
|
|
19
|
+
transactions: TransactionMeta[];
|
|
20
|
+
latestBlockNumber?: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=IncomingTransactionHelper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IncomingTransactionHelper.d.ts","sourceRoot":"","sources":["../src/IncomingTransactionHelper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAGjE,OAAO,KAAK,EACV,uBAAuB,EAEvB,eAAe,EAEhB,MAAM,SAAS,CAAC;AAQjB,qBAAa,yBAAyB;;gBASxB,EACV,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,uBAAuB,GACxB,EAAE;QACD,eAAe,EAAE,MAAM,YAAY,CAAC;QACpC,WAAW,EAAE,MAAM,QAAQ,CAAC;QAC5B,gBAAgB,EAAE,MAAM,CAAC;QACzB,uBAAuB,EAAE,uBAAuB,CAAC;KAClD;IAOK,SAAS,CAAC,EACd,OAAO,EACP,iBAAiB,EACjB,SAAS,EACT,MAAM,GACP,EAAE;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB,EAAE,eAAe,EAAE,CAAC;QACrC,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC;QACV,cAAc,EAAE,OAAO,CAAC;QACxB,YAAY,EAAE,eAAe,EAAE,CAAC;QAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CAmMH"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
12
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
13
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
14
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
15
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
16
|
+
};
|
|
17
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
18
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
19
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
20
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
21
|
+
};
|
|
22
|
+
var _IncomingTransactionHelper_instances, _IncomingTransactionHelper_getNetworkState, _IncomingTransactionHelper_getEthQuery, _IncomingTransactionHelper_transactionLimit, _IncomingTransactionHelper_remoteTransactionSource, _IncomingTransactionHelper_updateSmartContractProperty, _IncomingTransactionHelper_getLatestBlockNumber, _IncomingTransactionHelper_isToSmartContract, _IncomingTransactionHelper_sortTransactionsByTime, _IncomingTransactionHelper_reconcileTransactions, _IncomingTransactionHelper_getNewTransactions, _IncomingTransactionHelper_getUpdatedTransactions, _IncomingTransactionHelper_isTransactionOutdated, _IncomingTransactionHelper_isStatusOutdated, _IncomingTransactionHelper_isGasDataOutdated;
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.IncomingTransactionHelper = void 0;
|
|
25
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
26
|
+
const SUPPORTED_NETWORK_IDS = [
|
|
27
|
+
'1',
|
|
28
|
+
'5',
|
|
29
|
+
'11155111', // Sepolia
|
|
30
|
+
];
|
|
31
|
+
class IncomingTransactionHelper {
|
|
32
|
+
constructor({ getNetworkState, getEthQuery, transactionLimit, remoteTransactionSource, }) {
|
|
33
|
+
_IncomingTransactionHelper_instances.add(this);
|
|
34
|
+
_IncomingTransactionHelper_getNetworkState.set(this, void 0);
|
|
35
|
+
_IncomingTransactionHelper_getEthQuery.set(this, void 0);
|
|
36
|
+
_IncomingTransactionHelper_transactionLimit.set(this, void 0);
|
|
37
|
+
_IncomingTransactionHelper_remoteTransactionSource.set(this, void 0);
|
|
38
|
+
__classPrivateFieldSet(this, _IncomingTransactionHelper_getNetworkState, getNetworkState, "f");
|
|
39
|
+
__classPrivateFieldSet(this, _IncomingTransactionHelper_getEthQuery, getEthQuery, "f");
|
|
40
|
+
__classPrivateFieldSet(this, _IncomingTransactionHelper_transactionLimit, transactionLimit, "f");
|
|
41
|
+
__classPrivateFieldSet(this, _IncomingTransactionHelper_remoteTransactionSource, remoteTransactionSource, "f");
|
|
42
|
+
}
|
|
43
|
+
reconcile({ address, localTransactions, fromBlock, apiKey, }) {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
const { providerConfig, networkId: currentNetworkId } = __classPrivateFieldGet(this, _IncomingTransactionHelper_getNetworkState, "f").call(this);
|
|
46
|
+
const { chainId: currentChainId, type: networkType } = providerConfig;
|
|
47
|
+
if (currentNetworkId === null ||
|
|
48
|
+
!SUPPORTED_NETWORK_IDS.includes(currentNetworkId)) {
|
|
49
|
+
return { updateRequired: false, transactions: [] };
|
|
50
|
+
}
|
|
51
|
+
const remoteTransactions = yield __classPrivateFieldGet(this, _IncomingTransactionHelper_remoteTransactionSource, "f").fetchTransactions({
|
|
52
|
+
address,
|
|
53
|
+
networkType,
|
|
54
|
+
limit: __classPrivateFieldGet(this, _IncomingTransactionHelper_transactionLimit, "f"),
|
|
55
|
+
currentChainId,
|
|
56
|
+
currentNetworkId,
|
|
57
|
+
fromBlock,
|
|
58
|
+
apiKey,
|
|
59
|
+
});
|
|
60
|
+
const [updateRequired, transactions] = __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_reconcileTransactions).call(this, localTransactions, remoteTransactions);
|
|
61
|
+
__classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_sortTransactionsByTime).call(this, transactions);
|
|
62
|
+
const latestBlockNumber = __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_getLatestBlockNumber).call(this, transactions, address, currentChainId, currentNetworkId);
|
|
63
|
+
yield __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_updateSmartContractProperty).call(this, transactions);
|
|
64
|
+
return { updateRequired, transactions, latestBlockNumber };
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.IncomingTransactionHelper = IncomingTransactionHelper;
|
|
69
|
+
_IncomingTransactionHelper_getNetworkState = new WeakMap(), _IncomingTransactionHelper_getEthQuery = new WeakMap(), _IncomingTransactionHelper_transactionLimit = new WeakMap(), _IncomingTransactionHelper_remoteTransactionSource = new WeakMap(), _IncomingTransactionHelper_instances = new WeakSet(), _IncomingTransactionHelper_updateSmartContractProperty = function _IncomingTransactionHelper_updateSmartContractProperty(transactions) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
yield Promise.all(transactions.map((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
var _a;
|
|
73
|
+
(_a = tx.toSmartContract) !== null && _a !== void 0 ? _a : (tx.toSmartContract = yield __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_isToSmartContract).call(this, tx.transaction));
|
|
74
|
+
})));
|
|
75
|
+
});
|
|
76
|
+
}, _IncomingTransactionHelper_getLatestBlockNumber = function _IncomingTransactionHelper_getLatestBlockNumber(transactions, address, currentChainId, currentNetworkId) {
|
|
77
|
+
var _a;
|
|
78
|
+
let latestBlockNumber;
|
|
79
|
+
for (const tx of transactions) {
|
|
80
|
+
const onCurrentChain = tx.chainId === currentChainId ||
|
|
81
|
+
(!tx.chainId && tx.networkID === currentNetworkId);
|
|
82
|
+
const toCurrentAccount = ((_a = tx.transaction.to) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === address.toLowerCase();
|
|
83
|
+
const currentBlockNumberValue = tx.blockNumber
|
|
84
|
+
? parseInt(tx.blockNumber, 10)
|
|
85
|
+
: -1;
|
|
86
|
+
const latestBlockNumberValue = latestBlockNumber
|
|
87
|
+
? parseInt(latestBlockNumber, 10)
|
|
88
|
+
: -1;
|
|
89
|
+
if (onCurrentChain &&
|
|
90
|
+
toCurrentAccount &&
|
|
91
|
+
latestBlockNumberValue < currentBlockNumberValue) {
|
|
92
|
+
latestBlockNumber = tx.blockNumber;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return latestBlockNumber;
|
|
96
|
+
}, _IncomingTransactionHelper_isToSmartContract = function _IncomingTransactionHelper_isToSmartContract(transaction) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
// Contract Deploy
|
|
99
|
+
if (!transaction.to) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
// Send
|
|
103
|
+
if (transaction.data === '0x') {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const ethQuery = __classPrivateFieldGet(this, _IncomingTransactionHelper_getEthQuery, "f").call(this);
|
|
107
|
+
const code = yield (0, controller_utils_1.query)(ethQuery, 'getCode', [transaction.to]);
|
|
108
|
+
return (0, controller_utils_1.isSmartContractCode)(code);
|
|
109
|
+
});
|
|
110
|
+
}, _IncomingTransactionHelper_sortTransactionsByTime = function _IncomingTransactionHelper_sortTransactionsByTime(transactions) {
|
|
111
|
+
transactions.sort((a, b) => (a.time < b.time ? -1 : 1));
|
|
112
|
+
}, _IncomingTransactionHelper_reconcileTransactions = function _IncomingTransactionHelper_reconcileTransactions(localTxs, remoteTxs) {
|
|
113
|
+
const updatedTxs = __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_getUpdatedTransactions).call(this, remoteTxs, localTxs);
|
|
114
|
+
const newTxs = __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_getNewTransactions).call(this, remoteTxs, localTxs);
|
|
115
|
+
const updatedLocalTxs = localTxs.map((tx) => {
|
|
116
|
+
const txIdx = updatedTxs.findIndex(({ transactionHash }) => transactionHash === tx.transactionHash);
|
|
117
|
+
return txIdx === -1 ? tx : updatedTxs[txIdx];
|
|
118
|
+
});
|
|
119
|
+
const updateRequired = newTxs.length > 0 || updatedTxs.length > 0;
|
|
120
|
+
const transactions = [...newTxs, ...updatedLocalTxs];
|
|
121
|
+
return [updateRequired, transactions];
|
|
122
|
+
}, _IncomingTransactionHelper_getNewTransactions = function _IncomingTransactionHelper_getNewTransactions(remoteTxs, localTxs) {
|
|
123
|
+
return remoteTxs.filter((tx) => {
|
|
124
|
+
const alreadyInTransactions = localTxs.find(({ transactionHash }) => transactionHash === tx.transactionHash);
|
|
125
|
+
return !alreadyInTransactions;
|
|
126
|
+
});
|
|
127
|
+
}, _IncomingTransactionHelper_getUpdatedTransactions = function _IncomingTransactionHelper_getUpdatedTransactions(remoteTxs, localTxs) {
|
|
128
|
+
return remoteTxs.filter((remoteTx) => {
|
|
129
|
+
const isTxOutdated = localTxs.find((localTx) => {
|
|
130
|
+
return (remoteTx.transactionHash === localTx.transactionHash &&
|
|
131
|
+
__classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_isTransactionOutdated).call(this, remoteTx, localTx));
|
|
132
|
+
});
|
|
133
|
+
return isTxOutdated;
|
|
134
|
+
});
|
|
135
|
+
}, _IncomingTransactionHelper_isTransactionOutdated = function _IncomingTransactionHelper_isTransactionOutdated(remoteTx, localTx) {
|
|
136
|
+
const statusOutdated = __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_isStatusOutdated).call(this, remoteTx.transactionHash, localTx.transactionHash, remoteTx.status, localTx.status);
|
|
137
|
+
const gasDataOutdated = __classPrivateFieldGet(this, _IncomingTransactionHelper_instances, "m", _IncomingTransactionHelper_isGasDataOutdated).call(this, remoteTx.transaction.gasUsed, localTx.transaction.gasUsed);
|
|
138
|
+
return statusOutdated || gasDataOutdated;
|
|
139
|
+
}, _IncomingTransactionHelper_isStatusOutdated = function _IncomingTransactionHelper_isStatusOutdated(remoteTxHash, localTxHash, remoteTxStatus, localTxStatus) {
|
|
140
|
+
return remoteTxHash === localTxHash && remoteTxStatus !== localTxStatus;
|
|
141
|
+
}, _IncomingTransactionHelper_isGasDataOutdated = function _IncomingTransactionHelper_isGasDataOutdated(remoteGasUsed, localGasUsed) {
|
|
142
|
+
return remoteGasUsed !== localGasUsed;
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=IncomingTransactionHelper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IncomingTransactionHelper.js","sourceRoot":"","sources":["../src/IncomingTransactionHelper.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,iEAAwE;AAYxE,MAAM,qBAAqB,GAAG;IAC5B,GAAG;IACH,GAAG;IACH,UAAU,EAAE,UAAU;CACvB,CAAC;AAEF,MAAa,yBAAyB;IASpC,YAAY,EACV,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,uBAAuB,GAMxB;;QAlBD,6DAAqC;QAErC,yDAA6B;QAE7B,8DAA0B;QAE1B,qEAAkD;QAahD,uBAAA,IAAI,8CAAoB,eAAe,MAAA,CAAC;QACxC,uBAAA,IAAI,0CAAgB,WAAW,MAAA,CAAC;QAChC,uBAAA,IAAI,+CAAqB,gBAAgB,MAAA,CAAC;QAC1C,uBAAA,IAAI,sDAA4B,uBAAuB,MAAA,CAAC;IAC1D,CAAC;IAEK,SAAS,CAAC,EACd,OAAO,EACP,iBAAiB,EACjB,SAAS,EACT,MAAM,GAMP;;YAKC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,gBAAgB,EAAE,GACnD,uBAAA,IAAI,kDAAiB,MAArB,IAAI,CAAmB,CAAC;YAC1B,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC;YAEtE,IACE,gBAAgB,KAAK,IAAI;gBACzB,CAAC,qBAAqB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EACjD;gBACA,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;aACpD;YAED,MAAM,kBAAkB,GACtB,MAAM,uBAAA,IAAI,0DAAyB,CAAC,iBAAiB,CAAC;gBACpD,OAAO;gBACP,WAAW;gBACX,KAAK,EAAE,uBAAA,IAAI,mDAAkB;gBAC7B,cAAc;gBACd,gBAAgB;gBAChB,SAAS;gBACT,MAAM;aACP,CAAC,CAAC;YAEL,MAAM,CAAC,cAAc,EAAE,YAAY,CAAC,GAAG,uBAAA,IAAI,8FAAuB,MAA3B,IAAI,EACzC,iBAAiB,EACjB,kBAAkB,CACnB,CAAC;YAEF,uBAAA,IAAI,+FAAwB,MAA5B,IAAI,EAAyB,YAAY,CAAC,CAAC;YAE3C,MAAM,iBAAiB,GAAG,uBAAA,IAAI,6FAAsB,MAA1B,IAAI,EAC5B,YAAY,EACZ,OAAO,EACP,cAAc,EACd,gBAAgB,CACjB,CAAC;YAEF,MAAM,uBAAA,IAAI,oGAA6B,MAAjC,IAAI,EAA8B,YAAY,CAAC,CAAC;YAEtD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC;QAC7D,CAAC;KAAA;CA2JF;AA3OD,8DA2OC;oaAzJoC,YAA+B;;QAChE,MAAM,OAAO,CAAC,GAAG,CACf,YAAY,CAAC,GAAG,CAAC,CAAO,EAAE,EAAE,EAAE;;YAC5B,MAAA,EAAE,CAAC,eAAe,oCAAlB,EAAE,CAAC,eAAe,GAAK,MAAM,uBAAA,IAAI,0FAAmB,MAAvB,IAAI,EAAoB,EAAE,CAAC,WAAW,CAAC,EAAC;QACvE,CAAC,CAAA,CAAC,CACH,CAAC;IACJ,CAAC;8GAGC,YAA+B,EAC/B,OAAe,EACf,cAAmB,EACnB,gBAAwB;;IAExB,IAAI,iBAAqC,CAAC;IAE1C,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE;QAC7B,MAAM,cAAc,GAClB,EAAE,CAAC,OAAO,KAAK,cAAc;YAC7B,CAAC,CAAC,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,SAAS,KAAK,gBAAgB,CAAC,CAAC;QAErD,MAAM,gBAAgB,GACpB,CAAA,MAAA,EAAE,CAAC,WAAW,CAAC,EAAE,0CAAE,WAAW,EAAE,MAAK,OAAO,CAAC,WAAW,EAAE,CAAC;QAE7D,MAAM,uBAAuB,GAAG,EAAE,CAAC,WAAW;YAC5C,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YAC9B,CAAC,CAAC,CAAC,CAAC,CAAC;QAEP,MAAM,sBAAsB,GAAG,iBAAiB;YAC9C,CAAC,CAAC,QAAQ,CAAC,iBAAiB,EAAE,EAAE,CAAC;YACjC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEP,IACE,cAAc;YACd,gBAAgB;YAChB,sBAAsB,GAAG,uBAAuB,EAChD;YACA,iBAAiB,GAAG,EAAE,CAAC,WAAW,CAAC;SACpC;KACF;IAED,OAAO,iBAAiB,CAAC;AAC3B,CAAC,uGAEwB,WAAwB;;QAC/C,kBAAkB;QAClB,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE;YACnB,OAAO,KAAK,CAAC;SACd;QAED,OAAO;QACP,IAAI,WAAW,CAAC,IAAI,KAAK,IAAI,EAAE;YAC7B,OAAO,KAAK,CAAC;SACd;QAED,MAAM,QAAQ,GAAG,uBAAA,IAAI,8CAAa,MAAjB,IAAI,CAAe,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,IAAA,wBAAK,EAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QAEhE,OAAO,IAAA,sCAAmB,EAAC,IAAI,CAAC,CAAC;IACnC,CAAC;kHAEuB,YAA+B;IACrD,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC,+GAGC,QAA2B,EAC3B,SAA4B;IAE5B,MAAM,UAAU,GAAsB,uBAAA,IAAI,+FAAwB,MAA5B,IAAI,EACxC,SAAS,EACT,QAAQ,CACT,CAAC;IAEF,MAAM,MAAM,GAAsB,uBAAA,IAAI,2FAAoB,MAAxB,IAAI,EACpC,SAAS,EACT,QAAQ,CACT,CAAC;IAEF,MAAM,eAAe,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAmB,EAAE,EAAE;QAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAChC,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,eAAe,KAAK,EAAE,CAAC,eAAe,CAChE,CAAC;QACF,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,eAAe,CAAC,CAAC;IAErD,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;AACxC,CAAC,yGAGC,SAA4B,EAC5B,QAA2B;IAE3B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE;QAC7B,MAAM,qBAAqB,GAAG,QAAQ,CAAC,IAAI,CACzC,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,eAAe,KAAK,EAAE,CAAC,eAAe,CAChE,CAAC;QACF,OAAO,CAAC,qBAAqB,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,iHAGC,SAA4B,EAC5B,QAA2B;IAE3B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE;QACnC,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7C,OAAO,CACL,QAAQ,CAAC,eAAe,KAAK,OAAO,CAAC,eAAe;gBACpD,uBAAA,IAAI,8FAAuB,MAA3B,IAAI,EAAwB,QAAQ,EAAE,OAAO,CAAC,CAC/C,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC,+GAGC,QAAyB,EACzB,OAAwB;IAExB,MAAM,cAAc,GAAG,uBAAA,IAAI,yFAAkB,MAAtB,IAAI,EACzB,QAAQ,CAAC,eAAe,EACxB,OAAO,CAAC,eAAe,EACvB,QAAQ,CAAC,MAAM,EACf,OAAO,CAAC,MAAM,CACf,CAAC;IAEF,MAAM,eAAe,GAAG,uBAAA,IAAI,0FAAmB,MAAvB,IAAI,EAC1B,QAAQ,CAAC,WAAW,CAAC,OAAO,EAC5B,OAAO,CAAC,WAAW,CAAC,OAAO,CAC5B,CAAC;IAEF,OAAO,cAAc,IAAI,eAAe,CAAC;AAC3C,CAAC,qGAGC,YAAgC,EAChC,WAA+B,EAC/B,cAAiC,EACjC,aAAgC;IAEhC,OAAO,YAAY,KAAK,WAAW,IAAI,cAAc,KAAK,aAAa,CAAC;AAC1E,CAAC,uGAGC,aAAiC,EACjC,YAAgC;IAEhC,OAAO,aAAa,KAAK,YAAY,CAAC;AACxC,CAAC","sourcesContent":["import { isSmartContractCode, query } from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport type { NetworkState } from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\n\nimport type {\n RemoteTransactionSource,\n Transaction,\n TransactionMeta,\n TransactionStatus,\n} from './types';\n\nconst SUPPORTED_NETWORK_IDS = [\n '1', // Mainnet\n '5', // Goerli\n '11155111', // Sepolia\n];\n\nexport class IncomingTransactionHelper {\n #getNetworkState: () => NetworkState;\n\n #getEthQuery: () => EthQuery;\n\n #transactionLimit: number;\n\n #remoteTransactionSource: RemoteTransactionSource;\n\n constructor({\n getNetworkState,\n getEthQuery,\n transactionLimit,\n remoteTransactionSource,\n }: {\n getNetworkState: () => NetworkState;\n getEthQuery: () => EthQuery;\n transactionLimit: number;\n remoteTransactionSource: RemoteTransactionSource;\n }) {\n this.#getNetworkState = getNetworkState;\n this.#getEthQuery = getEthQuery;\n this.#transactionLimit = transactionLimit;\n this.#remoteTransactionSource = remoteTransactionSource;\n }\n\n async reconcile({\n address,\n localTransactions,\n fromBlock,\n apiKey,\n }: {\n address: string;\n localTransactions: TransactionMeta[];\n fromBlock?: string;\n apiKey?: string;\n }): Promise<{\n updateRequired: boolean;\n transactions: TransactionMeta[];\n latestBlockNumber?: string;\n }> {\n const { providerConfig, networkId: currentNetworkId } =\n this.#getNetworkState();\n const { chainId: currentChainId, type: networkType } = providerConfig;\n\n if (\n currentNetworkId === null ||\n !SUPPORTED_NETWORK_IDS.includes(currentNetworkId)\n ) {\n return { updateRequired: false, transactions: [] };\n }\n\n const remoteTransactions =\n await this.#remoteTransactionSource.fetchTransactions({\n address,\n networkType,\n limit: this.#transactionLimit,\n currentChainId,\n currentNetworkId,\n fromBlock,\n apiKey,\n });\n\n const [updateRequired, transactions] = this.#reconcileTransactions(\n localTransactions,\n remoteTransactions,\n );\n\n this.#sortTransactionsByTime(transactions);\n\n const latestBlockNumber = this.#getLatestBlockNumber(\n transactions,\n address,\n currentChainId,\n currentNetworkId,\n );\n\n await this.#updateSmartContractProperty(transactions);\n\n return { updateRequired, transactions, latestBlockNumber };\n }\n\n async #updateSmartContractProperty(transactions: TransactionMeta[]) {\n await Promise.all(\n transactions.map(async (tx) => {\n tx.toSmartContract ??= await this.#isToSmartContract(tx.transaction);\n }),\n );\n }\n\n #getLatestBlockNumber(\n transactions: TransactionMeta[],\n address: string,\n currentChainId: Hex,\n currentNetworkId: string,\n ): string | undefined {\n let latestBlockNumber: string | undefined;\n\n for (const tx of transactions) {\n const onCurrentChain =\n tx.chainId === currentChainId ||\n (!tx.chainId && tx.networkID === currentNetworkId);\n\n const toCurrentAccount =\n tx.transaction.to?.toLowerCase() === address.toLowerCase();\n\n const currentBlockNumberValue = tx.blockNumber\n ? parseInt(tx.blockNumber, 10)\n : -1;\n\n const latestBlockNumberValue = latestBlockNumber\n ? parseInt(latestBlockNumber, 10)\n : -1;\n\n if (\n onCurrentChain &&\n toCurrentAccount &&\n latestBlockNumberValue < currentBlockNumberValue\n ) {\n latestBlockNumber = tx.blockNumber;\n }\n }\n\n return latestBlockNumber;\n }\n\n async #isToSmartContract(transaction: Transaction): Promise<boolean> {\n // Contract Deploy\n if (!transaction.to) {\n return false;\n }\n\n // Send\n if (transaction.data === '0x') {\n return false;\n }\n\n const ethQuery = this.#getEthQuery();\n const code = await query(ethQuery, 'getCode', [transaction.to]);\n\n return isSmartContractCode(code);\n }\n\n #sortTransactionsByTime(transactions: TransactionMeta[]) {\n transactions.sort((a, b) => (a.time < b.time ? -1 : 1));\n }\n\n #reconcileTransactions(\n localTxs: TransactionMeta[],\n remoteTxs: TransactionMeta[],\n ): [boolean, TransactionMeta[]] {\n const updatedTxs: TransactionMeta[] = this.#getUpdatedTransactions(\n remoteTxs,\n localTxs,\n );\n\n const newTxs: TransactionMeta[] = this.#getNewTransactions(\n remoteTxs,\n localTxs,\n );\n\n const updatedLocalTxs = localTxs.map((tx: TransactionMeta) => {\n const txIdx = updatedTxs.findIndex(\n ({ transactionHash }) => transactionHash === tx.transactionHash,\n );\n return txIdx === -1 ? tx : updatedTxs[txIdx];\n });\n\n const updateRequired = newTxs.length > 0 || updatedTxs.length > 0;\n const transactions = [...newTxs, ...updatedLocalTxs];\n\n return [updateRequired, transactions];\n }\n\n #getNewTransactions(\n remoteTxs: TransactionMeta[],\n localTxs: TransactionMeta[],\n ): TransactionMeta[] {\n return remoteTxs.filter((tx) => {\n const alreadyInTransactions = localTxs.find(\n ({ transactionHash }) => transactionHash === tx.transactionHash,\n );\n return !alreadyInTransactions;\n });\n }\n\n #getUpdatedTransactions(\n remoteTxs: TransactionMeta[],\n localTxs: TransactionMeta[],\n ): TransactionMeta[] {\n return remoteTxs.filter((remoteTx) => {\n const isTxOutdated = localTxs.find((localTx) => {\n return (\n remoteTx.transactionHash === localTx.transactionHash &&\n this.#isTransactionOutdated(remoteTx, localTx)\n );\n });\n return isTxOutdated;\n });\n }\n\n #isTransactionOutdated(\n remoteTx: TransactionMeta,\n localTx: TransactionMeta,\n ): boolean {\n const statusOutdated = this.#isStatusOutdated(\n remoteTx.transactionHash,\n localTx.transactionHash,\n remoteTx.status,\n localTx.status,\n );\n\n const gasDataOutdated = this.#isGasDataOutdated(\n remoteTx.transaction.gasUsed,\n localTx.transaction.gasUsed,\n );\n\n return statusOutdated || gasDataOutdated;\n }\n\n #isStatusOutdated(\n remoteTxHash: string | undefined,\n localTxHash: string | undefined,\n remoteTxStatus: TransactionStatus,\n localTxStatus: TransactionStatus,\n ): boolean {\n return remoteTxHash === localTxHash && remoteTxStatus !== localTxStatus;\n }\n\n #isGasDataOutdated(\n remoteGasUsed: string | undefined,\n localGasUsed: string | undefined,\n ): boolean {\n return remoteGasUsed !== localGasUsed;\n }\n}\n"]}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import type {
|
|
6
|
-
import { BaseController
|
|
2
|
+
import { Hardfork, Common } from '@ethereumjs/common';
|
|
3
|
+
import type { TypedTransaction } from '@ethereumjs/tx';
|
|
4
|
+
import type { AddApprovalRequest } from '@metamask/approval-controller';
|
|
5
|
+
import type { BaseConfig, BaseState, RestrictedControllerMessenger } from '@metamask/base-controller';
|
|
6
|
+
import { BaseController } from '@metamask/base-controller';
|
|
7
7
|
import type { BlockTracker, NetworkState, Provider } from '@metamask/network-controller';
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
import type { Transaction, TransactionMeta, WalletDevice } from './types';
|
|
10
|
+
export declare const HARDFORK = Hardfork.London;
|
|
10
11
|
/**
|
|
11
12
|
* @type Result
|
|
12
13
|
* @property result - Promise resolving to a new transaction hash
|
|
@@ -25,35 +26,6 @@ export interface FetchAllOptions {
|
|
|
25
26
|
fromBlock?: string;
|
|
26
27
|
etherscanApiKey?: string;
|
|
27
28
|
}
|
|
28
|
-
/**
|
|
29
|
-
* @type Transaction
|
|
30
|
-
*
|
|
31
|
-
* Transaction representation
|
|
32
|
-
* @property chainId - Network ID as per EIP-155
|
|
33
|
-
* @property data - Data to pass with this transaction
|
|
34
|
-
* @property from - Address to send this transaction from
|
|
35
|
-
* @property gas - Gas to send with this transaction
|
|
36
|
-
* @property gasPrice - Price of gas with this transaction
|
|
37
|
-
* @property gasUsed - Gas used in the transaction
|
|
38
|
-
* @property nonce - Unique number to prevent replay attacks
|
|
39
|
-
* @property to - Address to send this transaction to
|
|
40
|
-
* @property value - Value associated with this transaction
|
|
41
|
-
*/
|
|
42
|
-
export interface Transaction {
|
|
43
|
-
chainId?: Hex;
|
|
44
|
-
data?: string;
|
|
45
|
-
from: string;
|
|
46
|
-
gas?: string;
|
|
47
|
-
gasPrice?: string;
|
|
48
|
-
gasUsed?: string;
|
|
49
|
-
nonce?: string;
|
|
50
|
-
to?: string;
|
|
51
|
-
value?: string;
|
|
52
|
-
maxFeePerGas?: string;
|
|
53
|
-
maxPriorityFeePerGas?: string;
|
|
54
|
-
estimatedBaseFee?: string;
|
|
55
|
-
estimateGasError?: string;
|
|
56
|
-
}
|
|
57
29
|
export interface GasPriceValue {
|
|
58
30
|
gasPrice: string;
|
|
59
31
|
}
|
|
@@ -61,115 +33,6 @@ export interface FeeMarketEIP1559Values {
|
|
|
61
33
|
maxFeePerGas: string;
|
|
62
34
|
maxPriorityFeePerGas: string;
|
|
63
35
|
}
|
|
64
|
-
/**
|
|
65
|
-
* The status of the transaction. Each status represents the state of the transaction internally
|
|
66
|
-
* in the wallet. Some of these correspond with the state of the transaction on the network, but
|
|
67
|
-
* some are wallet-specific.
|
|
68
|
-
*/
|
|
69
|
-
export declare enum TransactionStatus {
|
|
70
|
-
approved = "approved",
|
|
71
|
-
cancelled = "cancelled",
|
|
72
|
-
confirmed = "confirmed",
|
|
73
|
-
failed = "failed",
|
|
74
|
-
rejected = "rejected",
|
|
75
|
-
signed = "signed",
|
|
76
|
-
submitted = "submitted",
|
|
77
|
-
unapproved = "unapproved"
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Options for wallet device.
|
|
81
|
-
*/
|
|
82
|
-
export declare enum WalletDevice {
|
|
83
|
-
MM_MOBILE = "metamask_mobile",
|
|
84
|
-
MM_EXTENSION = "metamask_extension",
|
|
85
|
-
OTHER = "other_device"
|
|
86
|
-
}
|
|
87
|
-
declare type TransactionMetaBase = {
|
|
88
|
-
isTransfer?: boolean;
|
|
89
|
-
transferInformation?: {
|
|
90
|
-
symbol: string;
|
|
91
|
-
contractAddress: string;
|
|
92
|
-
decimals: number;
|
|
93
|
-
};
|
|
94
|
-
id: string;
|
|
95
|
-
networkID?: string;
|
|
96
|
-
chainId?: Hex;
|
|
97
|
-
origin?: string;
|
|
98
|
-
rawTransaction?: string;
|
|
99
|
-
time: number;
|
|
100
|
-
toSmartContract?: boolean;
|
|
101
|
-
transaction: Transaction;
|
|
102
|
-
transactionHash?: string;
|
|
103
|
-
blockNumber?: string;
|
|
104
|
-
deviceConfirmedOn?: WalletDevice;
|
|
105
|
-
verifiedOnBlockchain?: boolean;
|
|
106
|
-
};
|
|
107
|
-
/**
|
|
108
|
-
* @type TransactionMeta
|
|
109
|
-
*
|
|
110
|
-
* TransactionMeta representation
|
|
111
|
-
* @property error - Synthesized error information for failed transactions
|
|
112
|
-
* @property id - Generated UUID associated with this transaction
|
|
113
|
-
* @property networkID - Network code as per EIP-155 for this transaction
|
|
114
|
-
* @property origin - Origin this transaction was sent from
|
|
115
|
-
* @property deviceConfirmedOn - string to indicate what device the transaction was confirmed
|
|
116
|
-
* @property rawTransaction - Hex representation of the underlying transaction
|
|
117
|
-
* @property status - String status of this transaction
|
|
118
|
-
* @property time - Timestamp associated with this transaction
|
|
119
|
-
* @property toSmartContract - Whether transaction recipient is a smart contract
|
|
120
|
-
* @property transaction - Underlying Transaction object
|
|
121
|
-
* @property transactionHash - Hash of a successful transaction
|
|
122
|
-
* @property blockNumber - Number of the block where the transaction has been included
|
|
123
|
-
*/
|
|
124
|
-
export declare type TransactionMeta = ({
|
|
125
|
-
status: Exclude<TransactionStatus, TransactionStatus.failed>;
|
|
126
|
-
} & TransactionMetaBase) | ({
|
|
127
|
-
status: TransactionStatus.failed;
|
|
128
|
-
error: Error;
|
|
129
|
-
} & TransactionMetaBase);
|
|
130
|
-
/**
|
|
131
|
-
* @type EtherscanTransactionMeta
|
|
132
|
-
*
|
|
133
|
-
* EtherscanTransactionMeta representation
|
|
134
|
-
* @property blockNumber - Number of the block where the transaction has been included
|
|
135
|
-
* @property timeStamp - Timestamp associated with this transaction
|
|
136
|
-
* @property hash - Hash of a successful transaction
|
|
137
|
-
* @property nonce - Nonce of the transaction
|
|
138
|
-
* @property blockHash - Hash of the block where the transaction has been included
|
|
139
|
-
* @property transactionIndex - Etherscan internal index for this transaction
|
|
140
|
-
* @property from - Address to send this transaction from
|
|
141
|
-
* @property to - Address to send this transaction to
|
|
142
|
-
* @property gas - Gas to send with this transaction
|
|
143
|
-
* @property gasPrice - Price of gas with this transaction
|
|
144
|
-
* @property isError - Synthesized error information for failed transactions
|
|
145
|
-
* @property txreceipt_status - Receipt status for this transaction
|
|
146
|
-
* @property input - input of the transaction
|
|
147
|
-
* @property contractAddress - Address of the contract
|
|
148
|
-
* @property cumulativeGasUsed - Amount of gas used
|
|
149
|
-
* @property confirmations - Number of confirmations
|
|
150
|
-
*/
|
|
151
|
-
export interface EtherscanTransactionMeta {
|
|
152
|
-
blockNumber: string;
|
|
153
|
-
timeStamp: string;
|
|
154
|
-
hash: string;
|
|
155
|
-
nonce: string;
|
|
156
|
-
blockHash: string;
|
|
157
|
-
transactionIndex: string;
|
|
158
|
-
from: string;
|
|
159
|
-
to: string;
|
|
160
|
-
value: string;
|
|
161
|
-
gas: string;
|
|
162
|
-
gasPrice: string;
|
|
163
|
-
cumulativeGasUsed: string;
|
|
164
|
-
gasUsed: string;
|
|
165
|
-
isError: string;
|
|
166
|
-
txreceipt_status: string;
|
|
167
|
-
input: string;
|
|
168
|
-
contractAddress: string;
|
|
169
|
-
confirmations: string;
|
|
170
|
-
tokenDecimal: string;
|
|
171
|
-
tokenSymbol: string;
|
|
172
|
-
}
|
|
173
36
|
/**
|
|
174
37
|
* @type TransactionConfig
|
|
175
38
|
*
|
|
@@ -232,26 +95,16 @@ export declare type TransactionControllerMessenger = RestrictedControllerMesseng
|
|
|
232
95
|
*/
|
|
233
96
|
export declare class TransactionController extends BaseController<TransactionConfig, TransactionState> {
|
|
234
97
|
private ethQuery;
|
|
235
|
-
private nonceTracker;
|
|
98
|
+
private readonly nonceTracker;
|
|
236
99
|
private registry;
|
|
237
|
-
private provider;
|
|
100
|
+
private readonly provider;
|
|
238
101
|
private handle?;
|
|
239
|
-
private mutex;
|
|
240
|
-
private getNetworkState;
|
|
241
|
-
private messagingSystem;
|
|
102
|
+
private readonly mutex;
|
|
103
|
+
private readonly getNetworkState;
|
|
104
|
+
private readonly messagingSystem;
|
|
105
|
+
private readonly incomingTransactionHelper;
|
|
242
106
|
private failTransaction;
|
|
243
107
|
private registryLookup;
|
|
244
|
-
/**
|
|
245
|
-
* Normalizes the transaction information from etherscan
|
|
246
|
-
* to be compatible with the TransactionMeta interface.
|
|
247
|
-
*
|
|
248
|
-
* @param txMeta - The transaction.
|
|
249
|
-
* @param currentNetworkID - The current network ID.
|
|
250
|
-
* @param currentChainId - The current chain ID.
|
|
251
|
-
* @returns The normalized transaction.
|
|
252
|
-
*/
|
|
253
|
-
private normalizeTx;
|
|
254
|
-
private normalizeTokenTx;
|
|
255
108
|
/**
|
|
256
109
|
* EventEmitter instance used to listen to specific transactional events
|
|
257
110
|
*/
|
|
@@ -439,59 +292,6 @@ export declare class TransactionController extends BaseController<TransactionCon
|
|
|
439
292
|
* @returns Whether the transaction has failed.
|
|
440
293
|
*/
|
|
441
294
|
private checkTxReceiptStatusIsFailed;
|
|
442
|
-
/**
|
|
443
|
-
* Method to verify the state of transactions using Etherscan as a source of truth.
|
|
444
|
-
*
|
|
445
|
-
* @param remoteTxs - Transactions to reconcile that are from a remote source.
|
|
446
|
-
* @param localTxs - Transactions to reconcile that are local.
|
|
447
|
-
* @returns A tuple containing a boolean indicating whether or not an update was required, and the updated transaction.
|
|
448
|
-
*/
|
|
449
|
-
private etherscanTransactionStateReconciler;
|
|
450
|
-
/**
|
|
451
|
-
* Get all transactions that are in the remote transactions array
|
|
452
|
-
* but not in the local transactions array.
|
|
453
|
-
*
|
|
454
|
-
* @param remoteTxs - Array of transactions from remote source.
|
|
455
|
-
* @param localTxs - Array of transactions stored locally.
|
|
456
|
-
* @returns The new transactions.
|
|
457
|
-
*/
|
|
458
|
-
private getNewTransactions;
|
|
459
|
-
/**
|
|
460
|
-
* Get all the transactions that are locally outdated with respect
|
|
461
|
-
* to a remote source (etherscan or blockchain). The returned array
|
|
462
|
-
* contains the transactions with the updated data.
|
|
463
|
-
*
|
|
464
|
-
* @param remoteTxs - Array of transactions from remote source.
|
|
465
|
-
* @param localTxs - Array of transactions stored locally.
|
|
466
|
-
* @returns The updated transactions.
|
|
467
|
-
*/
|
|
468
|
-
private getUpdatedTransactions;
|
|
469
|
-
/**
|
|
470
|
-
* Verifies if a local transaction is outdated with respect to the remote transaction.
|
|
471
|
-
*
|
|
472
|
-
* @param remoteTx - The remote transaction from Etherscan.
|
|
473
|
-
* @param localTx - The local transaction.
|
|
474
|
-
* @returns Whether the transaction is outdated.
|
|
475
|
-
*/
|
|
476
|
-
private isTransactionOutdated;
|
|
477
|
-
/**
|
|
478
|
-
* Verifies if the status of a local transaction is outdated with respect to the remote transaction.
|
|
479
|
-
*
|
|
480
|
-
* @param remoteTxHash - Remote transaction hash.
|
|
481
|
-
* @param localTxHash - Local transaction hash.
|
|
482
|
-
* @param remoteTxStatus - Remote transaction status.
|
|
483
|
-
* @param localTxStatus - Local transaction status.
|
|
484
|
-
* @returns Whether the status is outdated.
|
|
485
|
-
*/
|
|
486
|
-
private isStatusOutdated;
|
|
487
|
-
/**
|
|
488
|
-
* Verifies if the gas data of a local transaction is outdated with respect to the remote transaction.
|
|
489
|
-
*
|
|
490
|
-
* @param remoteGasUsed - Remote gas used in the transaction.
|
|
491
|
-
* @param localGasUsed - Local gas used in the transaction.
|
|
492
|
-
* @returns Whether the gas data is outdated.
|
|
493
|
-
*/
|
|
494
|
-
private isGasDataOutdated;
|
|
495
295
|
private requestApproval;
|
|
496
296
|
private getTransaction;
|
|
497
297
|
private getApprovalId;
|