@metamask-previews/transaction-controller 44.0.0-preview-442894ce → 44.0.0-preview-43593c4e
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 +7 -0
- package/dist/TransactionController.cjs +38 -3
- package/dist/TransactionController.cjs.map +1 -1
- package/dist/TransactionController.d.cts +7 -0
- package/dist/TransactionController.d.cts.map +1 -1
- package/dist/TransactionController.d.mts +7 -0
- package/dist/TransactionController.d.mts.map +1 -1
- package/dist/TransactionController.mjs +36 -1
- package/dist/TransactionController.mjs.map +1 -1
- package/dist/{utils/resimulate.cjs → helpers/ResimulateHelper.cjs} +96 -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} +96 -5
- package/dist/helpers/ResimulateHelper.mjs.map +1 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +4 -0
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +4 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +2 -2
- 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
|
@@ -1,18 +1,104 @@
|
|
|
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_intervalIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_start, _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 <=> intervalId
|
|
32
|
+
_ResimulateHelper_intervalIds.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_intervalIds = 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_intervalIds, "f").keys(),
|
|
48
|
+
]);
|
|
49
|
+
allTransactionIds.forEach((transactionId) => {
|
|
50
|
+
const transactionMeta = unapprovedTransactions.find((tx) => tx.id === transactionId);
|
|
51
|
+
if (transactionMeta && 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, {
|
|
56
|
+
id: transactionId,
|
|
57
|
+
isActive: false,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}, _ResimulateHelper_start = function _ResimulateHelper_start(transactionMeta) {
|
|
62
|
+
const { id: transactionId } = transactionMeta;
|
|
63
|
+
if (!transactionMeta.isActive || __classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").has(transactionId)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const listener = () => {
|
|
67
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
68
|
+
__classPrivateFieldGet(this, _ResimulateHelper_simulateTransaction, "f").call(this, transactionMeta)
|
|
69
|
+
.catch((error) => {
|
|
70
|
+
/* istanbul ignore next */
|
|
71
|
+
log('Error during transaction resimulation', error);
|
|
72
|
+
})
|
|
73
|
+
.finally(() => {
|
|
74
|
+
// Schedule the next execution
|
|
75
|
+
if (__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").has(transactionId)) {
|
|
76
|
+
const timeoutId = setTimeout(listener, exports.RESIMULATE_INTERVAL_MS);
|
|
77
|
+
__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").set(transactionId, timeoutId);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
// Start the first execution
|
|
82
|
+
const timeoutId = setTimeout(listener, exports.RESIMULATE_INTERVAL_MS);
|
|
83
|
+
__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").set(transactionId, timeoutId);
|
|
84
|
+
log(`Started resimulating transaction ${transactionId} every ${exports.RESIMULATE_INTERVAL_MS} milliseconds`);
|
|
85
|
+
}, _ResimulateHelper_stop = function _ResimulateHelper_stop(transactionMeta) {
|
|
86
|
+
const { id: transactionId } = transactionMeta;
|
|
87
|
+
if (transactionMeta.isActive || !__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").has(transactionId)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_removeListener).call(this, transactionId);
|
|
91
|
+
log(`Stopped resimulating transaction ${transactionId} every 3 seconds`);
|
|
92
|
+
}, _ResimulateHelper_removeListener = function _ResimulateHelper_removeListener(id) {
|
|
93
|
+
const intervalId = __classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").get(id);
|
|
94
|
+
if (intervalId) {
|
|
95
|
+
clearInterval(intervalId);
|
|
96
|
+
__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").delete(id);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
14
99
|
/**
|
|
15
100
|
* Determine if a transaction should be resimulated.
|
|
101
|
+
*
|
|
16
102
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
17
103
|
* @param newTransactionMeta - The new transaction metadata.
|
|
18
104
|
* @returns Whether the transaction should be resimulated.
|
|
@@ -45,6 +131,7 @@ function shouldResimulate(originalTransactionMeta, newTransactionMeta) {
|
|
|
45
131
|
exports.shouldResimulate = shouldResimulate;
|
|
46
132
|
/**
|
|
47
133
|
* Determine if the simulation data has changed.
|
|
134
|
+
*
|
|
48
135
|
* @param originalSimulationData - The original simulation data.
|
|
49
136
|
* @param newSimulationData - The new simulation data.
|
|
50
137
|
* @returns Whether the simulation data has changed.
|
|
@@ -84,6 +171,7 @@ function hasSimulationDataChanged(originalSimulationData, newSimulationData) {
|
|
|
84
171
|
exports.hasSimulationDataChanged = hasSimulationDataChanged;
|
|
85
172
|
/**
|
|
86
173
|
* Determine if the transaction parameters have been updated.
|
|
174
|
+
*
|
|
87
175
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
88
176
|
* @param newTransactionMeta - The new transaction metadata.
|
|
89
177
|
* @returns Whether the transaction parameters have been updated.
|
|
@@ -106,6 +194,7 @@ function isParametersUpdated(originalTransactionMeta, newTransactionMeta) {
|
|
|
106
194
|
}
|
|
107
195
|
/**
|
|
108
196
|
* Determine if a transaction has a new security alert.
|
|
197
|
+
*
|
|
109
198
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
110
199
|
* @param newTransactionMeta - The new transaction metadata.
|
|
111
200
|
* @returns Whether the transaction has a new security alert.
|
|
@@ -125,6 +214,7 @@ function hasNewSecurityAlert(originalTransactionMeta, newTransactionMeta) {
|
|
|
125
214
|
}
|
|
126
215
|
/**
|
|
127
216
|
* Determine if a transaction has a value and simulation native balance mismatch.
|
|
217
|
+
*
|
|
128
218
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
129
219
|
* @param newTransactionMeta - The new transaction metadata.
|
|
130
220
|
* @returns Whether the transaction has a value and simulation native balance mismatch.
|
|
@@ -142,6 +232,7 @@ function hasValueAndNativeBalanceMismatch(originalTransactionMeta, newTransactio
|
|
|
142
232
|
}
|
|
143
233
|
/**
|
|
144
234
|
* Determine if a balance change has been updated.
|
|
235
|
+
*
|
|
145
236
|
* @param originalBalanceChange - The original balance change.
|
|
146
237
|
* @param newBalanceChange - The new balance change.
|
|
147
238
|
* @returns Whether the balance change has been updated.
|
|
@@ -151,6 +242,7 @@ function isBalanceChangeUpdated(originalBalanceChange, newBalanceChange) {
|
|
|
151
242
|
}
|
|
152
243
|
/**
|
|
153
244
|
* Determine if the percentage change between two values is within a threshold.
|
|
245
|
+
*
|
|
154
246
|
* @param originalValue - The original value.
|
|
155
247
|
* @param newValue - The new value.
|
|
156
248
|
* @param originalNegative - Whether the original value is negative.
|
|
@@ -169,4 +261,4 @@ function percentageChangeWithinThreshold(originalValue, newValue, originalNegati
|
|
|
169
261
|
return ((0, utils_2.getPercentageChange)(originalValueBN, newValueBN) <=
|
|
170
262
|
exports.VALUE_COMPARISON_PERCENT_THRESHOLD);
|
|
171
263
|
}
|
|
172
|
-
//# sourceMappingURL=
|
|
264
|
+
//# 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 <=> intervalId\n readonly #intervalIds: 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.#intervalIds.keys(),\n ]);\n\n allTransactionIds.forEach((transactionId) => {\n const transactionMeta = unapprovedTransactions.find(\n (tx) => tx.id === transactionId,\n );\n\n if (transactionMeta && transactionMeta.isActive) {\n this.#start(transactionMeta);\n } else {\n this.#stop({\n id: transactionId,\n isActive: false,\n } as unknown as TransactionMeta);\n }\n });\n }\n\n #start(transactionMeta: TransactionMeta) {\n const { id: transactionId } = transactionMeta;\n if (!transactionMeta.isActive || this.#intervalIds.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.#intervalIds.has(transactionId)) {\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#intervalIds.set(transactionId, timeoutId);\n }\n });\n };\n\n // Start the first execution\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#intervalIds.set(transactionId, timeoutId);\n log(\n `Started resimulating transaction ${transactionId} every ${RESIMULATE_INTERVAL_MS} milliseconds`,\n );\n }\n\n #stop(transactionMeta: TransactionMeta) {\n const { id: transactionId } = transactionMeta;\n if (transactionMeta.isActive || !this.#intervalIds.has(transactionId)) {\n return;\n }\n\n this.#removeListener(transactionId);\n log(`Stopped resimulating transaction ${transactionId} every 3 seconds`);\n }\n\n #removeListener(id: string) {\n const intervalId = this.#intervalIds.get(id);\n if (intervalId) {\n clearInterval(intervalId);\n this.#intervalIds.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;CAqF3B;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;CAqF3B;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,101 @@
|
|
|
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_intervalIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_start, _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 <=> intervalId
|
|
30
|
+
_ResimulateHelper_intervalIds.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_intervalIds = 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_intervalIds, "f").keys(),
|
|
45
|
+
]);
|
|
46
|
+
allTransactionIds.forEach((transactionId) => {
|
|
47
|
+
const transactionMeta = unapprovedTransactions.find((tx) => tx.id === transactionId);
|
|
48
|
+
if (transactionMeta && 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, {
|
|
53
|
+
id: transactionId,
|
|
54
|
+
isActive: false,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}, _ResimulateHelper_start = function _ResimulateHelper_start(transactionMeta) {
|
|
59
|
+
const { id: transactionId } = transactionMeta;
|
|
60
|
+
if (!transactionMeta.isActive || __classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "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_intervalIds, "f").has(transactionId)) {
|
|
73
|
+
const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);
|
|
74
|
+
__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").set(transactionId, timeoutId);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
// Start the first execution
|
|
79
|
+
const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);
|
|
80
|
+
__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").set(transactionId, timeoutId);
|
|
81
|
+
log(`Started resimulating transaction ${transactionId} every ${RESIMULATE_INTERVAL_MS} milliseconds`);
|
|
82
|
+
}, _ResimulateHelper_stop = function _ResimulateHelper_stop(transactionMeta) {
|
|
83
|
+
const { id: transactionId } = transactionMeta;
|
|
84
|
+
if (transactionMeta.isActive || !__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").has(transactionId)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_removeListener).call(this, transactionId);
|
|
88
|
+
log(`Stopped resimulating transaction ${transactionId} every 3 seconds`);
|
|
89
|
+
}, _ResimulateHelper_removeListener = function _ResimulateHelper_removeListener(id) {
|
|
90
|
+
const intervalId = __classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").get(id);
|
|
91
|
+
if (intervalId) {
|
|
92
|
+
clearInterval(intervalId);
|
|
93
|
+
__classPrivateFieldGet(this, _ResimulateHelper_intervalIds, "f").delete(id);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
12
96
|
/**
|
|
13
97
|
* Determine if a transaction should be resimulated.
|
|
98
|
+
*
|
|
14
99
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
15
100
|
* @param newTransactionMeta - The new transaction metadata.
|
|
16
101
|
* @returns Whether the transaction should be resimulated.
|
|
@@ -42,6 +127,7 @@ export function shouldResimulate(originalTransactionMeta, newTransactionMeta) {
|
|
|
42
127
|
}
|
|
43
128
|
/**
|
|
44
129
|
* Determine if the simulation data has changed.
|
|
130
|
+
*
|
|
45
131
|
* @param originalSimulationData - The original simulation data.
|
|
46
132
|
* @param newSimulationData - The new simulation data.
|
|
47
133
|
* @returns Whether the simulation data has changed.
|
|
@@ -80,6 +166,7 @@ export function hasSimulationDataChanged(originalSimulationData, newSimulationDa
|
|
|
80
166
|
}
|
|
81
167
|
/**
|
|
82
168
|
* Determine if the transaction parameters have been updated.
|
|
169
|
+
*
|
|
83
170
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
84
171
|
* @param newTransactionMeta - The new transaction metadata.
|
|
85
172
|
* @returns Whether the transaction parameters have been updated.
|
|
@@ -102,6 +189,7 @@ function isParametersUpdated(originalTransactionMeta, newTransactionMeta) {
|
|
|
102
189
|
}
|
|
103
190
|
/**
|
|
104
191
|
* Determine if a transaction has a new security alert.
|
|
192
|
+
*
|
|
105
193
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
106
194
|
* @param newTransactionMeta - The new transaction metadata.
|
|
107
195
|
* @returns Whether the transaction has a new security alert.
|
|
@@ -121,6 +209,7 @@ function hasNewSecurityAlert(originalTransactionMeta, newTransactionMeta) {
|
|
|
121
209
|
}
|
|
122
210
|
/**
|
|
123
211
|
* Determine if a transaction has a value and simulation native balance mismatch.
|
|
212
|
+
*
|
|
124
213
|
* @param originalTransactionMeta - The original transaction metadata.
|
|
125
214
|
* @param newTransactionMeta - The new transaction metadata.
|
|
126
215
|
* @returns Whether the transaction has a value and simulation native balance mismatch.
|
|
@@ -138,6 +227,7 @@ function hasValueAndNativeBalanceMismatch(originalTransactionMeta, newTransactio
|
|
|
138
227
|
}
|
|
139
228
|
/**
|
|
140
229
|
* Determine if a balance change has been updated.
|
|
230
|
+
*
|
|
141
231
|
* @param originalBalanceChange - The original balance change.
|
|
142
232
|
* @param newBalanceChange - The new balance change.
|
|
143
233
|
* @returns Whether the balance change has been updated.
|
|
@@ -147,6 +237,7 @@ function isBalanceChangeUpdated(originalBalanceChange, newBalanceChange) {
|
|
|
147
237
|
}
|
|
148
238
|
/**
|
|
149
239
|
* Determine if the percentage change between two values is within a threshold.
|
|
240
|
+
*
|
|
150
241
|
* @param originalValue - The original value.
|
|
151
242
|
* @param newValue - The new value.
|
|
152
243
|
* @param originalNegative - Whether the original value is negative.
|
|
@@ -165,4 +256,4 @@ function percentageChangeWithinThreshold(originalValue, newValue, originalNegati
|
|
|
165
256
|
return (getPercentageChange(originalValueBN, newValueBN) <=
|
|
166
257
|
VALUE_COMPARISON_PERCENT_THRESHOLD);
|
|
167
258
|
}
|
|
168
|
-
//# sourceMappingURL=
|
|
259
|
+
//# sourceMappingURL=ResimulateHelper.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResimulateHelper.mjs","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 <=> intervalId\n readonly #intervalIds: 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.#intervalIds.keys(),\n ]);\n\n allTransactionIds.forEach((transactionId) => {\n const transactionMeta = unapprovedTransactions.find(\n (tx) => tx.id === transactionId,\n );\n\n if (transactionMeta && transactionMeta.isActive) {\n this.#start(transactionMeta);\n } else {\n this.#stop({\n id: transactionId,\n isActive: false,\n } as unknown as TransactionMeta);\n }\n });\n }\n\n #start(transactionMeta: TransactionMeta) {\n const { id: transactionId } = transactionMeta;\n if (!transactionMeta.isActive || this.#intervalIds.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.#intervalIds.has(transactionId)) {\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#intervalIds.set(transactionId, timeoutId);\n }\n });\n };\n\n // Start the first execution\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#intervalIds.set(transactionId, timeoutId);\n log(\n `Started resimulating transaction ${transactionId} every ${RESIMULATE_INTERVAL_MS} milliseconds`,\n );\n }\n\n #stop(transactionMeta: TransactionMeta) {\n const { id: transactionId } = transactionMeta;\n if (transactionMeta.isActive || !this.#intervalIds.has(transactionId)) {\n return;\n }\n\n this.#removeListener(transactionId);\n log(`Stopped resimulating transaction ${transactionId} every 3 seconds`);\n }\n\n #removeListener(id: string) {\n const intervalId = this.#intervalIds.get(id);\n if (intervalId) {\n clearInterval(intervalId);\n this.#intervalIds.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"]}
|