@metamask/transaction-controller 45.0.0 → 46.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -1
- package/dist/TransactionController.cjs +72 -67
- package/dist/TransactionController.cjs.map +1 -1
- package/dist/TransactionController.d.cts +10 -15
- package/dist/TransactionController.d.cts.map +1 -1
- package/dist/TransactionController.d.mts +10 -15
- package/dist/TransactionController.d.mts.map +1 -1
- package/dist/TransactionController.mjs +69 -64
- package/dist/TransactionController.mjs.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.cjs +4 -13
- package/dist/gas-flows/OracleLayer1GasFeeFlow.cjs.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.d.cts.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.d.mts.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.mjs +4 -13
- package/dist/gas-flows/OracleLayer1GasFeeFlow.mjs.map +1 -1
- package/dist/{utils/resimulate.cjs → helpers/ResimulateHelper.cjs} +93 -4
- package/dist/helpers/ResimulateHelper.cjs.map +1 -0
- package/dist/{utils/resimulate.d.cts → helpers/ResimulateHelper.d.cts} +13 -1
- package/dist/helpers/ResimulateHelper.d.cts.map +1 -0
- package/dist/{utils/resimulate.d.mts → helpers/ResimulateHelper.d.mts} +13 -1
- package/dist/helpers/ResimulateHelper.d.mts.map +1 -0
- package/dist/{utils/resimulate.mjs → helpers/ResimulateHelper.mjs} +93 -5
- package/dist/helpers/ResimulateHelper.mjs.map +1 -0
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs +6 -37
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +51 -1
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +51 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +6 -37
- package/dist/types.mjs.map +1 -1
- package/dist/utils/eip7702.cjs +87 -0
- package/dist/utils/eip7702.cjs.map +1 -0
- package/dist/utils/eip7702.d.cts +26 -0
- package/dist/utils/eip7702.d.cts.map +1 -0
- package/dist/utils/eip7702.d.mts +26 -0
- package/dist/utils/eip7702.d.mts.map +1 -0
- package/dist/utils/eip7702.mjs +83 -0
- package/dist/utils/eip7702.mjs.map +1 -0
- package/dist/utils/prepare.cjs +49 -0
- package/dist/utils/prepare.cjs.map +1 -0
- package/dist/utils/prepare.d.cts +21 -0
- package/dist/utils/prepare.d.cts.map +1 -0
- package/dist/utils/prepare.d.mts +21 -0
- package/dist/utils/prepare.d.mts.map +1 -0
- package/dist/utils/prepare.mjs +44 -0
- package/dist/utils/prepare.mjs.map +1 -0
- package/dist/utils/utils.cjs +3 -8
- package/dist/utils/utils.cjs.map +1 -1
- package/dist/utils/utils.d.cts.map +1 -1
- package/dist/utils/utils.d.mts.map +1 -1
- package/dist/utils/utils.mjs +3 -8
- package/dist/utils/utils.mjs.map +1 -1
- package/dist/utils/validation.cjs +91 -31
- package/dist/utils/validation.cjs.map +1 -1
- package/dist/utils/validation.d.cts +13 -5
- package/dist/utils/validation.d.cts.map +1 -1
- package/dist/utils/validation.d.mts +13 -5
- package/dist/utils/validation.d.mts.map +1 -1
- package/dist/utils/validation.mjs +92 -32
- package/dist/utils/validation.mjs.map +1 -1
- package/package.json +9 -9
- package/dist/utils/resimulate.cjs.map +0 -1
- package/dist/utils/resimulate.d.cts.map +0 -1
- package/dist/utils/resimulate.d.mts.map +0 -1
- package/dist/utils/resimulate.mjs.map +0 -1
|
@@ -10,16 +10,15 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
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");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_oracleAddress, _OracleLayer1GasFeeFlow_signTransaction, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams
|
|
13
|
+
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_oracleAddress, _OracleLayer1GasFeeFlow_signTransaction, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.OracleLayer1GasFeeFlow = void 0;
|
|
16
|
-
const common_1 = require("@ethereumjs/common");
|
|
17
|
-
const tx_1 = require("@ethereumjs/tx");
|
|
18
16
|
const contracts_1 = require("@ethersproject/contracts");
|
|
19
17
|
const providers_1 = require("@ethersproject/providers");
|
|
20
18
|
const utils_1 = require("@metamask/utils");
|
|
21
19
|
const lodash_1 = require("lodash");
|
|
22
20
|
const logger_1 = require("../logger.cjs");
|
|
21
|
+
const prepare_1 = require("../utils/prepare.cjs");
|
|
23
22
|
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'oracle-layer1-gas-fee-flow');
|
|
24
23
|
const DUMMY_KEY = 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';
|
|
25
24
|
const GAS_PRICE_ORACLE_ABI = [
|
|
@@ -68,10 +67,8 @@ _OracleLayer1GasFeeFlow_oracleAddress = new WeakMap(), _OracleLayer1GasFeeFlow_s
|
|
|
68
67
|
};
|
|
69
68
|
}, _OracleLayer1GasFeeFlow_buildUnserializedTransaction = function _OracleLayer1GasFeeFlow_buildUnserializedTransaction(transactionMeta, sign) {
|
|
70
69
|
const txParams = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildTransactionParams).call(this, transactionMeta);
|
|
71
|
-
const
|
|
72
|
-
let unserializedTransaction =
|
|
73
|
-
common,
|
|
74
|
-
});
|
|
70
|
+
const { chainId } = transactionMeta;
|
|
71
|
+
let unserializedTransaction = (0, prepare_1.prepareTransaction)(chainId, txParams);
|
|
75
72
|
if (sign) {
|
|
76
73
|
const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');
|
|
77
74
|
unserializedTransaction = unserializedTransaction.sign(keyBuffer);
|
|
@@ -82,11 +79,5 @@ _OracleLayer1GasFeeFlow_oracleAddress = new WeakMap(), _OracleLayer1GasFeeFlow_s
|
|
|
82
79
|
...(0, lodash_1.omit)(transactionMeta.txParams, 'gas'),
|
|
83
80
|
gasLimit: transactionMeta.txParams.gas,
|
|
84
81
|
};
|
|
85
|
-
}, _OracleLayer1GasFeeFlow_buildTransactionCommon = function _OracleLayer1GasFeeFlow_buildTransactionCommon(transactionMeta) {
|
|
86
|
-
const chainId = Number(transactionMeta.chainId);
|
|
87
|
-
return common_1.Common.custom({
|
|
88
|
-
chainId,
|
|
89
|
-
defaultHardfork: common_1.Hardfork.London,
|
|
90
|
-
});
|
|
91
82
|
};
|
|
92
83
|
//# sourceMappingURL=OracleLayer1GasFeeFlow.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.cjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.cjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wDAAoD;AACpD,wDAA+E;AAE/E,2CAAqD;AACrD,mCAA8B;AAE9B,0CAA0C;AAO1C,kDAAsD;AAEtD,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,4BAA4B,CAAC,CAAC;AAE5E,MAAM,SAAS,GACb,kEAAkE,CAAC;AAErE,MAAM,oBAAoB,GAAG;IAC3B;QACE,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACjE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACjE,eAAe,EAAE,MAAM;QACvB,IAAI,EAAE,UAAU;KACjB;CACF,CAAC;AAEF;;GAEG;AACH,MAAsB,sBAAsB;IAK1C,YAAY,aAAkB,EAAE,eAAyB;;QAJhD,wDAAoB;QAEpB,0DAA0B;QAGjC,uBAAA,IAAI,yCAAkB,aAAa,MAAA,CAAC;QACpC,uBAAA,IAAI,2CAAoB,eAAe,IAAI,KAAK,MAAA,CAAC;IACnD,CAAC;IAID,KAAK,CAAC,YAAY,CAChB,OAAgC;QAEhC,IAAI;YACF,OAAO,MAAM,uBAAA,IAAI,wFAAuB,MAA3B,IAAI,EAAwB,OAAO,CAAC,CAAC;SACnD;QAAC,OAAO,KAAK,EAAE;YACd,GAAG,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;SACzD;IACH,CAAC;CAuDF;AA5ED,wDA4EC;mNArDC,KAAK,wDACH,OAAgC;IAEhC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAE9C,MAAM,QAAQ,GAAG,IAAI,oBAAQ,CAC3B,uBAAA,IAAI,6CAAe,EACnB,oBAAoB;IACpB,wEAAwE;IACxE,IAAI,wBAAY,CAAC,QAAuC,CAAC,CAC1D,CAAC;IAEF,MAAM,qBAAqB,GAAG,uBAAA,IAAI,+FAA8B,MAAlC,IAAI,EAChC,eAAe,EACf,uBAAA,IAAI,+CAAiB,CACtB,CAAC,SAAS,EAAE,CAAC;IAEd,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAE9D,IAAI,MAAM,KAAK,SAAS,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;KAC3D;IAED,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,WAAW,EAAE;KAChC,CAAC;AACJ,CAAC,uHAGC,eAAgC,EAChC,IAAa;IAEb,MAAM,QAAQ,GAAG,uBAAA,IAAI,yFAAwB,MAA5B,IAAI,EAAyB,eAAe,CAAC,CAAC;IAC/D,MAAM,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC;IAEpC,IAAI,uBAAuB,GAAG,IAAA,4BAAkB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAEpE,IAAI,IAAI,EAAE;QACR,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAChD,uBAAuB,GAAG,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;KACnE;IAED,OAAO,uBAAuB,CAAC;AACjC,CAAC,2GAGC,eAAgC;IAEhC,OAAO;QACL,GAAG,IAAA,aAAI,EAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC;QACxC,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC,GAAG;KACvC,CAAC;AACJ,CAAC","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider, type ExternalProvider } from '@ethersproject/providers';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { omit } from 'lodash';\n\nimport { projectLogger } from '../logger';\nimport type {\n Layer1GasFeeFlow,\n Layer1GasFeeFlowRequest,\n Layer1GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { prepareTransaction } from '../utils/prepare';\n\nconst log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');\n\nconst DUMMY_KEY =\n 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';\n\nconst GAS_PRICE_ORACLE_ABI = [\n {\n inputs: [{ internalType: 'bytes', name: '_data', type: 'bytes' }],\n name: 'getL1Fee',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n/**\n * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.\n */\nexport abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow {\n readonly #oracleAddress: Hex;\n\n readonly #signTransaction: boolean;\n\n constructor(oracleAddress: Hex, signTransaction?: boolean) {\n this.#oracleAddress = oracleAddress;\n this.#signTransaction = signTransaction ?? false;\n }\n\n abstract matchesTransaction(transactionMeta: TransactionMeta): boolean;\n\n async getLayer1Fee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n try {\n return await this.#getOracleLayer1GasFee(request);\n } catch (error) {\n log('Failed to get oracle layer 1 gas fee', error);\n throw new Error(`Failed to get oracle layer 1 gas fee`);\n }\n }\n\n async #getOracleLayer1GasFee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n const { provider, transactionMeta } = request;\n\n const contract = new Contract(\n this.#oracleAddress,\n GAS_PRICE_ORACLE_ABI,\n // Network controller provider type is incompatible with ethers provider\n new Web3Provider(provider as unknown as ExternalProvider),\n );\n\n const serializedTransaction = this.#buildUnserializedTransaction(\n transactionMeta,\n this.#signTransaction,\n ).serialize();\n\n const result = await contract.getL1Fee(serializedTransaction);\n\n if (result === undefined) {\n throw new Error('No value returned from oracle contract');\n }\n\n return {\n layer1Fee: result.toHexString(),\n };\n }\n\n #buildUnserializedTransaction(\n transactionMeta: TransactionMeta,\n sign: boolean,\n ) {\n const txParams = this.#buildTransactionParams(transactionMeta);\n const { chainId } = transactionMeta;\n\n let unserializedTransaction = prepareTransaction(chainId, txParams);\n\n if (sign) {\n const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');\n unserializedTransaction = unserializedTransaction.sign(keyBuffer);\n }\n\n return unserializedTransaction;\n }\n\n #buildTransactionParams(\n transactionMeta: TransactionMeta,\n ): TransactionMeta['txParams'] {\n return {\n ...omit(transactionMeta.txParams, 'gas'),\n gasLimit: transactionMeta.txParams.gas,\n };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,EAChB,qBAAiB;AAkBlB;;GAEG;AACH,8BAAsB,sBAAuB,YAAW,gBAAgB;;gBAK1D,aAAa,EAAE,GAAG,EAAE,eAAe,CAAC,EAAE,OAAO;IAKzD,QAAQ,CAAC,kBAAkB,CAAC,eAAe,EAAE,eAAe,GAAG,OAAO;IAEhE,YAAY,CAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,wBAAwB,CAAC;CA8DrC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,EAChB,qBAAiB;AAkBlB;;GAEG;AACH,8BAAsB,sBAAuB,YAAW,gBAAgB;;gBAK1D,aAAa,EAAE,GAAG,EAAE,eAAe,CAAC,EAAE,OAAO;IAKzD,QAAQ,CAAC,kBAAkB,CAAC,eAAe,EAAE,eAAe,GAAG,OAAO;IAEhE,YAAY,CAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,wBAAwB,CAAC;CA8DrC"}
|
|
@@ -9,15 +9,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
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");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_oracleAddress, _OracleLayer1GasFeeFlow_signTransaction, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams
|
|
13
|
-
import { Common, Hardfork } from "@ethereumjs/common";
|
|
14
|
-
import { TransactionFactory } from "@ethereumjs/tx";
|
|
12
|
+
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_oracleAddress, _OracleLayer1GasFeeFlow_signTransaction, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams;
|
|
15
13
|
import { Contract } from "@ethersproject/contracts";
|
|
16
14
|
import { Web3Provider } from "@ethersproject/providers";
|
|
17
15
|
import { createModuleLogger } from "@metamask/utils";
|
|
18
16
|
import $lodash from "lodash";
|
|
19
17
|
const { omit } = $lodash;
|
|
20
18
|
import { projectLogger } from "../logger.mjs";
|
|
19
|
+
import { prepareTransaction } from "../utils/prepare.mjs";
|
|
21
20
|
const log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');
|
|
22
21
|
const DUMMY_KEY = 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';
|
|
23
22
|
const GAS_PRICE_ORACLE_ABI = [
|
|
@@ -65,10 +64,8 @@ _OracleLayer1GasFeeFlow_oracleAddress = new WeakMap(), _OracleLayer1GasFeeFlow_s
|
|
|
65
64
|
};
|
|
66
65
|
}, _OracleLayer1GasFeeFlow_buildUnserializedTransaction = function _OracleLayer1GasFeeFlow_buildUnserializedTransaction(transactionMeta, sign) {
|
|
67
66
|
const txParams = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildTransactionParams).call(this, transactionMeta);
|
|
68
|
-
const
|
|
69
|
-
let unserializedTransaction =
|
|
70
|
-
common,
|
|
71
|
-
});
|
|
67
|
+
const { chainId } = transactionMeta;
|
|
68
|
+
let unserializedTransaction = prepareTransaction(chainId, txParams);
|
|
72
69
|
if (sign) {
|
|
73
70
|
const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');
|
|
74
71
|
unserializedTransaction = unserializedTransaction.sign(keyBuffer);
|
|
@@ -79,11 +76,5 @@ _OracleLayer1GasFeeFlow_oracleAddress = new WeakMap(), _OracleLayer1GasFeeFlow_s
|
|
|
79
76
|
...omit(transactionMeta.txParams, 'gas'),
|
|
80
77
|
gasLimit: transactionMeta.txParams.gas,
|
|
81
78
|
};
|
|
82
|
-
}, _OracleLayer1GasFeeFlow_buildTransactionCommon = function _OracleLayer1GasFeeFlow_buildTransactionCommon(transactionMeta) {
|
|
83
|
-
const chainId = Number(transactionMeta.chainId);
|
|
84
|
-
return Common.custom({
|
|
85
|
-
chainId,
|
|
86
|
-
defaultHardfork: Hardfork.London,
|
|
87
|
-
});
|
|
88
79
|
};
|
|
89
80
|
//# sourceMappingURL=OracleLayer1GasFeeFlow.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.mjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.mjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider, type ExternalProvider } from '@ethersproject/providers';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { omit } from 'lodash';\n\nimport { projectLogger } from '../logger';\nimport type {\n Layer1GasFeeFlow,\n Layer1GasFeeFlowRequest,\n Layer1GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { prepareTransaction } from '../utils/prepare';\n\nconst log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');\n\nconst DUMMY_KEY =\n 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';\n\nconst GAS_PRICE_ORACLE_ABI = [\n {\n inputs: [{ internalType: 'bytes', name: '_data', type: 'bytes' }],\n name: 'getL1Fee',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n/**\n * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.\n */\nexport abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow {\n readonly #oracleAddress: Hex;\n\n readonly #signTransaction: boolean;\n\n constructor(oracleAddress: Hex, signTransaction?: boolean) {\n this.#oracleAddress = oracleAddress;\n this.#signTransaction = signTransaction ?? false;\n }\n\n abstract matchesTransaction(transactionMeta: TransactionMeta): boolean;\n\n async getLayer1Fee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n try {\n return await this.#getOracleLayer1GasFee(request);\n } catch (error) {\n log('Failed to get oracle layer 1 gas fee', error);\n throw new Error(`Failed to get oracle layer 1 gas fee`);\n }\n }\n\n async #getOracleLayer1GasFee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n const { provider, transactionMeta } = request;\n\n const contract = new Contract(\n this.#oracleAddress,\n GAS_PRICE_ORACLE_ABI,\n // Network controller provider type is incompatible with ethers provider\n new Web3Provider(provider as unknown as ExternalProvider),\n );\n\n const serializedTransaction = this.#buildUnserializedTransaction(\n transactionMeta,\n this.#signTransaction,\n ).serialize();\n\n const result = await contract.getL1Fee(serializedTransaction);\n\n if (result === undefined) {\n throw new Error('No value returned from oracle contract');\n }\n\n return {\n layer1Fee: result.toHexString(),\n };\n }\n\n #buildUnserializedTransaction(\n transactionMeta: TransactionMeta,\n sign: boolean,\n ) {\n const txParams = this.#buildTransactionParams(transactionMeta);\n const { chainId } = transactionMeta;\n\n let unserializedTransaction = prepareTransaction(chainId, txParams);\n\n if (sign) {\n const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');\n unserializedTransaction = unserializedTransaction.sign(keyBuffer);\n }\n\n return unserializedTransaction;\n }\n\n #buildTransactionParams(\n transactionMeta: TransactionMeta,\n ): TransactionMeta['txParams'] {\n return {\n ...omit(transactionMeta.txParams, 'gas'),\n gasLimit: transactionMeta.txParams.gas,\n };\n }\n}\n"]}
|
|
@@ -1,18 +1,101 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
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");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
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");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _ResimulateHelper_instances, _ResimulateHelper_timeoutIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_start, _ResimulateHelper_queueUpdate, _ResimulateHelper_stop, _ResimulateHelper_removeListener;
|
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasSimulationDataChanged = exports.shouldResimulate = exports.BLOCK_TIME_ADDITIONAL_SECONDS = exports.VALUE_COMPARISON_PERCENT_THRESHOLD = exports.BLOCKAID_RESULT_TYPE_MALICIOUS = exports.RESIMULATE_PARAMS = void 0;
|
|
15
|
+
exports.hasSimulationDataChanged = exports.shouldResimulate = exports.ResimulateHelper = exports.RESIMULATE_INTERVAL_MS = exports.BLOCK_TIME_ADDITIONAL_SECONDS = exports.VALUE_COMPARISON_PERCENT_THRESHOLD = exports.BLOCKAID_RESULT_TYPE_MALICIOUS = exports.RESIMULATE_PARAMS = void 0;
|
|
4
16
|
const utils_1 = require("@metamask/utils");
|
|
5
17
|
const bn_js_1 = require("bn.js");
|
|
6
18
|
const lodash_1 = require("lodash");
|
|
7
19
|
const logger_1 = require("../logger.cjs");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
20
|
+
const types_1 = require("../types.cjs");
|
|
21
|
+
const utils_2 = require("../utils/utils.cjs");
|
|
22
|
+
const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, 'resimulate-helper');
|
|
10
23
|
exports.RESIMULATE_PARAMS = ['to', 'value', 'data'];
|
|
11
24
|
exports.BLOCKAID_RESULT_TYPE_MALICIOUS = 'Malicious';
|
|
12
25
|
exports.VALUE_COMPARISON_PERCENT_THRESHOLD = 5;
|
|
13
26
|
exports.BLOCK_TIME_ADDITIONAL_SECONDS = 60;
|
|
27
|
+
exports.RESIMULATE_INTERVAL_MS = 3000;
|
|
28
|
+
class ResimulateHelper {
|
|
29
|
+
constructor({ getTransactions, simulateTransaction, onTransactionsUpdate, }) {
|
|
30
|
+
_ResimulateHelper_instances.add(this);
|
|
31
|
+
// Map of transactionId <=> timeoutId
|
|
32
|
+
_ResimulateHelper_timeoutIds.set(this, new Map());
|
|
33
|
+
_ResimulateHelper_getTransactions.set(this, void 0);
|
|
34
|
+
_ResimulateHelper_simulateTransaction.set(this, void 0);
|
|
35
|
+
__classPrivateFieldSet(this, _ResimulateHelper_getTransactions, getTransactions, "f");
|
|
36
|
+
__classPrivateFieldSet(this, _ResimulateHelper_simulateTransaction, simulateTransaction, "f");
|
|
37
|
+
onTransactionsUpdate(__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_onTransactionsUpdate).bind(this));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.ResimulateHelper = ResimulateHelper;
|
|
41
|
+
_ResimulateHelper_timeoutIds = new WeakMap(), _ResimulateHelper_getTransactions = new WeakMap(), _ResimulateHelper_simulateTransaction = new WeakMap(), _ResimulateHelper_instances = new WeakSet(), _ResimulateHelper_onTransactionsUpdate = function _ResimulateHelper_onTransactionsUpdate() {
|
|
42
|
+
const unapprovedTransactions = __classPrivateFieldGet(this, _ResimulateHelper_getTransactions, "f").call(this).filter((tx) => tx.status === types_1.TransactionStatus.unapproved);
|
|
43
|
+
const unapprovedTransactionIds = new Set(unapprovedTransactions.map((tx) => tx.id));
|
|
44
|
+
// Combine unapproved transaction IDs and currently active resimulations
|
|
45
|
+
const allTransactionIds = new Set([
|
|
46
|
+
...unapprovedTransactionIds,
|
|
47
|
+
...__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").keys(),
|
|
48
|
+
]);
|
|
49
|
+
allTransactionIds.forEach((transactionId) => {
|
|
50
|
+
const transactionMeta = unapprovedTransactions.find((tx) => tx.id === transactionId);
|
|
51
|
+
if (transactionMeta?.isActive) {
|
|
52
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_start).call(this, transactionMeta);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_stop).call(this, transactionId);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}, _ResimulateHelper_start = function _ResimulateHelper_start(transactionMeta) {
|
|
59
|
+
const { id: transactionId } = transactionMeta;
|
|
60
|
+
if (__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const listener = () => {
|
|
64
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
65
|
+
__classPrivateFieldGet(this, _ResimulateHelper_simulateTransaction, "f").call(this, transactionMeta)
|
|
66
|
+
.catch((error) => {
|
|
67
|
+
/* istanbul ignore next */
|
|
68
|
+
log('Error during transaction resimulation', error);
|
|
69
|
+
})
|
|
70
|
+
.finally(() => {
|
|
71
|
+
// Schedule the next execution
|
|
72
|
+
if (__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
73
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_queueUpdate).call(this, transactionId, listener);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
// Start the first execution
|
|
78
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_queueUpdate).call(this, transactionId, listener);
|
|
79
|
+
log(`Started resimulating transaction ${transactionId} every ${exports.RESIMULATE_INTERVAL_MS} milliseconds`);
|
|
80
|
+
}, _ResimulateHelper_queueUpdate = function _ResimulateHelper_queueUpdate(transactionId, listener) {
|
|
81
|
+
const timeoutId = setTimeout(listener, exports.RESIMULATE_INTERVAL_MS);
|
|
82
|
+
__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").set(transactionId, timeoutId);
|
|
83
|
+
}, _ResimulateHelper_stop = function _ResimulateHelper_stop(transactionId) {
|
|
84
|
+
if (!__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_removeListener).call(this, transactionId);
|
|
88
|
+
log(`Stopped resimulating transaction ${transactionId} every ${exports.RESIMULATE_INTERVAL_MS} milliseconds`);
|
|
89
|
+
}, _ResimulateHelper_removeListener = function _ResimulateHelper_removeListener(id) {
|
|
90
|
+
const timeoutId = __classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").get(id);
|
|
91
|
+
if (timeoutId) {
|
|
92
|
+
clearTimeout(timeoutId);
|
|
93
|
+
__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").delete(id);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
14
96
|
/**
|
|
15
97
|
* Determine if a transaction should be resimulated.
|
|
98
|
+
*
|
|
16
99
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
17
100
|
* @param newTransactionMeta - The new transaction metadata.
|
|
18
101
|
* @returns Whether the transaction should be resimulated.
|
|
@@ -45,6 +128,7 @@ function shouldResimulate(originalTransactionMeta, newTransactionMeta) {
|
|
|
45
128
|
exports.shouldResimulate = shouldResimulate;
|
|
46
129
|
/**
|
|
47
130
|
* Determine if the simulation data has changed.
|
|
131
|
+
*
|
|
48
132
|
* @param originalSimulationData - The original simulation data.
|
|
49
133
|
* @param newSimulationData - The new simulation data.
|
|
50
134
|
* @returns Whether the simulation data has changed.
|
|
@@ -84,6 +168,7 @@ function hasSimulationDataChanged(originalSimulationData, newSimulationData) {
|
|
|
84
168
|
exports.hasSimulationDataChanged = hasSimulationDataChanged;
|
|
85
169
|
/**
|
|
86
170
|
* Determine if the transaction parameters have been updated.
|
|
171
|
+
*
|
|
87
172
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
88
173
|
* @param newTransactionMeta - The new transaction metadata.
|
|
89
174
|
* @returns Whether the transaction parameters have been updated.
|
|
@@ -106,6 +191,7 @@ function isParametersUpdated(originalTransactionMeta, newTransactionMeta) {
|
|
|
106
191
|
}
|
|
107
192
|
/**
|
|
108
193
|
* Determine if a transaction has a new security alert.
|
|
194
|
+
*
|
|
109
195
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
110
196
|
* @param newTransactionMeta - The new transaction metadata.
|
|
111
197
|
* @returns Whether the transaction has a new security alert.
|
|
@@ -125,6 +211,7 @@ function hasNewSecurityAlert(originalTransactionMeta, newTransactionMeta) {
|
|
|
125
211
|
}
|
|
126
212
|
/**
|
|
127
213
|
* Determine if a transaction has a value and simulation native balance mismatch.
|
|
214
|
+
*
|
|
128
215
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
129
216
|
* @param newTransactionMeta - The new transaction metadata.
|
|
130
217
|
* @returns Whether the transaction has a value and simulation native balance mismatch.
|
|
@@ -142,6 +229,7 @@ function hasValueAndNativeBalanceMismatch(originalTransactionMeta, newTransactio
|
|
|
142
229
|
}
|
|
143
230
|
/**
|
|
144
231
|
* Determine if a balance change has been updated.
|
|
232
|
+
*
|
|
145
233
|
* @param originalBalanceChange - The original balance change.
|
|
146
234
|
* @param newBalanceChange - The new balance change.
|
|
147
235
|
* @returns Whether the balance change has been updated.
|
|
@@ -151,6 +239,7 @@ function isBalanceChangeUpdated(originalBalanceChange, newBalanceChange) {
|
|
|
151
239
|
}
|
|
152
240
|
/**
|
|
153
241
|
* Determine if the percentage change between two values is within a threshold.
|
|
242
|
+
*
|
|
154
243
|
* @param originalValue - The original value.
|
|
155
244
|
* @param newValue - The new value.
|
|
156
245
|
* @param originalNegative - Whether the original value is negative.
|
|
@@ -169,4 +258,4 @@ function percentageChangeWithinThreshold(originalValue, newValue, originalNegati
|
|
|
169
258
|
return ((0, utils_2.getPercentageChange)(originalValueBN, newValueBN) <=
|
|
170
259
|
exports.VALUE_COMPARISON_PERCENT_THRESHOLD);
|
|
171
260
|
}
|
|
172
|
-
//# sourceMappingURL=
|
|
261
|
+
//# sourceMappingURL=ResimulateHelper.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResimulateHelper.cjs","sourceRoot":"","sources":["../../src/helpers/ResimulateHelper.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Hex } from '@metamask/utils';\nimport { remove0x } from '@metamask/utils';\nimport { BN } from 'bn.js';\nimport { isEqual } from 'lodash';\n\nimport { createModuleLogger, projectLogger } from '../logger';\nimport { TransactionStatus } from '../types';\nimport type {\n SimulationBalanceChange,\n SimulationData,\n TransactionMeta,\n TransactionParams,\n} from '../types';\nimport { getPercentageChange } from '../utils/utils';\n\nconst log = createModuleLogger(projectLogger, 'resimulate-helper');\n\nexport const RESIMULATE_PARAMS = ['to', 'value', 'data'] as const;\nexport const BLOCKAID_RESULT_TYPE_MALICIOUS = 'Malicious';\nexport const VALUE_COMPARISON_PERCENT_THRESHOLD = 5;\nexport const BLOCK_TIME_ADDITIONAL_SECONDS = 60;\nexport const RESIMULATE_INTERVAL_MS = 3000;\n\nexport type ResimulateResponse = {\n blockTime?: number;\n resimulate: boolean;\n};\n\nexport type ResimulateHelperOptions = {\n getTransactions: () => TransactionMeta[];\n onTransactionsUpdate: (listener: () => void) => void;\n simulateTransaction: (transactionMeta: TransactionMeta) => Promise<void>;\n};\n\nexport class ResimulateHelper {\n // Map of transactionId <=> timeoutId\n readonly #timeoutIds: Map<string, NodeJS.Timeout> = new Map();\n\n readonly #getTransactions: () => TransactionMeta[];\n\n readonly #simulateTransaction: (\n transactionMeta: TransactionMeta,\n ) => Promise<void>;\n\n constructor({\n getTransactions,\n simulateTransaction,\n onTransactionsUpdate,\n }: ResimulateHelperOptions) {\n this.#getTransactions = getTransactions;\n this.#simulateTransaction = simulateTransaction;\n\n onTransactionsUpdate(this.#onTransactionsUpdate.bind(this));\n }\n\n #onTransactionsUpdate() {\n const unapprovedTransactions = this.#getTransactions().filter(\n (tx) => tx.status === TransactionStatus.unapproved,\n );\n\n const unapprovedTransactionIds = new Set(\n unapprovedTransactions.map((tx) => tx.id),\n );\n\n // Combine unapproved transaction IDs and currently active resimulations\n const allTransactionIds = new Set([\n ...unapprovedTransactionIds,\n ...this.#timeoutIds.keys(),\n ]);\n\n allTransactionIds.forEach((transactionId) => {\n const transactionMeta = unapprovedTransactions.find(\n (tx) => tx.id === transactionId,\n ) as TransactionMeta;\n\n if (transactionMeta?.isActive) {\n this.#start(transactionMeta);\n } else {\n this.#stop(transactionId);\n }\n });\n }\n\n #start(transactionMeta: TransactionMeta) {\n const { id: transactionId } = transactionMeta;\n if (this.#timeoutIds.has(transactionId)) {\n return;\n }\n\n const listener = () => {\n // eslint-disable-next-line promise/catch-or-return\n this.#simulateTransaction(transactionMeta)\n .catch((error) => {\n /* istanbul ignore next */\n log('Error during transaction resimulation', error);\n })\n .finally(() => {\n // Schedule the next execution\n if (this.#timeoutIds.has(transactionId)) {\n this.#queueUpdate(transactionId, listener);\n }\n });\n };\n\n // Start the first execution\n this.#queueUpdate(transactionId, listener);\n log(\n `Started resimulating transaction ${transactionId} every ${RESIMULATE_INTERVAL_MS} milliseconds`,\n );\n }\n\n #queueUpdate(transactionId: string, listener: () => void) {\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#timeoutIds.set(transactionId, timeoutId);\n }\n\n #stop(transactionId: string) {\n if (!this.#timeoutIds.has(transactionId)) {\n return;\n }\n\n this.#removeListener(transactionId);\n log(\n `Stopped resimulating transaction ${transactionId} every ${RESIMULATE_INTERVAL_MS} milliseconds`,\n );\n }\n\n #removeListener(id: string) {\n const timeoutId = this.#timeoutIds.get(id);\n if (timeoutId) {\n clearTimeout(timeoutId);\n this.#timeoutIds.delete(id);\n }\n }\n}\n\n/**\n * Determine if a transaction should be resimulated.\n *\n * @param originalTransactionMeta - The original transaction metadata.\n * @param newTransactionMeta - The new transaction metadata.\n * @returns Whether the transaction should be resimulated.\n */\nexport function shouldResimulate(\n originalTransactionMeta: TransactionMeta,\n newTransactionMeta: TransactionMeta,\n) {\n const { id: transactionId } = newTransactionMeta;\n\n const parametersUpdated = isParametersUpdated(\n originalTransactionMeta,\n newTransactionMeta,\n );\n\n const securityAlert = hasNewSecurityAlert(\n originalTransactionMeta,\n newTransactionMeta,\n );\n\n const valueAndNativeBalanceMismatch = hasValueAndNativeBalanceMismatch(\n originalTransactionMeta,\n newTransactionMeta,\n );\n\n const resimulate =\n parametersUpdated || securityAlert || valueAndNativeBalanceMismatch;\n\n let blockTime: number | undefined;\n\n if (securityAlert || valueAndNativeBalanceMismatch) {\n const nowSeconds = Math.floor(Date.now() / 1000);\n blockTime = nowSeconds + BLOCK_TIME_ADDITIONAL_SECONDS;\n }\n\n if (resimulate) {\n log('Transaction should be resimulated', {\n transactionId,\n blockTime,\n parametersUpdated,\n securityAlert,\n valueAndNativeBalanceMismatch,\n });\n }\n\n return {\n blockTime,\n resimulate,\n };\n}\n\n/**\n * Determine if the simulation data has changed.\n *\n * @param originalSimulationData - The original simulation data.\n * @param newSimulationData - The new simulation data.\n * @returns Whether the simulation data has changed.\n */\nexport function hasSimulationDataChanged(\n originalSimulationData: SimulationData,\n newSimulationData: SimulationData,\n): boolean {\n if (isEqual(originalSimulationData, newSimulationData)) {\n return false;\n }\n\n if (\n isBalanceChangeUpdated(\n originalSimulationData?.nativeBalanceChange,\n newSimulationData?.nativeBalanceChange,\n )\n ) {\n log('Simulation data native balance changed');\n return true;\n }\n\n if (\n originalSimulationData.tokenBalanceChanges.length !==\n newSimulationData.tokenBalanceChanges.length\n ) {\n return true;\n }\n\n for (const originalTokenBalanceChange of originalSimulationData.tokenBalanceChanges) {\n const newTokenBalanceChange = newSimulationData.tokenBalanceChanges.find(\n ({ address, id }) =>\n address === originalTokenBalanceChange.address &&\n id === originalTokenBalanceChange.id,\n );\n\n if (!newTokenBalanceChange) {\n log('Missing new token balance', {\n address: originalTokenBalanceChange.address,\n id: originalTokenBalanceChange.id,\n });\n\n return true;\n }\n\n if (\n isBalanceChangeUpdated(originalTokenBalanceChange, newTokenBalanceChange)\n ) {\n log('Simulation data token balance changed', {\n originalTokenBalanceChange,\n newTokenBalanceChange,\n });\n\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine if the transaction parameters have been updated.\n *\n * @param originalTransactionMeta - The original transaction metadata.\n * @param newTransactionMeta - The new transaction metadata.\n * @returns Whether the transaction parameters have been updated.\n */\nfunction isParametersUpdated(\n originalTransactionMeta: TransactionMeta,\n newTransactionMeta: TransactionMeta,\n): boolean {\n const { id: transactionId, txParams: newParams } = newTransactionMeta;\n const { txParams: originalParams } = originalTransactionMeta;\n\n if (!originalParams || isEqual(originalParams, newParams)) {\n return false;\n }\n\n const params = Object.keys(newParams) as (keyof TransactionParams)[];\n\n const updatedProperties = params.filter(\n (param) => newParams[param] !== originalParams[param],\n );\n\n log('Transaction parameters updated', {\n transactionId,\n updatedProperties,\n originalParams,\n newParams,\n });\n\n return RESIMULATE_PARAMS.some((param) => updatedProperties.includes(param));\n}\n\n/**\n * Determine if a transaction has a new security alert.\n *\n * @param originalTransactionMeta - The original transaction metadata.\n * @param newTransactionMeta - The new transaction metadata.\n * @returns Whether the transaction has a new security alert.\n */\nfunction hasNewSecurityAlert(\n originalTransactionMeta: TransactionMeta,\n newTransactionMeta: TransactionMeta,\n): boolean {\n const { securityAlertResponse: originalSecurityAlertResponse } =\n originalTransactionMeta;\n\n const { id: transactionId, securityAlertResponse: newSecurityAlertResponse } =\n newTransactionMeta;\n\n if (isEqual(originalSecurityAlertResponse, newSecurityAlertResponse)) {\n return false;\n }\n\n log('Security alert updated', {\n transactionId,\n originalSecurityAlertResponse,\n newSecurityAlertResponse,\n });\n\n return (\n newSecurityAlertResponse?.result_type === BLOCKAID_RESULT_TYPE_MALICIOUS\n );\n}\n\n/**\n * Determine if a transaction has a value and simulation native balance mismatch.\n *\n * @param originalTransactionMeta - The original transaction metadata.\n * @param newTransactionMeta - The new transaction metadata.\n * @returns Whether the transaction has a value and simulation native balance mismatch.\n */\nfunction hasValueAndNativeBalanceMismatch(\n originalTransactionMeta: TransactionMeta,\n newTransactionMeta: TransactionMeta,\n): boolean {\n const { simulationData: originalSimulationData } = originalTransactionMeta;\n\n const { simulationData: newSimulationData, txParams: newTxParams } =\n newTransactionMeta;\n\n if (\n !newSimulationData ||\n isEqual(originalSimulationData, newSimulationData)\n ) {\n return false;\n }\n\n const newValue = newTxParams?.value ?? '0x0';\n\n const newNativeBalanceDifference =\n newSimulationData?.nativeBalanceChange?.difference ?? '0x0';\n\n return !percentageChangeWithinThreshold(\n newValue as Hex,\n newNativeBalanceDifference,\n false,\n newSimulationData?.nativeBalanceChange?.isDecrease === false,\n );\n}\n\n/**\n * Determine if a balance change has been updated.\n *\n * @param originalBalanceChange - The original balance change.\n * @param newBalanceChange - The new balance change.\n * @returns Whether the balance change has been updated.\n */\nfunction isBalanceChangeUpdated(\n originalBalanceChange?: SimulationBalanceChange,\n newBalanceChange?: SimulationBalanceChange,\n): boolean {\n return !percentageChangeWithinThreshold(\n originalBalanceChange?.difference ?? '0x0',\n newBalanceChange?.difference ?? '0x0',\n originalBalanceChange?.isDecrease === false,\n newBalanceChange?.isDecrease === false,\n );\n}\n\n/**\n * Determine if the percentage change between two values is within a threshold.\n *\n * @param originalValue - The original value.\n * @param newValue - The new value.\n * @param originalNegative - Whether the original value is negative.\n * @param newNegative - Whether the new value is negative.\n * @returns Whether the percentage change between the two values is within a threshold.\n */\nfunction percentageChangeWithinThreshold(\n originalValue: Hex,\n newValue: Hex,\n originalNegative?: boolean,\n newNegative?: boolean,\n): boolean {\n let originalValueBN = new BN(remove0x(originalValue), 'hex');\n let newValueBN = new BN(remove0x(newValue), 'hex');\n\n if (originalNegative) {\n originalValueBN = originalValueBN.neg();\n }\n\n if (newNegative) {\n newValueBN = newValueBN.neg();\n }\n\n return (\n getPercentageChange(originalValueBN, newValueBN) <=\n VALUE_COMPARISON_PERCENT_THRESHOLD\n );\n}\n"]}
|
|
@@ -3,12 +3,23 @@ export declare const RESIMULATE_PARAMS: readonly ["to", "value", "data"];
|
|
|
3
3
|
export declare const BLOCKAID_RESULT_TYPE_MALICIOUS = "Malicious";
|
|
4
4
|
export declare const VALUE_COMPARISON_PERCENT_THRESHOLD = 5;
|
|
5
5
|
export declare const BLOCK_TIME_ADDITIONAL_SECONDS = 60;
|
|
6
|
+
export declare const RESIMULATE_INTERVAL_MS = 3000;
|
|
6
7
|
export type ResimulateResponse = {
|
|
7
8
|
blockTime?: number;
|
|
8
9
|
resimulate: boolean;
|
|
9
10
|
};
|
|
11
|
+
export type ResimulateHelperOptions = {
|
|
12
|
+
getTransactions: () => TransactionMeta[];
|
|
13
|
+
onTransactionsUpdate: (listener: () => void) => void;
|
|
14
|
+
simulateTransaction: (transactionMeta: TransactionMeta) => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
export declare class ResimulateHelper {
|
|
17
|
+
#private;
|
|
18
|
+
constructor({ getTransactions, simulateTransaction, onTransactionsUpdate, }: ResimulateHelperOptions);
|
|
19
|
+
}
|
|
10
20
|
/**
|
|
11
21
|
* Determine if a transaction should be resimulated.
|
|
22
|
+
*
|
|
12
23
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
13
24
|
* @param newTransactionMeta - The new transaction metadata.
|
|
14
25
|
* @returns Whether the transaction should be resimulated.
|
|
@@ -19,9 +30,10 @@ export declare function shouldResimulate(originalTransactionMeta: TransactionMet
|
|
|
19
30
|
};
|
|
20
31
|
/**
|
|
21
32
|
* Determine if the simulation data has changed.
|
|
33
|
+
*
|
|
22
34
|
* @param originalSimulationData - The original simulation data.
|
|
23
35
|
* @param newSimulationData - The new simulation data.
|
|
24
36
|
* @returns Whether the simulation data has changed.
|
|
25
37
|
*/
|
|
26
38
|
export declare function hasSimulationDataChanged(originalSimulationData: SimulationData, newSimulationData: SimulationData): boolean;
|
|
27
|
-
//# sourceMappingURL=
|
|
39
|
+
//# sourceMappingURL=ResimulateHelper.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResimulateHelper.d.cts","sourceRoot":"","sources":["../../src/helpers/ResimulateHelper.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEV,cAAc,EACd,eAAe,EAEhB,qBAAiB;AAKlB,eAAO,MAAM,iBAAiB,kCAAmC,CAAC;AAClE,eAAO,MAAM,8BAA8B,cAAc,CAAC;AAC1D,eAAO,MAAM,kCAAkC,IAAI,CAAC;AACpD,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAChD,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,eAAe,EAAE,MAAM,eAAe,EAAE,CAAC;IACzC,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACrD,mBAAmB,EAAE,CAAC,eAAe,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E,CAAC;AAEF,qBAAa,gBAAgB;;gBAUf,EACV,eAAe,EACf,mBAAmB,EACnB,oBAAoB,GACrB,EAAE,uBAAuB;CAsF3B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,uBAAuB,EAAE,eAAe,EACxC,kBAAkB,EAAE,eAAe;;;EA2CpC;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,sBAAsB,EAAE,cAAc,EACtC,iBAAiB,EAAE,cAAc,GAChC,OAAO,CAmDT"}
|
|
@@ -3,12 +3,23 @@ export declare const RESIMULATE_PARAMS: readonly ["to", "value", "data"];
|
|
|
3
3
|
export declare const BLOCKAID_RESULT_TYPE_MALICIOUS = "Malicious";
|
|
4
4
|
export declare const VALUE_COMPARISON_PERCENT_THRESHOLD = 5;
|
|
5
5
|
export declare const BLOCK_TIME_ADDITIONAL_SECONDS = 60;
|
|
6
|
+
export declare const RESIMULATE_INTERVAL_MS = 3000;
|
|
6
7
|
export type ResimulateResponse = {
|
|
7
8
|
blockTime?: number;
|
|
8
9
|
resimulate: boolean;
|
|
9
10
|
};
|
|
11
|
+
export type ResimulateHelperOptions = {
|
|
12
|
+
getTransactions: () => TransactionMeta[];
|
|
13
|
+
onTransactionsUpdate: (listener: () => void) => void;
|
|
14
|
+
simulateTransaction: (transactionMeta: TransactionMeta) => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
export declare class ResimulateHelper {
|
|
17
|
+
#private;
|
|
18
|
+
constructor({ getTransactions, simulateTransaction, onTransactionsUpdate, }: ResimulateHelperOptions);
|
|
19
|
+
}
|
|
10
20
|
/**
|
|
11
21
|
* Determine if a transaction should be resimulated.
|
|
22
|
+
*
|
|
12
23
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
13
24
|
* @param newTransactionMeta - The new transaction metadata.
|
|
14
25
|
* @returns Whether the transaction should be resimulated.
|
|
@@ -19,9 +30,10 @@ export declare function shouldResimulate(originalTransactionMeta: TransactionMet
|
|
|
19
30
|
};
|
|
20
31
|
/**
|
|
21
32
|
* Determine if the simulation data has changed.
|
|
33
|
+
*
|
|
22
34
|
* @param originalSimulationData - The original simulation data.
|
|
23
35
|
* @param newSimulationData - The new simulation data.
|
|
24
36
|
* @returns Whether the simulation data has changed.
|
|
25
37
|
*/
|
|
26
38
|
export declare function hasSimulationDataChanged(originalSimulationData: SimulationData, newSimulationData: SimulationData): boolean;
|
|
27
|
-
//# sourceMappingURL=
|
|
39
|
+
//# sourceMappingURL=ResimulateHelper.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResimulateHelper.d.mts","sourceRoot":"","sources":["../../src/helpers/ResimulateHelper.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEV,cAAc,EACd,eAAe,EAEhB,qBAAiB;AAKlB,eAAO,MAAM,iBAAiB,kCAAmC,CAAC;AAClE,eAAO,MAAM,8BAA8B,cAAc,CAAC;AAC1D,eAAO,MAAM,kCAAkC,IAAI,CAAC;AACpD,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAChD,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,eAAe,EAAE,MAAM,eAAe,EAAE,CAAC;IACzC,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACrD,mBAAmB,EAAE,CAAC,eAAe,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E,CAAC;AAEF,qBAAa,gBAAgB;;gBAUf,EACV,eAAe,EACf,mBAAmB,EACnB,oBAAoB,GACrB,EAAE,uBAAuB;CAsF3B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,uBAAuB,EAAE,eAAe,EACxC,kBAAkB,EAAE,eAAe;;;EA2CpC;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,sBAAsB,EAAE,cAAc,EACtC,iBAAiB,EAAE,cAAc,GAChC,OAAO,CAmDT"}
|
|
@@ -1,16 +1,98 @@
|
|
|
1
|
-
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
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");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
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");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _ResimulateHelper_instances, _ResimulateHelper_timeoutIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_start, _ResimulateHelper_queueUpdate, _ResimulateHelper_stop, _ResimulateHelper_removeListener;
|
|
13
|
+
import { remove0x } from "@metamask/utils";
|
|
2
14
|
import { BN } from "bn.js";
|
|
3
15
|
import $lodash from "lodash";
|
|
4
16
|
const { isEqual } = $lodash;
|
|
5
|
-
import { projectLogger } from "../logger.mjs";
|
|
6
|
-
import {
|
|
7
|
-
|
|
17
|
+
import { createModuleLogger, projectLogger } from "../logger.mjs";
|
|
18
|
+
import { TransactionStatus } from "../types.mjs";
|
|
19
|
+
import { getPercentageChange } from "../utils/utils.mjs";
|
|
20
|
+
const log = createModuleLogger(projectLogger, 'resimulate-helper');
|
|
8
21
|
export const RESIMULATE_PARAMS = ['to', 'value', 'data'];
|
|
9
22
|
export const BLOCKAID_RESULT_TYPE_MALICIOUS = 'Malicious';
|
|
10
23
|
export const VALUE_COMPARISON_PERCENT_THRESHOLD = 5;
|
|
11
24
|
export const BLOCK_TIME_ADDITIONAL_SECONDS = 60;
|
|
25
|
+
export const RESIMULATE_INTERVAL_MS = 3000;
|
|
26
|
+
export class ResimulateHelper {
|
|
27
|
+
constructor({ getTransactions, simulateTransaction, onTransactionsUpdate, }) {
|
|
28
|
+
_ResimulateHelper_instances.add(this);
|
|
29
|
+
// Map of transactionId <=> timeoutId
|
|
30
|
+
_ResimulateHelper_timeoutIds.set(this, new Map());
|
|
31
|
+
_ResimulateHelper_getTransactions.set(this, void 0);
|
|
32
|
+
_ResimulateHelper_simulateTransaction.set(this, void 0);
|
|
33
|
+
__classPrivateFieldSet(this, _ResimulateHelper_getTransactions, getTransactions, "f");
|
|
34
|
+
__classPrivateFieldSet(this, _ResimulateHelper_simulateTransaction, simulateTransaction, "f");
|
|
35
|
+
onTransactionsUpdate(__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_onTransactionsUpdate).bind(this));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
_ResimulateHelper_timeoutIds = new WeakMap(), _ResimulateHelper_getTransactions = new WeakMap(), _ResimulateHelper_simulateTransaction = new WeakMap(), _ResimulateHelper_instances = new WeakSet(), _ResimulateHelper_onTransactionsUpdate = function _ResimulateHelper_onTransactionsUpdate() {
|
|
39
|
+
const unapprovedTransactions = __classPrivateFieldGet(this, _ResimulateHelper_getTransactions, "f").call(this).filter((tx) => tx.status === TransactionStatus.unapproved);
|
|
40
|
+
const unapprovedTransactionIds = new Set(unapprovedTransactions.map((tx) => tx.id));
|
|
41
|
+
// Combine unapproved transaction IDs and currently active resimulations
|
|
42
|
+
const allTransactionIds = new Set([
|
|
43
|
+
...unapprovedTransactionIds,
|
|
44
|
+
...__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").keys(),
|
|
45
|
+
]);
|
|
46
|
+
allTransactionIds.forEach((transactionId) => {
|
|
47
|
+
const transactionMeta = unapprovedTransactions.find((tx) => tx.id === transactionId);
|
|
48
|
+
if (transactionMeta?.isActive) {
|
|
49
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_start).call(this, transactionMeta);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_stop).call(this, transactionId);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}, _ResimulateHelper_start = function _ResimulateHelper_start(transactionMeta) {
|
|
56
|
+
const { id: transactionId } = transactionMeta;
|
|
57
|
+
if (__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const listener = () => {
|
|
61
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
62
|
+
__classPrivateFieldGet(this, _ResimulateHelper_simulateTransaction, "f").call(this, transactionMeta)
|
|
63
|
+
.catch((error) => {
|
|
64
|
+
/* istanbul ignore next */
|
|
65
|
+
log('Error during transaction resimulation', error);
|
|
66
|
+
})
|
|
67
|
+
.finally(() => {
|
|
68
|
+
// Schedule the next execution
|
|
69
|
+
if (__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
70
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_queueUpdate).call(this, transactionId, listener);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
// Start the first execution
|
|
75
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_queueUpdate).call(this, transactionId, listener);
|
|
76
|
+
log(`Started resimulating transaction ${transactionId} every ${RESIMULATE_INTERVAL_MS} milliseconds`);
|
|
77
|
+
}, _ResimulateHelper_queueUpdate = function _ResimulateHelper_queueUpdate(transactionId, listener) {
|
|
78
|
+
const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);
|
|
79
|
+
__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").set(transactionId, timeoutId);
|
|
80
|
+
}, _ResimulateHelper_stop = function _ResimulateHelper_stop(transactionId) {
|
|
81
|
+
if (!__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_removeListener).call(this, transactionId);
|
|
85
|
+
log(`Stopped resimulating transaction ${transactionId} every ${RESIMULATE_INTERVAL_MS} milliseconds`);
|
|
86
|
+
}, _ResimulateHelper_removeListener = function _ResimulateHelper_removeListener(id) {
|
|
87
|
+
const timeoutId = __classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").get(id);
|
|
88
|
+
if (timeoutId) {
|
|
89
|
+
clearTimeout(timeoutId);
|
|
90
|
+
__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").delete(id);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
12
93
|
/**
|
|
13
94
|
* Determine if a transaction should be resimulated.
|
|
95
|
+
*
|
|
14
96
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
15
97
|
* @param newTransactionMeta - The new transaction metadata.
|
|
16
98
|
* @returns Whether the transaction should be resimulated.
|
|
@@ -42,6 +124,7 @@ export function shouldResimulate(originalTransactionMeta, newTransactionMeta) {
|
|
|
42
124
|
}
|
|
43
125
|
/**
|
|
44
126
|
* Determine if the simulation data has changed.
|
|
127
|
+
*
|
|
45
128
|
* @param originalSimulationData - The original simulation data.
|
|
46
129
|
* @param newSimulationData - The new simulation data.
|
|
47
130
|
* @returns Whether the simulation data has changed.
|
|
@@ -80,6 +163,7 @@ export function hasSimulationDataChanged(originalSimulationData, newSimulationDa
|
|
|
80
163
|
}
|
|
81
164
|
/**
|
|
82
165
|
* Determine if the transaction parameters have been updated.
|
|
166
|
+
*
|
|
83
167
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
84
168
|
* @param newTransactionMeta - The new transaction metadata.
|
|
85
169
|
* @returns Whether the transaction parameters have been updated.
|
|
@@ -102,6 +186,7 @@ function isParametersUpdated(originalTransactionMeta, newTransactionMeta) {
|
|
|
102
186
|
}
|
|
103
187
|
/**
|
|
104
188
|
* Determine if a transaction has a new security alert.
|
|
189
|
+
*
|
|
105
190
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
106
191
|
* @param newTransactionMeta - The new transaction metadata.
|
|
107
192
|
* @returns Whether the transaction has a new security alert.
|
|
@@ -121,6 +206,7 @@ function hasNewSecurityAlert(originalTransactionMeta, newTransactionMeta) {
|
|
|
121
206
|
}
|
|
122
207
|
/**
|
|
123
208
|
* Determine if a transaction has a value and simulation native balance mismatch.
|
|
209
|
+
*
|
|
124
210
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
125
211
|
* @param newTransactionMeta - The new transaction metadata.
|
|
126
212
|
* @returns Whether the transaction has a value and simulation native balance mismatch.
|
|
@@ -138,6 +224,7 @@ function hasValueAndNativeBalanceMismatch(originalTransactionMeta, newTransactio
|
|
|
138
224
|
}
|
|
139
225
|
/**
|
|
140
226
|
* Determine if a balance change has been updated.
|
|
227
|
+
*
|
|
141
228
|
* @param originalBalanceChange - The original balance change.
|
|
142
229
|
* @param newBalanceChange - The new balance change.
|
|
143
230
|
* @returns Whether the balance change has been updated.
|
|
@@ -147,6 +234,7 @@ function isBalanceChangeUpdated(originalBalanceChange, newBalanceChange) {
|
|
|
147
234
|
}
|
|
148
235
|
/**
|
|
149
236
|
* Determine if the percentage change between two values is within a threshold.
|
|
237
|
+
*
|
|
150
238
|
* @param originalValue - The original value.
|
|
151
239
|
* @param newValue - The new value.
|
|
152
240
|
* @param originalNegative - Whether the original value is negative.
|
|
@@ -165,4 +253,4 @@ function percentageChangeWithinThreshold(originalValue, newValue, originalNegati
|
|
|
165
253
|
return (getPercentageChange(originalValueBN, newValueBN) <=
|
|
166
254
|
VALUE_COMPARISON_PERCENT_THRESHOLD);
|
|
167
255
|
}
|
|
168
|
-
//# sourceMappingURL=
|
|
256
|
+
//# sourceMappingURL=ResimulateHelper.mjs.map
|