@metamask/transaction-controller 23.0.0 → 23.1.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/dist/TransactionController.d.ts +2 -1
  3. package/dist/TransactionController.d.ts.map +1 -1
  4. package/dist/TransactionController.js +79 -52
  5. package/dist/TransactionController.js.map +1 -1
  6. package/dist/gas-flows/DefaultGasFeeFlow.d.ts +10 -0
  7. package/dist/gas-flows/DefaultGasFeeFlow.d.ts.map +1 -0
  8. package/dist/gas-flows/DefaultGasFeeFlow.js +78 -0
  9. package/dist/gas-flows/DefaultGasFeeFlow.js.map +1 -0
  10. package/dist/gas-flows/LineaGasFeeFlow.d.ts +12 -0
  11. package/dist/gas-flows/LineaGasFeeFlow.d.ts.map +1 -0
  12. package/dist/gas-flows/LineaGasFeeFlow.js +111 -0
  13. package/dist/gas-flows/LineaGasFeeFlow.js.map +1 -0
  14. package/dist/helpers/EtherscanRemoteTransactionSource.js +9 -6
  15. package/dist/helpers/EtherscanRemoteTransactionSource.js.map +1 -1
  16. package/dist/helpers/GasFeePoller.d.ts +32 -0
  17. package/dist/helpers/GasFeePoller.d.ts.map +1 -0
  18. package/dist/helpers/GasFeePoller.js +144 -0
  19. package/dist/helpers/GasFeePoller.js.map +1 -0
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +3 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/types.d.ts +57 -0
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/types.js +8 -1
  27. package/dist/types.js.map +1 -1
  28. package/dist/utils/gas-fees.d.ts +11 -17
  29. package/dist/utils/gas-fees.d.ts.map +1 -1
  30. package/dist/utils/gas-fees.js +20 -35
  31. package/dist/utils/gas-fees.js.map +1 -1
  32. package/dist/utils/gas-flow.d.ts +32 -0
  33. package/dist/utils/gas-flow.d.ts.map +1 -0
  34. package/dist/utils/gas-flow.js +53 -0
  35. package/dist/utils/gas-flow.js.map +1 -0
  36. package/dist/utils/gas.d.ts +1 -1
  37. package/dist/utils/gas.d.ts.map +1 -1
  38. package/dist/utils/gas.js +4 -5
  39. package/dist/utils/gas.js.map +1 -1
  40. package/dist/utils/utils.d.ts.map +1 -1
  41. package/dist/utils/utils.js +15 -16
  42. package/dist/utils/utils.js.map +1 -1
  43. package/package.json +5 -3
@@ -0,0 +1,10 @@
1
+ import type { GasFeeFlow, GasFeeFlowRequest, GasFeeFlowResponse, TransactionMeta } from '../types';
2
+ /**
3
+ * The standard implementation of a gas fee flow that obtains gas fee estimates using only the GasFeeController.
4
+ */
5
+ export declare class DefaultGasFeeFlow implements GasFeeFlow {
6
+ #private;
7
+ matchesTransaction(_transactionMeta: TransactionMeta): boolean;
8
+ getGasFees(request: GasFeeFlowRequest): Promise<GasFeeFlowResponse>;
9
+ }
10
+ //# sourceMappingURL=DefaultGasFeeFlow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultGasFeeFlow.d.ts","sourceRoot":"","sources":["../../src/gas-flows/DefaultGasFeeFlow.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAGV,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EAChB,MAAM,UAAU,CAAC;AAkBlB;;GAEG;AACH,qBAAa,iBAAkB,YAAW,UAAU;;IAClD,kBAAkB,CAAC,gBAAgB,EAAE,eAAe,GAAG,OAAO;IAIxD,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAyE1E"}
@@ -0,0 +1,78 @@
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 _DefaultGasFeeFlow_instances, _DefaultGasFeeFlow_getEstimateLevel, _DefaultGasFeeFlow_getFeeMarketLevel, _DefaultGasFeeFlow_getLegacyLevel;
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.DefaultGasFeeFlow = void 0;
19
+ const gas_fee_controller_1 = require("@metamask/gas-fee-controller");
20
+ const utils_1 = require("@metamask/utils");
21
+ const logger_1 = require("../logger");
22
+ const types_1 = require("../types");
23
+ const gas_fees_1 = require("../utils/gas-fees");
24
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'default-gas-fee-flow');
25
+ /**
26
+ * The standard implementation of a gas fee flow that obtains gas fee estimates using only the GasFeeController.
27
+ */
28
+ class DefaultGasFeeFlow {
29
+ constructor() {
30
+ _DefaultGasFeeFlow_instances.add(this);
31
+ }
32
+ matchesTransaction(_transactionMeta) {
33
+ return true;
34
+ }
35
+ getGasFees(request) {
36
+ return __awaiter(this, void 0, void 0, function* () {
37
+ const { getGasFeeControllerEstimates, transactionMeta } = request;
38
+ const { networkClientId } = transactionMeta;
39
+ const { gasEstimateType, gasFeeEstimates } = yield getGasFeeControllerEstimates({ networkClientId });
40
+ if (gasEstimateType === gas_fee_controller_1.GAS_ESTIMATE_TYPES.FEE_MARKET) {
41
+ log('Using fee market estimates', gasFeeEstimates);
42
+ }
43
+ else if (gasEstimateType === gas_fee_controller_1.GAS_ESTIMATE_TYPES.LEGACY) {
44
+ log('Using legacy estimates', gasFeeEstimates);
45
+ }
46
+ else {
47
+ throw new Error(`'No gas fee estimates available`);
48
+ }
49
+ const estimates = Object.values(types_1.GasFeeEstimateLevel).reduce((result, level) => (Object.assign(Object.assign({}, result), { [level]: __classPrivateFieldGet(this, _DefaultGasFeeFlow_instances, "m", _DefaultGasFeeFlow_getEstimateLevel).call(this, {
50
+ gasEstimateType,
51
+ gasFeeEstimates,
52
+ level,
53
+ }) })), {});
54
+ return { estimates };
55
+ });
56
+ }
57
+ }
58
+ exports.DefaultGasFeeFlow = DefaultGasFeeFlow;
59
+ _DefaultGasFeeFlow_instances = new WeakSet(), _DefaultGasFeeFlow_getEstimateLevel = function _DefaultGasFeeFlow_getEstimateLevel({ gasEstimateType, gasFeeEstimates, level, }) {
60
+ if (gasEstimateType === gas_fee_controller_1.GAS_ESTIMATE_TYPES.FEE_MARKET) {
61
+ return __classPrivateFieldGet(this, _DefaultGasFeeFlow_instances, "m", _DefaultGasFeeFlow_getFeeMarketLevel).call(this, gasFeeEstimates, level);
62
+ }
63
+ return __classPrivateFieldGet(this, _DefaultGasFeeFlow_instances, "m", _DefaultGasFeeFlow_getLegacyLevel).call(this, gasFeeEstimates, level);
64
+ }, _DefaultGasFeeFlow_getFeeMarketLevel = function _DefaultGasFeeFlow_getFeeMarketLevel(gasFeeEstimates, level) {
65
+ const maxFeePerGas = (0, gas_fees_1.gweiDecimalToWeiHex)(gasFeeEstimates[level].suggestedMaxFeePerGas);
66
+ const maxPriorityFeePerGas = (0, gas_fees_1.gweiDecimalToWeiHex)(gasFeeEstimates[level].suggestedMaxPriorityFeePerGas);
67
+ return {
68
+ maxFeePerGas,
69
+ maxPriorityFeePerGas,
70
+ };
71
+ }, _DefaultGasFeeFlow_getLegacyLevel = function _DefaultGasFeeFlow_getLegacyLevel(gasFeeEstimates, level) {
72
+ const gasPrice = (0, gas_fees_1.gweiDecimalToWeiHex)(gasFeeEstimates[level]);
73
+ return {
74
+ maxFeePerGas: gasPrice,
75
+ maxPriorityFeePerGas: gasPrice,
76
+ };
77
+ };
78
+ //# sourceMappingURL=DefaultGasFeeFlow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultGasFeeFlow.js","sourceRoot":"","sources":["../../src/gas-flows/DefaultGasFeeFlow.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAIA,qEAAkE;AAClE,2CAAqD;AAErD,sCAA0C;AAS1C,oCAA+C;AAC/C,gDAAwD;AAExD,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,sBAAsB,CAAC,CAAC;AActE;;GAEG;AACH,MAAa,iBAAiB;IAA9B;;IA8EA,CAAC;IA7EC,kBAAkB,CAAC,gBAAiC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAEK,UAAU,CAAC,OAA0B;;YACzC,MAAM,EAAE,4BAA4B,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;YAClE,MAAM,EAAE,eAAe,EAAE,GAAG,eAAe,CAAC;YAE5C,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,GACxC,MAAM,4BAA4B,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;YAE1D,IAAI,eAAe,KAAK,uCAAkB,CAAC,UAAU,EAAE;gBACrD,GAAG,CAAC,4BAA4B,EAAE,eAAe,CAAC,CAAC;aACpD;iBAAM,IAAI,eAAe,KAAK,uCAAkB,CAAC,MAAM,EAAE;gBACxD,GAAG,CAAC,wBAAwB,EAAE,eAAe,CAAC,CAAC;aAChD;iBAAM;gBACL,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;aACpD;YAED,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,2BAAmB,CAAC,CAAC,MAAM,CACzD,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,iCACd,MAAM,KACT,CAAC,KAAK,CAAC,EAAE,uBAAA,IAAI,yEAAkB,MAAtB,IAAI,EAAmB;oBAC9B,eAAe;oBACf,eAAe;oBACf,KAAK;iBAC8D,CAAC,IACtE,EACF,EAAqB,CACtB,CAAC;YAEF,OAAO,EAAE,SAAS,EAAE,CAAC;QACvB,CAAC;KAAA;CA6CF;AA9ED,8CA8EC;iIA3CmB,EAChB,eAAe,EACf,eAAe,EACf,KAAK,GAG0B;IAC/B,IAAI,eAAe,KAAK,uCAAkB,CAAC,UAAU,EAAE;QACrD,OAAO,uBAAA,IAAI,0EAAmB,MAAvB,IAAI,EAAoB,eAAe,EAAE,KAAK,CAAC,CAAC;KACxD;IAED,OAAO,uBAAA,IAAI,uEAAgB,MAApB,IAAI,EAAiB,eAAe,EAAE,KAAK,CAAC,CAAC;AACtD,CAAC,uFAGC,eAA0C,EAC1C,KAA0B;IAE1B,MAAM,YAAY,GAAG,IAAA,8BAAmB,EACtC,eAAe,CAAC,KAAK,CAAC,CAAC,qBAAqB,CAC7C,CAAC;IAEF,MAAM,oBAAoB,GAAG,IAAA,8BAAmB,EAC9C,eAAe,CAAC,KAAK,CAAC,CAAC,6BAA6B,CACrD,CAAC;IAEF,OAAO;QACL,YAAY;QACZ,oBAAoB;KACrB,CAAC;AACJ,CAAC,iFAGC,eAAuC,EACvC,KAA0B;IAE1B,MAAM,QAAQ,GAAG,IAAA,8BAAmB,EAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IAE7D,OAAO;QACL,YAAY,EAAE,QAAQ;QACtB,oBAAoB,EAAE,QAAQ;KAC/B,CAAC;AACJ,CAAC","sourcesContent":["import type {\n LegacyGasPriceEstimate,\n GasFeeEstimates as FeeMarketGasPriceEstimate,\n} from '@metamask/gas-fee-controller';\nimport { GAS_ESTIMATE_TYPES } from '@metamask/gas-fee-controller';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { projectLogger } from '../logger';\nimport type {\n GasFeeEstimates,\n GasFeeEstimatesForLevel,\n GasFeeFlow,\n GasFeeFlowRequest,\n GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { GasFeeEstimateLevel } from '../types';\nimport { gweiDecimalToWeiHex } from '../utils/gas-fees';\n\nconst log = createModuleLogger(projectLogger, 'default-gas-fee-flow');\n\ntype FeeMarketGetEstimateLevelRequest = {\n gasEstimateType: 'fee-market';\n gasFeeEstimates: FeeMarketGasPriceEstimate;\n level: GasFeeEstimateLevel;\n};\n\ntype LegacyGetEstimateLevelRequest = {\n gasEstimateType: 'legacy';\n gasFeeEstimates: LegacyGasPriceEstimate;\n level: GasFeeEstimateLevel;\n};\n\n/**\n * The standard implementation of a gas fee flow that obtains gas fee estimates using only the GasFeeController.\n */\nexport class DefaultGasFeeFlow implements GasFeeFlow {\n matchesTransaction(_transactionMeta: TransactionMeta): boolean {\n return true;\n }\n\n async getGasFees(request: GasFeeFlowRequest): Promise<GasFeeFlowResponse> {\n const { getGasFeeControllerEstimates, transactionMeta } = request;\n const { networkClientId } = transactionMeta;\n\n const { gasEstimateType, gasFeeEstimates } =\n await getGasFeeControllerEstimates({ networkClientId });\n\n if (gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET) {\n log('Using fee market estimates', gasFeeEstimates);\n } else if (gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY) {\n log('Using legacy estimates', gasFeeEstimates);\n } else {\n throw new Error(`'No gas fee estimates available`);\n }\n\n const estimates = Object.values(GasFeeEstimateLevel).reduce(\n (result, level) => ({\n ...result,\n [level]: this.#getEstimateLevel({\n gasEstimateType,\n gasFeeEstimates,\n level,\n } as FeeMarketGetEstimateLevelRequest | LegacyGetEstimateLevelRequest),\n }),\n {} as GasFeeEstimates,\n );\n\n return { estimates };\n }\n\n #getEstimateLevel({\n gasEstimateType,\n gasFeeEstimates,\n level,\n }:\n | FeeMarketGetEstimateLevelRequest\n | LegacyGetEstimateLevelRequest): GasFeeEstimatesForLevel {\n if (gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET) {\n return this.#getFeeMarketLevel(gasFeeEstimates, level);\n }\n\n return this.#getLegacyLevel(gasFeeEstimates, level);\n }\n\n #getFeeMarketLevel(\n gasFeeEstimates: FeeMarketGasPriceEstimate,\n level: GasFeeEstimateLevel,\n ): GasFeeEstimatesForLevel {\n const maxFeePerGas = gweiDecimalToWeiHex(\n gasFeeEstimates[level].suggestedMaxFeePerGas,\n );\n\n const maxPriorityFeePerGas = gweiDecimalToWeiHex(\n gasFeeEstimates[level].suggestedMaxPriorityFeePerGas,\n );\n\n return {\n maxFeePerGas,\n maxPriorityFeePerGas,\n };\n }\n\n #getLegacyLevel(\n gasFeeEstimates: LegacyGasPriceEstimate,\n level: GasFeeEstimateLevel,\n ): GasFeeEstimatesForLevel {\n const gasPrice = gweiDecimalToWeiHex(gasFeeEstimates[level]);\n\n return {\n maxFeePerGas: gasPrice,\n maxPriorityFeePerGas: gasPrice,\n };\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { GasFeeFlow, GasFeeFlowRequest, GasFeeFlowResponse, TransactionMeta } from '../types';
2
+ /**
3
+ * Implementation of a gas fee flow specific to Linea networks that obtains gas fee estimates using:
4
+ * - The `linea_estimateGas` RPC method to obtain the base fee and lowest priority fee.
5
+ * - Static multipliers to increase the base and priority fees.
6
+ */
7
+ export declare class LineaGasFeeFlow implements GasFeeFlow {
8
+ #private;
9
+ matchesTransaction(transactionMeta: TransactionMeta): boolean;
10
+ getGasFees(request: GasFeeFlowRequest): Promise<GasFeeFlowResponse>;
11
+ }
12
+ //# sourceMappingURL=LineaGasFeeFlow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LineaGasFeeFlow.d.ts","sourceRoot":"","sources":["../../src/gas-flows/LineaGasFeeFlow.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EAChB,MAAM,UAAU,CAAC;AAgClB;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,UAAU;;IAChD,kBAAkB,CAAC,eAAe,EAAE,eAAe,GAAG,OAAO;IAIvD,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAqG1E"}
@@ -0,0 +1,111 @@
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 _LineaGasFeeFlow_instances, _LineaGasFeeFlow_getLineaGasFees, _LineaGasFeeFlow_getLineaResponse, _LineaGasFeeFlow_getValuesFromMultipliers, _LineaGasFeeFlow_getMaxFees, _LineaGasFeeFlow_feesToString;
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.LineaGasFeeFlow = void 0;
19
+ const controller_utils_1 = require("@metamask/controller-utils");
20
+ const utils_1 = require("@metamask/utils");
21
+ const logger_1 = require("../logger");
22
+ const types_1 = require("../types");
23
+ const DefaultGasFeeFlow_1 = require("./DefaultGasFeeFlow");
24
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'linea-gas-fee-flow');
25
+ const LINEA_CHAIN_IDS = [
26
+ controller_utils_1.ChainId['linea-mainnet'],
27
+ controller_utils_1.ChainId['linea-goerli'],
28
+ ];
29
+ const BASE_FEE_MULTIPLIERS = {
30
+ low: 1,
31
+ medium: 1.35,
32
+ high: 1.7,
33
+ };
34
+ const PRIORITY_FEE_MULTIPLIERS = {
35
+ low: 1,
36
+ medium: 1.05,
37
+ high: 1.1,
38
+ };
39
+ /**
40
+ * Implementation of a gas fee flow specific to Linea networks that obtains gas fee estimates using:
41
+ * - The `linea_estimateGas` RPC method to obtain the base fee and lowest priority fee.
42
+ * - Static multipliers to increase the base and priority fees.
43
+ */
44
+ class LineaGasFeeFlow {
45
+ constructor() {
46
+ _LineaGasFeeFlow_instances.add(this);
47
+ }
48
+ matchesTransaction(transactionMeta) {
49
+ return LINEA_CHAIN_IDS.includes(transactionMeta.chainId);
50
+ }
51
+ getGasFees(request) {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ try {
54
+ return yield __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_getLineaGasFees).call(this, request);
55
+ }
56
+ catch (error) {
57
+ log('Using default flow as fallback due to error', error);
58
+ return new DefaultGasFeeFlow_1.DefaultGasFeeFlow().getGasFees(request);
59
+ }
60
+ });
61
+ }
62
+ }
63
+ exports.LineaGasFeeFlow = LineaGasFeeFlow;
64
+ _LineaGasFeeFlow_instances = new WeakSet(), _LineaGasFeeFlow_getLineaGasFees = function _LineaGasFeeFlow_getLineaGasFees(request) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ const { ethQuery, transactionMeta } = request;
67
+ const lineaResponse = yield __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_getLineaResponse).call(this, transactionMeta, ethQuery);
68
+ log('Received Linea response', lineaResponse);
69
+ const baseFees = __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_getValuesFromMultipliers).call(this, lineaResponse.baseFeePerGas, BASE_FEE_MULTIPLIERS);
70
+ log('Generated base fees', __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_feesToString).call(this, baseFees));
71
+ const priorityFees = __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_getValuesFromMultipliers).call(this, lineaResponse.priorityFeePerGas, PRIORITY_FEE_MULTIPLIERS);
72
+ log('Generated priority fees', __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_feesToString).call(this, priorityFees));
73
+ const maxFees = __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_getMaxFees).call(this, baseFees, priorityFees);
74
+ log('Generated max fees', __classPrivateFieldGet(this, _LineaGasFeeFlow_instances, "m", _LineaGasFeeFlow_feesToString).call(this, maxFees));
75
+ const estimates = Object.values(types_1.GasFeeEstimateLevel).reduce((result, level) => (Object.assign(Object.assign({}, result), { [level]: {
76
+ maxFeePerGas: (0, controller_utils_1.toHex)(maxFees[level]),
77
+ maxPriorityFeePerGas: (0, controller_utils_1.toHex)(priorityFees[level]),
78
+ } })), {});
79
+ return { estimates };
80
+ });
81
+ }, _LineaGasFeeFlow_getLineaResponse = function _LineaGasFeeFlow_getLineaResponse(transactionMeta, ethQuery) {
82
+ return (0, controller_utils_1.query)(ethQuery, 'linea_estimateGas', [
83
+ {
84
+ from: transactionMeta.txParams.from,
85
+ to: transactionMeta.txParams.to,
86
+ value: transactionMeta.txParams.value,
87
+ input: transactionMeta.txParams.data,
88
+ // Required in request but no impact on response.
89
+ gasPrice: '0x100000000',
90
+ },
91
+ ]);
92
+ }, _LineaGasFeeFlow_getValuesFromMultipliers = function _LineaGasFeeFlow_getValuesFromMultipliers(value, multipliers) {
93
+ const base = (0, controller_utils_1.hexToBN)(value);
94
+ const low = base.muln(multipliers.low);
95
+ const medium = base.muln(multipliers.medium);
96
+ const high = base.muln(multipliers.high);
97
+ return {
98
+ low,
99
+ medium,
100
+ high,
101
+ };
102
+ }, _LineaGasFeeFlow_getMaxFees = function _LineaGasFeeFlow_getMaxFees(baseFees, priorityFees) {
103
+ return {
104
+ low: baseFees.low.add(priorityFees.low),
105
+ medium: baseFees.medium.add(priorityFees.medium),
106
+ high: baseFees.high.add(priorityFees.high),
107
+ };
108
+ }, _LineaGasFeeFlow_feesToString = function _LineaGasFeeFlow_feesToString(fees) {
109
+ return Object.values(types_1.GasFeeEstimateLevel).map((level) => fees[level].toString(10));
110
+ };
111
+ //# sourceMappingURL=LineaGasFeeFlow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LineaGasFeeFlow.js","sourceRoot":"","sources":["../../src/gas-flows/LineaGasFeeFlow.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChainId, hexToBN, query, toHex } from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport { createModuleLogger, type Hex } from '@metamask/utils';\nimport type BN from 'bn.js';\n\nimport { projectLogger } from '../logger';\nimport type {\n GasFeeEstimates,\n GasFeeFlow,\n GasFeeFlowRequest,\n GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { GasFeeEstimateLevel } from '../types';\nimport { DefaultGasFeeFlow } from './DefaultGasFeeFlow';\n\ntype LineaEstimateGasResponse = {\n baseFeePerGas: Hex;\n priorityFeePerGas: Hex;\n};\n\ntype FeesByLevel = {\n [key in GasFeeEstimateLevel]: BN;\n};\n\nconst log = createModuleLogger(projectLogger, 'linea-gas-fee-flow');\n\nconst LINEA_CHAIN_IDS: Hex[] = [\n ChainId['linea-mainnet'],\n ChainId['linea-goerli'],\n];\n\nconst BASE_FEE_MULTIPLIERS = {\n low: 1,\n medium: 1.35,\n high: 1.7,\n};\n\nconst PRIORITY_FEE_MULTIPLIERS = {\n low: 1,\n medium: 1.05,\n high: 1.1,\n};\n\n/**\n * Implementation of a gas fee flow specific to Linea networks that obtains gas fee estimates using:\n * - The `linea_estimateGas` RPC method to obtain the base fee and lowest priority fee.\n * - Static multipliers to increase the base and priority fees.\n */\nexport class LineaGasFeeFlow implements GasFeeFlow {\n matchesTransaction(transactionMeta: TransactionMeta): boolean {\n return LINEA_CHAIN_IDS.includes(transactionMeta.chainId);\n }\n\n async getGasFees(request: GasFeeFlowRequest): Promise<GasFeeFlowResponse> {\n try {\n return await this.#getLineaGasFees(request);\n } catch (error) {\n log('Using default flow as fallback due to error', error);\n return new DefaultGasFeeFlow().getGasFees(request);\n }\n }\n\n async #getLineaGasFees(\n request: GasFeeFlowRequest,\n ): Promise<GasFeeFlowResponse> {\n const { ethQuery, transactionMeta } = request;\n\n const lineaResponse = await this.#getLineaResponse(\n transactionMeta,\n ethQuery,\n );\n\n log('Received Linea response', lineaResponse);\n\n const baseFees = this.#getValuesFromMultipliers(\n lineaResponse.baseFeePerGas,\n BASE_FEE_MULTIPLIERS,\n );\n\n log('Generated base fees', this.#feesToString(baseFees));\n\n const priorityFees = this.#getValuesFromMultipliers(\n lineaResponse.priorityFeePerGas,\n PRIORITY_FEE_MULTIPLIERS,\n );\n\n log('Generated priority fees', this.#feesToString(priorityFees));\n\n const maxFees = this.#getMaxFees(baseFees, priorityFees);\n\n log('Generated max fees', this.#feesToString(maxFees));\n\n const estimates = Object.values(GasFeeEstimateLevel).reduce(\n (result, level) => ({\n ...result,\n [level]: {\n maxFeePerGas: toHex(maxFees[level]),\n maxPriorityFeePerGas: toHex(priorityFees[level]),\n },\n }),\n {} as GasFeeEstimates,\n );\n\n return { estimates };\n }\n\n #getLineaResponse(\n transactionMeta: TransactionMeta,\n ethQuery: EthQuery,\n ): Promise<LineaEstimateGasResponse> {\n return query(ethQuery, 'linea_estimateGas', [\n {\n from: transactionMeta.txParams.from,\n to: transactionMeta.txParams.to,\n value: transactionMeta.txParams.value,\n input: transactionMeta.txParams.data,\n // Required in request but no impact on response.\n gasPrice: '0x100000000',\n },\n ]);\n }\n\n #getValuesFromMultipliers(\n value: Hex,\n multipliers: { low: number; medium: number; high: number },\n ): FeesByLevel {\n const base = hexToBN(value);\n const low = base.muln(multipliers.low);\n const medium = base.muln(multipliers.medium);\n const high = base.muln(multipliers.high);\n\n return {\n low,\n medium,\n high,\n };\n }\n\n #getMaxFees(\n baseFees: Record<GasFeeEstimateLevel, BN>,\n priorityFees: Record<GasFeeEstimateLevel, BN>,\n ): FeesByLevel {\n return {\n low: baseFees.low.add(priorityFees.low),\n medium: baseFees.medium.add(priorityFees.medium),\n high: baseFees.high.add(priorityFees.high),\n };\n }\n\n #feesToString(fees: FeesByLevel) {\n return Object.values(GasFeeEstimateLevel).map((level) =>\n fees[level].toString(10),\n );\n }\n}\n"]}
@@ -19,12 +19,15 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
19
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
20
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
21
21
  };
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
22
25
  var _EtherscanRemoteTransactionSource_instances, _EtherscanRemoteTransactionSource_includeTokenTransfers, _EtherscanRemoteTransactionSource_isTokenRequestPending, _EtherscanRemoteTransactionSource_mutex, _EtherscanRemoteTransactionSource_releaseLockAfterInterval, _EtherscanRemoteTransactionSource_fetchNormalTransactions, _EtherscanRemoteTransactionSource_fetchTokenTransactions, _EtherscanRemoteTransactionSource_getResponseTransactions, _EtherscanRemoteTransactionSource_normalizeTransaction, _EtherscanRemoteTransactionSource_normalizeTokenTransaction, _EtherscanRemoteTransactionSource_normalizeTransactionBase;
23
26
  Object.defineProperty(exports, "__esModule", { value: true });
24
27
  exports.EtherscanRemoteTransactionSource = void 0;
25
28
  const controller_utils_1 = require("@metamask/controller-utils");
26
29
  const async_mutex_1 = require("async-mutex");
27
- const ethereumjs_util_1 = require("ethereumjs-util");
30
+ const bn_js_1 = __importDefault(require("bn.js"));
28
31
  const uuid_1 = require("uuid");
29
32
  const constants_1 = require("../constants");
30
33
  const logger_1 = require("../logger");
@@ -129,12 +132,12 @@ _EtherscanRemoteTransactionSource_includeTokenTransfers = new WeakMap(), _Ethers
129
132
  txParams: {
130
133
  chainId: currentChainId,
131
134
  from: txMeta.from,
132
- gas: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.gas)),
133
- gasPrice: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.gasPrice)),
134
- gasUsed: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.gasUsed)),
135
- nonce: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.nonce)),
135
+ gas: (0, controller_utils_1.BNToHex)(new bn_js_1.default(txMeta.gas)),
136
+ gasPrice: (0, controller_utils_1.BNToHex)(new bn_js_1.default(txMeta.gasPrice)),
137
+ gasUsed: (0, controller_utils_1.BNToHex)(new bn_js_1.default(txMeta.gasUsed)),
138
+ nonce: (0, controller_utils_1.BNToHex)(new bn_js_1.default(txMeta.nonce)),
136
139
  to: txMeta.to,
137
- value: (0, controller_utils_1.BNToHex)(new ethereumjs_util_1.BN(txMeta.value)),
140
+ value: (0, controller_utils_1.BNToHex)(new bn_js_1.default(txMeta.value)),
138
141
  },
139
142
  type: types_1.TransactionType.incoming,
140
143
  verifiedOnBlockchain: false,
@@ -1 +1 @@
1
- {"version":3,"file":"EtherscanRemoteTransactionSource.js","sourceRoot":"","sources":["../../src/helpers/EtherscanRemoteTransactionSource.ts"],"names":[],"mappings":"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","sourcesContent":["import { BNToHex } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { BN } from 'ethereumjs-util';\nimport { v1 as random } from 'uuid';\n\nimport { ETHERSCAN_SUPPORTED_NETWORKS } from '../constants';\nimport { incomingTransactionsLogger as log } from '../logger';\nimport type {\n RemoteTransactionSource,\n RemoteTransactionSourceRequest,\n TransactionMeta,\n} from '../types';\nimport { TransactionStatus, TransactionType } from '../types';\nimport {\n fetchEtherscanTokenTransactions,\n fetchEtherscanTransactions,\n} from '../utils/etherscan';\nimport type {\n EtherscanTokenTransactionMeta,\n EtherscanTransactionMeta,\n EtherscanTransactionMetaBase,\n EtherscanTransactionRequest,\n EtherscanTransactionResponse,\n} from '../utils/etherscan';\n\nconst ETHERSCAN_RATE_LIMIT_INTERVAL = 5000;\n/**\n * A RemoteTransactionSource that fetches transaction data from Etherscan.\n */\nexport class EtherscanRemoteTransactionSource\n implements RemoteTransactionSource\n{\n #includeTokenTransfers: boolean;\n\n #isTokenRequestPending: boolean;\n\n #mutex = new Mutex();\n\n constructor({\n includeTokenTransfers,\n }: { includeTokenTransfers?: boolean } = {}) {\n this.#includeTokenTransfers = includeTokenTransfers ?? true;\n this.#isTokenRequestPending = false;\n }\n\n isSupportedNetwork(chainId: Hex): boolean {\n return Object.keys(ETHERSCAN_SUPPORTED_NETWORKS).includes(chainId);\n }\n\n getLastBlockVariations(): string[] {\n return [this.#isTokenRequestPending ? 'token' : 'normal'];\n }\n\n async fetchTransactions(\n request: RemoteTransactionSourceRequest,\n ): Promise<TransactionMeta[]> {\n const releaseLock = await this.#mutex.acquire();\n const acquiredTime = Date.now();\n\n const etherscanRequest: EtherscanTransactionRequest = {\n ...request,\n chainId: request.currentChainId,\n };\n\n try {\n const transactions = this.#isTokenRequestPending\n ? await this.#fetchTokenTransactions(request, etherscanRequest)\n : await this.#fetchNormalTransactions(request, etherscanRequest);\n\n if (this.#includeTokenTransfers) {\n this.#isTokenRequestPending = !this.#isTokenRequestPending;\n }\n\n return transactions;\n } finally {\n this.#releaseLockAfterInterval(acquiredTime, releaseLock);\n }\n }\n\n #releaseLockAfterInterval(acquireTime: number, releaseLock: () => void) {\n const elapsedTime = Date.now() - acquireTime;\n const remainingTime = Math.max(\n 0,\n ETHERSCAN_RATE_LIMIT_INTERVAL - elapsedTime,\n );\n // Wait for the remaining time if it hasn't been 5 seconds yet\n if (remainingTime > 0) {\n setTimeout(releaseLock, remainingTime);\n } else {\n releaseLock();\n }\n }\n\n #fetchNormalTransactions = async (\n request: RemoteTransactionSourceRequest,\n etherscanRequest: EtherscanTransactionRequest,\n ) => {\n const { currentChainId } = request;\n\n const etherscanTransactions = await fetchEtherscanTransactions(\n etherscanRequest,\n );\n\n return this.#getResponseTransactions(etherscanTransactions).map((tx) =>\n this.#normalizeTransaction(tx, currentChainId),\n );\n };\n\n #fetchTokenTransactions = async (\n request: RemoteTransactionSourceRequest,\n etherscanRequest: EtherscanTransactionRequest,\n ) => {\n const { currentChainId } = request;\n\n const etherscanTransactions = await fetchEtherscanTokenTransactions(\n etherscanRequest,\n );\n\n return this.#getResponseTransactions(etherscanTransactions).map((tx) =>\n this.#normalizeTokenTransaction(tx, currentChainId),\n );\n };\n\n #getResponseTransactions<T extends EtherscanTransactionMetaBase>(\n response: EtherscanTransactionResponse<T>,\n ): T[] {\n let result = response.result as T[];\n\n if (response.status === '0') {\n result = [];\n\n if (response.result.length) {\n log('Ignored Etherscan request error', {\n message: response.result,\n type: this.#isTokenRequestPending ? 'token' : 'normal',\n });\n }\n }\n\n return result;\n }\n\n #normalizeTransaction(\n txMeta: EtherscanTransactionMeta,\n currentChainId: Hex,\n ): TransactionMeta {\n const base = this.#normalizeTransactionBase(txMeta, currentChainId);\n\n return {\n ...base,\n txParams: {\n ...base.txParams,\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 currentChainId: Hex,\n ): TransactionMeta {\n const base = this.#normalizeTransactionBase(txMeta, currentChainId);\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 currentChainId: Hex,\n ): TransactionMeta {\n const time = parseInt(txMeta.timeStamp, 10) * 1000;\n\n return {\n blockNumber: txMeta.blockNumber,\n chainId: currentChainId,\n hash: txMeta.hash,\n id: random({ msecs: time }),\n status: TransactionStatus.confirmed,\n time,\n txParams: {\n chainId: currentChainId,\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 type: TransactionType.incoming,\n verifiedOnBlockchain: false,\n };\n }\n}\n"]}
1
+ {"version":3,"file":"EtherscanRemoteTransactionSource.js","sourceRoot":"","sources":["../../src/helpers/EtherscanRemoteTransactionSource.ts"],"names":[],"mappings":"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","sourcesContent":["import { BNToHex } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport BN from 'bn.js';\nimport { v1 as random } from 'uuid';\n\nimport { ETHERSCAN_SUPPORTED_NETWORKS } from '../constants';\nimport { incomingTransactionsLogger as log } from '../logger';\nimport type {\n RemoteTransactionSource,\n RemoteTransactionSourceRequest,\n TransactionMeta,\n} from '../types';\nimport { TransactionStatus, TransactionType } from '../types';\nimport {\n fetchEtherscanTokenTransactions,\n fetchEtherscanTransactions,\n} from '../utils/etherscan';\nimport type {\n EtherscanTokenTransactionMeta,\n EtherscanTransactionMeta,\n EtherscanTransactionMetaBase,\n EtherscanTransactionRequest,\n EtherscanTransactionResponse,\n} from '../utils/etherscan';\n\nconst ETHERSCAN_RATE_LIMIT_INTERVAL = 5000;\n/**\n * A RemoteTransactionSource that fetches transaction data from Etherscan.\n */\nexport class EtherscanRemoteTransactionSource\n implements RemoteTransactionSource\n{\n #includeTokenTransfers: boolean;\n\n #isTokenRequestPending: boolean;\n\n #mutex = new Mutex();\n\n constructor({\n includeTokenTransfers,\n }: { includeTokenTransfers?: boolean } = {}) {\n this.#includeTokenTransfers = includeTokenTransfers ?? true;\n this.#isTokenRequestPending = false;\n }\n\n isSupportedNetwork(chainId: Hex): boolean {\n return Object.keys(ETHERSCAN_SUPPORTED_NETWORKS).includes(chainId);\n }\n\n getLastBlockVariations(): string[] {\n return [this.#isTokenRequestPending ? 'token' : 'normal'];\n }\n\n async fetchTransactions(\n request: RemoteTransactionSourceRequest,\n ): Promise<TransactionMeta[]> {\n const releaseLock = await this.#mutex.acquire();\n const acquiredTime = Date.now();\n\n const etherscanRequest: EtherscanTransactionRequest = {\n ...request,\n chainId: request.currentChainId,\n };\n\n try {\n const transactions = this.#isTokenRequestPending\n ? await this.#fetchTokenTransactions(request, etherscanRequest)\n : await this.#fetchNormalTransactions(request, etherscanRequest);\n\n if (this.#includeTokenTransfers) {\n this.#isTokenRequestPending = !this.#isTokenRequestPending;\n }\n\n return transactions;\n } finally {\n this.#releaseLockAfterInterval(acquiredTime, releaseLock);\n }\n }\n\n #releaseLockAfterInterval(acquireTime: number, releaseLock: () => void) {\n const elapsedTime = Date.now() - acquireTime;\n const remainingTime = Math.max(\n 0,\n ETHERSCAN_RATE_LIMIT_INTERVAL - elapsedTime,\n );\n // Wait for the remaining time if it hasn't been 5 seconds yet\n if (remainingTime > 0) {\n setTimeout(releaseLock, remainingTime);\n } else {\n releaseLock();\n }\n }\n\n #fetchNormalTransactions = async (\n request: RemoteTransactionSourceRequest,\n etherscanRequest: EtherscanTransactionRequest,\n ) => {\n const { currentChainId } = request;\n\n const etherscanTransactions = await fetchEtherscanTransactions(\n etherscanRequest,\n );\n\n return this.#getResponseTransactions(etherscanTransactions).map((tx) =>\n this.#normalizeTransaction(tx, currentChainId),\n );\n };\n\n #fetchTokenTransactions = async (\n request: RemoteTransactionSourceRequest,\n etherscanRequest: EtherscanTransactionRequest,\n ) => {\n const { currentChainId } = request;\n\n const etherscanTransactions = await fetchEtherscanTokenTransactions(\n etherscanRequest,\n );\n\n return this.#getResponseTransactions(etherscanTransactions).map((tx) =>\n this.#normalizeTokenTransaction(tx, currentChainId),\n );\n };\n\n #getResponseTransactions<T extends EtherscanTransactionMetaBase>(\n response: EtherscanTransactionResponse<T>,\n ): T[] {\n let result = response.result as T[];\n\n if (response.status === '0') {\n result = [];\n\n if (response.result.length) {\n log('Ignored Etherscan request error', {\n message: response.result,\n type: this.#isTokenRequestPending ? 'token' : 'normal',\n });\n }\n }\n\n return result;\n }\n\n #normalizeTransaction(\n txMeta: EtherscanTransactionMeta,\n currentChainId: Hex,\n ): TransactionMeta {\n const base = this.#normalizeTransactionBase(txMeta, currentChainId);\n\n return {\n ...base,\n txParams: {\n ...base.txParams,\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 currentChainId: Hex,\n ): TransactionMeta {\n const base = this.#normalizeTransactionBase(txMeta, currentChainId);\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 currentChainId: Hex,\n ): TransactionMeta {\n const time = parseInt(txMeta.timeStamp, 10) * 1000;\n\n return {\n blockNumber: txMeta.blockNumber,\n chainId: currentChainId,\n hash: txMeta.hash,\n id: random({ msecs: time }),\n status: TransactionStatus.confirmed,\n time,\n txParams: {\n chainId: currentChainId,\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 type: TransactionType.incoming,\n verifiedOnBlockchain: false,\n };\n }\n}\n"]}
@@ -0,0 +1,32 @@
1
+ /// <reference types="node" />
2
+ import type EthQuery from '@metamask/eth-query';
3
+ import type { GasFeeState } from '@metamask/gas-fee-controller';
4
+ import type { Hex } from '@metamask/utils';
5
+ import EventEmitter from 'events';
6
+ import type { NetworkClientId } from '../../../network-controller/src';
7
+ import type { GasFeeFlow } from '../types';
8
+ import { type TransactionMeta } from '../types';
9
+ /**
10
+ * Automatically polls and updates suggested gas fees on unapproved transactions.
11
+ */
12
+ export declare class GasFeePoller {
13
+ #private;
14
+ hub: EventEmitter;
15
+ /**
16
+ * Constructs a new instance of the GasFeePoller.
17
+ * @param options - The options for this instance.
18
+ * @param options.gasFeeFlows - The gas fee flows to use to obtain suitable gas fees.
19
+ * @param options.getEthQuery - Callback to obtain an EthQuery instance.
20
+ * @param options.getGasFeeControllerEstimates - Callback to obtain the default fee estimates.
21
+ * @param options.getTransactions - Callback to obtain the transaction data.
22
+ * @param options.onStateChange - Callback to register a listener for controller state changes.
23
+ */
24
+ constructor({ gasFeeFlows, getEthQuery, getGasFeeControllerEstimates, getTransactions, onStateChange, }: {
25
+ gasFeeFlows: GasFeeFlow[];
26
+ getEthQuery: (chainId: Hex, networkClientId?: NetworkClientId) => EthQuery;
27
+ getGasFeeControllerEstimates: () => Promise<GasFeeState>;
28
+ getTransactions: () => TransactionMeta[];
29
+ onStateChange: (listener: () => void) => void;
30
+ });
31
+ }
32
+ //# sourceMappingURL=GasFeePoller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GasFeePoller.d.ts","sourceRoot":"","sources":["../../src/helpers/GasFeePoller.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,OAAO,YAAY,MAAM,QAAQ,CAAC;AAElC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,KAAK,EAAmB,UAAU,EAAqB,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAOnE;;GAEG;AACH,qBAAa,YAAY;;IACvB,GAAG,EAAE,YAAY,CAAsB;IAcvC;;;;;;;;OAQG;gBACS,EACV,WAAW,EACX,WAAW,EACX,4BAA4B,EAC5B,eAAe,EACf,aAAa,GACd,EAAE;QACD,WAAW,EAAE,UAAU,EAAE,CAAC;QAC1B,WAAW,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,eAAe,CAAC,EAAE,eAAe,KAAK,QAAQ,CAAC;QAC3E,4BAA4B,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;QACzD,eAAe,EAAE,MAAM,eAAe,EAAE,CAAC;QACzC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;KAC/C;CAsHF"}
@@ -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 __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ var _GasFeePoller_instances, _GasFeePoller_gasFeeFlows, _GasFeePoller_getEthQuery, _GasFeePoller_getGasFeeControllerEstimates, _GasFeePoller_getTransactions, _GasFeePoller_timeout, _GasFeePoller_running, _GasFeePoller_start, _GasFeePoller_stop, _GasFeePoller_onTimeout, _GasFeePoller_updateUnapprovedTransactions, _GasFeePoller_updateTransactionSuggestedFees, _GasFeePoller_getUnapprovedTransactions;
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.GasFeePoller = void 0;
28
+ const utils_1 = require("@metamask/utils");
29
+ const events_1 = __importDefault(require("events"));
30
+ const logger_1 = require("../logger");
31
+ const types_1 = require("../types");
32
+ const gas_flow_1 = require("../utils/gas-flow");
33
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'gas-fee-poller');
34
+ const INTERVAL_MILLISECONDS = 10000;
35
+ /**
36
+ * Automatically polls and updates suggested gas fees on unapproved transactions.
37
+ */
38
+ class GasFeePoller {
39
+ /**
40
+ * Constructs a new instance of the GasFeePoller.
41
+ * @param options - The options for this instance.
42
+ * @param options.gasFeeFlows - The gas fee flows to use to obtain suitable gas fees.
43
+ * @param options.getEthQuery - Callback to obtain an EthQuery instance.
44
+ * @param options.getGasFeeControllerEstimates - Callback to obtain the default fee estimates.
45
+ * @param options.getTransactions - Callback to obtain the transaction data.
46
+ * @param options.onStateChange - Callback to register a listener for controller state changes.
47
+ */
48
+ constructor({ gasFeeFlows, getEthQuery, getGasFeeControllerEstimates, getTransactions, onStateChange, }) {
49
+ _GasFeePoller_instances.add(this);
50
+ this.hub = new events_1.default();
51
+ _GasFeePoller_gasFeeFlows.set(this, void 0);
52
+ _GasFeePoller_getEthQuery.set(this, void 0);
53
+ _GasFeePoller_getGasFeeControllerEstimates.set(this, void 0);
54
+ _GasFeePoller_getTransactions.set(this, void 0);
55
+ _GasFeePoller_timeout.set(this, void 0);
56
+ _GasFeePoller_running.set(this, false);
57
+ __classPrivateFieldSet(this, _GasFeePoller_gasFeeFlows, gasFeeFlows, "f");
58
+ __classPrivateFieldSet(this, _GasFeePoller_getEthQuery, getEthQuery, "f");
59
+ __classPrivateFieldSet(this, _GasFeePoller_getGasFeeControllerEstimates, getGasFeeControllerEstimates, "f");
60
+ __classPrivateFieldSet(this, _GasFeePoller_getTransactions, getTransactions, "f");
61
+ onStateChange(() => {
62
+ const unapprovedTransactions = __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_getUnapprovedTransactions).call(this);
63
+ if (unapprovedTransactions.length) {
64
+ __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_start).call(this);
65
+ }
66
+ else {
67
+ __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_stop).call(this);
68
+ }
69
+ });
70
+ }
71
+ }
72
+ exports.GasFeePoller = GasFeePoller;
73
+ _GasFeePoller_gasFeeFlows = new WeakMap(), _GasFeePoller_getEthQuery = new WeakMap(), _GasFeePoller_getGasFeeControllerEstimates = new WeakMap(), _GasFeePoller_getTransactions = new WeakMap(), _GasFeePoller_timeout = new WeakMap(), _GasFeePoller_running = new WeakMap(), _GasFeePoller_instances = new WeakSet(), _GasFeePoller_start = function _GasFeePoller_start() {
74
+ if (__classPrivateFieldGet(this, _GasFeePoller_running, "f")) {
75
+ return;
76
+ }
77
+ // Intentionally not awaiting since this starts the timeout chain.
78
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
79
+ __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_onTimeout).call(this);
80
+ __classPrivateFieldSet(this, _GasFeePoller_running, true, "f");
81
+ log('Started polling');
82
+ }, _GasFeePoller_stop = function _GasFeePoller_stop() {
83
+ if (!__classPrivateFieldGet(this, _GasFeePoller_running, "f")) {
84
+ return;
85
+ }
86
+ clearTimeout(__classPrivateFieldGet(this, _GasFeePoller_timeout, "f"));
87
+ __classPrivateFieldSet(this, _GasFeePoller_timeout, undefined, "f");
88
+ __classPrivateFieldSet(this, _GasFeePoller_running, false, "f");
89
+ log('Stopped polling');
90
+ }, _GasFeePoller_onTimeout = function _GasFeePoller_onTimeout() {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ yield __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_updateUnapprovedTransactions).call(this);
93
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
94
+ __classPrivateFieldSet(this, _GasFeePoller_timeout, setTimeout(() => __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_onTimeout).call(this), INTERVAL_MILLISECONDS), "f");
95
+ });
96
+ }, _GasFeePoller_updateUnapprovedTransactions = function _GasFeePoller_updateUnapprovedTransactions() {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ const unapprovedTransactions = __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_getUnapprovedTransactions).call(this);
99
+ log('Found unapproved transactions', {
100
+ count: unapprovedTransactions.length,
101
+ });
102
+ yield Promise.all(unapprovedTransactions.map((tx) => __classPrivateFieldGet(this, _GasFeePoller_instances, "m", _GasFeePoller_updateTransactionSuggestedFees).call(this, tx)));
103
+ });
104
+ }, _GasFeePoller_updateTransactionSuggestedFees = function _GasFeePoller_updateTransactionSuggestedFees(transactionMeta) {
105
+ return __awaiter(this, void 0, void 0, function* () {
106
+ const { chainId, networkClientId } = transactionMeta;
107
+ const ethQuery = __classPrivateFieldGet(this, _GasFeePoller_getEthQuery, "f").call(this, chainId, networkClientId);
108
+ const gasFeeFlow = (0, gas_flow_1.getGasFeeFlow)(transactionMeta, __classPrivateFieldGet(this, _GasFeePoller_gasFeeFlows, "f"));
109
+ if (!gasFeeFlow) {
110
+ log('No gas fee flow found', transactionMeta.id);
111
+ }
112
+ else {
113
+ log('Found gas fee flow', gasFeeFlow.constructor.name, transactionMeta.id);
114
+ }
115
+ const request = {
116
+ ethQuery,
117
+ getGasFeeControllerEstimates: __classPrivateFieldGet(this, _GasFeePoller_getGasFeeControllerEstimates, "f"),
118
+ transactionMeta,
119
+ };
120
+ let gasFeeEstimates;
121
+ if (gasFeeFlow) {
122
+ try {
123
+ const response = yield gasFeeFlow.getGasFees(request);
124
+ gasFeeEstimates = response.estimates;
125
+ }
126
+ catch (error) {
127
+ log('Failed to get suggested gas fees', transactionMeta.id, error);
128
+ }
129
+ }
130
+ if (!gasFeeEstimates && transactionMeta.gasFeeEstimatesLoaded) {
131
+ return;
132
+ }
133
+ transactionMeta.gasFeeEstimates = gasFeeEstimates;
134
+ transactionMeta.gasFeeEstimatesLoaded = true;
135
+ this.hub.emit('transaction-updated', transactionMeta);
136
+ log('Updated suggested gas fees', {
137
+ gasFeeEstimates: transactionMeta.gasFeeEstimates,
138
+ transaction: transactionMeta.id,
139
+ });
140
+ });
141
+ }, _GasFeePoller_getUnapprovedTransactions = function _GasFeePoller_getUnapprovedTransactions() {
142
+ return __classPrivateFieldGet(this, _GasFeePoller_getTransactions, "f").call(this).filter((tx) => tx.status === types_1.TransactionStatus.unapproved);
143
+ };
144
+ //# sourceMappingURL=GasFeePoller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GasFeePoller.js","sourceRoot":"","sources":["../../src/helpers/GasFeePoller.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport type { GasFeeState } from '@metamask/gas-fee-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport EventEmitter from 'events';\n\nimport type { NetworkClientId } from '../../../network-controller/src';\nimport { projectLogger } from '../logger';\nimport type { GasFeeEstimates, GasFeeFlow, GasFeeFlowRequest } from '../types';\nimport { TransactionStatus, type TransactionMeta } from '../types';\nimport { getGasFeeFlow } from '../utils/gas-flow';\n\nconst log = createModuleLogger(projectLogger, 'gas-fee-poller');\n\nconst INTERVAL_MILLISECONDS = 10000;\n\n/**\n * Automatically polls and updates suggested gas fees on unapproved transactions.\n */\nexport class GasFeePoller {\n hub: EventEmitter = new EventEmitter();\n\n #gasFeeFlows: GasFeeFlow[];\n\n #getEthQuery: (chainId: Hex, networkClientId?: NetworkClientId) => EthQuery;\n\n #getGasFeeControllerEstimates: () => Promise<GasFeeState>;\n\n #getTransactions: () => TransactionMeta[];\n\n #timeout: ReturnType<typeof setTimeout> | undefined;\n\n #running = false;\n\n /**\n * Constructs a new instance of the GasFeePoller.\n * @param options - The options for this instance.\n * @param options.gasFeeFlows - The gas fee flows to use to obtain suitable gas fees.\n * @param options.getEthQuery - Callback to obtain an EthQuery instance.\n * @param options.getGasFeeControllerEstimates - Callback to obtain the default fee estimates.\n * @param options.getTransactions - Callback to obtain the transaction data.\n * @param options.onStateChange - Callback to register a listener for controller state changes.\n */\n constructor({\n gasFeeFlows,\n getEthQuery,\n getGasFeeControllerEstimates,\n getTransactions,\n onStateChange,\n }: {\n gasFeeFlows: GasFeeFlow[];\n getEthQuery: (chainId: Hex, networkClientId?: NetworkClientId) => EthQuery;\n getGasFeeControllerEstimates: () => Promise<GasFeeState>;\n getTransactions: () => TransactionMeta[];\n onStateChange: (listener: () => void) => void;\n }) {\n this.#gasFeeFlows = gasFeeFlows;\n this.#getEthQuery = getEthQuery;\n this.#getGasFeeControllerEstimates = getGasFeeControllerEstimates;\n this.#getTransactions = getTransactions;\n\n onStateChange(() => {\n const unapprovedTransactions = this.#getUnapprovedTransactions();\n\n if (unapprovedTransactions.length) {\n this.#start();\n } else {\n this.#stop();\n }\n });\n }\n\n #start() {\n if (this.#running) {\n return;\n }\n\n // Intentionally not awaiting since this starts the timeout chain.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#onTimeout();\n\n this.#running = true;\n\n log('Started polling');\n }\n\n #stop() {\n if (!this.#running) {\n return;\n }\n\n clearTimeout(this.#timeout);\n\n this.#timeout = undefined;\n this.#running = false;\n\n log('Stopped polling');\n }\n\n async #onTimeout() {\n await this.#updateUnapprovedTransactions();\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n this.#timeout = setTimeout(() => this.#onTimeout(), INTERVAL_MILLISECONDS);\n }\n\n async #updateUnapprovedTransactions() {\n const unapprovedTransactions = this.#getUnapprovedTransactions();\n\n log('Found unapproved transactions', {\n count: unapprovedTransactions.length,\n });\n\n await Promise.all(\n unapprovedTransactions.map((tx) =>\n this.#updateTransactionSuggestedFees(tx),\n ),\n );\n }\n\n async #updateTransactionSuggestedFees(transactionMeta: TransactionMeta) {\n const { chainId, networkClientId } = transactionMeta;\n\n const ethQuery = this.#getEthQuery(chainId, networkClientId);\n const gasFeeFlow = getGasFeeFlow(transactionMeta, this.#gasFeeFlows);\n\n if (!gasFeeFlow) {\n log('No gas fee flow found', transactionMeta.id);\n } else {\n log(\n 'Found gas fee flow',\n gasFeeFlow.constructor.name,\n transactionMeta.id,\n );\n }\n\n const request: GasFeeFlowRequest = {\n ethQuery,\n getGasFeeControllerEstimates: this.#getGasFeeControllerEstimates,\n transactionMeta,\n };\n\n let gasFeeEstimates: GasFeeEstimates | undefined;\n\n if (gasFeeFlow) {\n try {\n const response = await gasFeeFlow.getGasFees(request);\n gasFeeEstimates = response.estimates;\n } catch (error) {\n log('Failed to get suggested gas fees', transactionMeta.id, error);\n }\n }\n\n if (!gasFeeEstimates && transactionMeta.gasFeeEstimatesLoaded) {\n return;\n }\n\n transactionMeta.gasFeeEstimates = gasFeeEstimates;\n transactionMeta.gasFeeEstimatesLoaded = true;\n\n this.hub.emit('transaction-updated', transactionMeta);\n\n log('Updated suggested gas fees', {\n gasFeeEstimates: transactionMeta.gasFeeEstimates,\n transaction: transactionMeta.id,\n });\n }\n\n #getUnapprovedTransactions() {\n return this.#getTransactions().filter(\n (tx) => tx.status === TransactionStatus.unapproved,\n );\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export type { EtherscanTransactionMeta } from './utils/etherscan';
3
3
  export { isEIP1559Transaction } from './utils/utils';
4
4
  export * from './types';
5
5
  export { determineTransactionType } from './utils/transaction-type';
6
+ export { mergeGasFeeEstimates } from './utils/gas-flow';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -14,11 +14,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.determineTransactionType = exports.isEIP1559Transaction = void 0;
17
+ exports.mergeGasFeeEstimates = exports.determineTransactionType = exports.isEIP1559Transaction = void 0;
18
18
  __exportStar(require("./TransactionController"), exports);
19
19
  var utils_1 = require("./utils/utils");
20
20
  Object.defineProperty(exports, "isEIP1559Transaction", { enumerable: true, get: function () { return utils_1.isEIP1559Transaction; } });
21
21
  __exportStar(require("./types"), exports);
22
22
  var transaction_type_1 = require("./utils/transaction-type");
23
23
  Object.defineProperty(exports, "determineTransactionType", { enumerable: true, get: function () { return transaction_type_1.determineTransactionType; } });
24
+ var gas_flow_1 = require("./utils/gas-flow");
25
+ Object.defineProperty(exports, "mergeGasFeeEstimates", { enumerable: true, get: function () { return gas_flow_1.mergeGasFeeEstimates; } });
24
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,0DAAwC;AAExC,uCAAqD;AAA5C,6GAAA,oBAAoB,OAAA;AAC7B,0CAAwB;AACxB,6DAAoE;AAA3D,4HAAA,wBAAwB,OAAA","sourcesContent":["export * from './TransactionController';\nexport type { EtherscanTransactionMeta } from './utils/etherscan';\nexport { isEIP1559Transaction } from './utils/utils';\nexport * from './types';\nexport { determineTransactionType } from './utils/transaction-type';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,0DAAwC;AAExC,uCAAqD;AAA5C,6GAAA,oBAAoB,OAAA;AAC7B,0CAAwB;AACxB,6DAAoE;AAA3D,4HAAA,wBAAwB,OAAA;AACjC,6CAAwD;AAA/C,gHAAA,oBAAoB,OAAA","sourcesContent":["export * from './TransactionController';\nexport type { EtherscanTransactionMeta } from './utils/etherscan';\nexport { isEIP1559Transaction } from './utils/utils';\nexport * from './types';\nexport { determineTransactionType } from './utils/transaction-type';\nexport { mergeGasFeeEstimates } from './utils/gas-flow';\n"]}