@metamask-previews/transaction-controller 68.2.0-preview-7d3094360 → 68.2.0-preview-d7951629b
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 +4 -0
- package/dist/helpers/ResimulateHelper.cjs +18 -10
- package/dist/helpers/ResimulateHelper.cjs.map +1 -1
- package/dist/helpers/ResimulateHelper.d.cts.map +1 -1
- package/dist/helpers/ResimulateHelper.d.mts.map +1 -1
- package/dist/helpers/ResimulateHelper.mjs +18 -10
- package/dist/helpers/ResimulateHelper.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Resimulate the latest transaction data instead of stale data captured when resimulation started, fixing flickering simulation results after a transaction is updated ([#9287](https://github.com/MetaMask/core/pull/9287))
|
|
13
|
+
|
|
10
14
|
## [68.2.0]
|
|
11
15
|
|
|
12
16
|
### Added
|
|
@@ -10,7 +10,7 @@ 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 _ResimulateHelper_instances, _ResimulateHelper_timeoutIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_start, _ResimulateHelper_queueUpdate, _ResimulateHelper_stop, _ResimulateHelper_removeListener;
|
|
13
|
+
var _ResimulateHelper_instances, _ResimulateHelper_timeoutIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_getResimulatableTransactions, _ResimulateHelper_start, _ResimulateHelper_queueUpdate, _ResimulateHelper_stop, _ResimulateHelper_removeListener;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
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;
|
|
16
16
|
const utils_1 = require("@metamask/utils");
|
|
@@ -39,28 +39,36 @@ class ResimulateHelper {
|
|
|
39
39
|
}
|
|
40
40
|
exports.ResimulateHelper = ResimulateHelper;
|
|
41
41
|
_ResimulateHelper_timeoutIds = new WeakMap(), _ResimulateHelper_getTransactions = new WeakMap(), _ResimulateHelper_simulateTransaction = new WeakMap(), _ResimulateHelper_instances = new WeakSet(), _ResimulateHelper_onTransactionsUpdate = function _ResimulateHelper_onTransactionsUpdate() {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
// Combine unapproved transaction IDs and currently active resimulations
|
|
42
|
+
const resimulatableTransactionIds = new Set(__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_getResimulatableTransactions).call(this).map((tx) => tx.id));
|
|
43
|
+
// Combine resimulatable transaction IDs and currently active resimulations
|
|
45
44
|
const allTransactionIds = new Set([
|
|
46
|
-
...
|
|
45
|
+
...resimulatableTransactionIds,
|
|
47
46
|
...__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").keys(),
|
|
48
47
|
]);
|
|
49
48
|
allTransactionIds.forEach((transactionId) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_start).call(this, transactionMeta);
|
|
49
|
+
if (resimulatableTransactionIds.has(transactionId)) {
|
|
50
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_start).call(this, transactionId);
|
|
53
51
|
}
|
|
54
52
|
else {
|
|
55
53
|
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_stop).call(this, transactionId);
|
|
56
54
|
}
|
|
57
55
|
});
|
|
58
|
-
},
|
|
59
|
-
|
|
56
|
+
}, _ResimulateHelper_getResimulatableTransactions = function _ResimulateHelper_getResimulatableTransactions() {
|
|
57
|
+
return __classPrivateFieldGet(this, _ResimulateHelper_getTransactions, "f").call(this).filter((tx) => tx.status === types_1.TransactionStatus.unapproved && tx.isActive);
|
|
58
|
+
}, _ResimulateHelper_start = function _ResimulateHelper_start(transactionId) {
|
|
60
59
|
if (__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
61
60
|
return;
|
|
62
61
|
}
|
|
63
62
|
const listener = () => {
|
|
63
|
+
// Read the latest transaction on each tick rather than capturing it in
|
|
64
|
+
// the closure. Otherwise an update to the transaction (e.g. editing a
|
|
65
|
+
// batch approval amount) would keep resimulating the stale data, as
|
|
66
|
+
// `#start` returns early when a timer already exists for the id.
|
|
67
|
+
const transactionMeta = __classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_getResimulatableTransactions).call(this).find((tx) => tx.id === transactionId);
|
|
68
|
+
if (!transactionMeta) {
|
|
69
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_stop).call(this, transactionId);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
64
72
|
__classPrivateFieldGet(this, _ResimulateHelper_simulateTransaction, "f").call(this, transactionMeta)
|
|
65
73
|
.catch((error) => {
|
|
66
74
|
/* istanbul ignore next */
|
|
@@ -1 +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(): void {\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): void {\n const { id: transactionId } = transactionMeta;\n if (this.#timeoutIds.has(transactionId)) {\n return;\n }\n\n const listener = (): void => {\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): void {\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#timeoutIds.set(transactionId, timeoutId);\n }\n\n #stop(transactionId: string): void {\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): void {\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): ResimulateResponse {\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"]}
|
|
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(): void {\n const resimulatableTransactionIds = new Set(\n this.#getResimulatableTransactions().map((tx) => tx.id),\n );\n\n // Combine resimulatable transaction IDs and currently active resimulations\n const allTransactionIds = new Set([\n ...resimulatableTransactionIds,\n ...this.#timeoutIds.keys(),\n ]);\n\n allTransactionIds.forEach((transactionId) => {\n if (resimulatableTransactionIds.has(transactionId)) {\n this.#start(transactionId);\n } else {\n this.#stop(transactionId);\n }\n });\n }\n\n #getResimulatableTransactions(): TransactionMeta[] {\n return this.#getTransactions().filter(\n (tx) => tx.status === TransactionStatus.unapproved && tx.isActive,\n );\n }\n\n #start(transactionId: string): void {\n if (this.#timeoutIds.has(transactionId)) {\n return;\n }\n\n const listener = (): void => {\n // Read the latest transaction on each tick rather than capturing it in\n // the closure. Otherwise an update to the transaction (e.g. editing a\n // batch approval amount) would keep resimulating the stale data, as\n // `#start` returns early when a timer already exists for the id.\n const transactionMeta = this.#getResimulatableTransactions().find(\n (tx) => tx.id === transactionId,\n );\n\n if (!transactionMeta) {\n this.#stop(transactionId);\n return;\n }\n\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): void {\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#timeoutIds.set(transactionId, timeoutId);\n }\n\n #stop(transactionId: string): void {\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): void {\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): ResimulateResponse {\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"]}
|
|
@@ -1 +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;
|
|
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;CA+F3B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,uBAAuB,EAAE,eAAe,EACxC,kBAAkB,EAAE,eAAe,GAClC,kBAAkB,CA0CpB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,sBAAsB,EAAE,cAAc,EACtC,iBAAiB,EAAE,cAAc,GAChC,OAAO,CAmDT"}
|
|
@@ -1 +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;
|
|
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;CA+F3B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,uBAAuB,EAAE,eAAe,EACxC,kBAAkB,EAAE,eAAe,GAClC,kBAAkB,CA0CpB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,sBAAsB,EAAE,cAAc,EACtC,iBAAiB,EAAE,cAAc,GAChC,OAAO,CAmDT"}
|
|
@@ -9,7 +9,7 @@ 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 _ResimulateHelper_instances, _ResimulateHelper_timeoutIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_start, _ResimulateHelper_queueUpdate, _ResimulateHelper_stop, _ResimulateHelper_removeListener;
|
|
12
|
+
var _ResimulateHelper_instances, _ResimulateHelper_timeoutIds, _ResimulateHelper_getTransactions, _ResimulateHelper_simulateTransaction, _ResimulateHelper_onTransactionsUpdate, _ResimulateHelper_getResimulatableTransactions, _ResimulateHelper_start, _ResimulateHelper_queueUpdate, _ResimulateHelper_stop, _ResimulateHelper_removeListener;
|
|
13
13
|
import { remove0x } from "@metamask/utils";
|
|
14
14
|
import { BN } from "bn.js";
|
|
15
15
|
import $lodash from "lodash";
|
|
@@ -36,28 +36,36 @@ export class ResimulateHelper {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
_ResimulateHelper_timeoutIds = new WeakMap(), _ResimulateHelper_getTransactions = new WeakMap(), _ResimulateHelper_simulateTransaction = new WeakMap(), _ResimulateHelper_instances = new WeakSet(), _ResimulateHelper_onTransactionsUpdate = function _ResimulateHelper_onTransactionsUpdate() {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
// Combine unapproved transaction IDs and currently active resimulations
|
|
39
|
+
const resimulatableTransactionIds = new Set(__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_getResimulatableTransactions).call(this).map((tx) => tx.id));
|
|
40
|
+
// Combine resimulatable transaction IDs and currently active resimulations
|
|
42
41
|
const allTransactionIds = new Set([
|
|
43
|
-
...
|
|
42
|
+
...resimulatableTransactionIds,
|
|
44
43
|
...__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").keys(),
|
|
45
44
|
]);
|
|
46
45
|
allTransactionIds.forEach((transactionId) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_start).call(this, transactionMeta);
|
|
46
|
+
if (resimulatableTransactionIds.has(transactionId)) {
|
|
47
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_start).call(this, transactionId);
|
|
50
48
|
}
|
|
51
49
|
else {
|
|
52
50
|
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_stop).call(this, transactionId);
|
|
53
51
|
}
|
|
54
52
|
});
|
|
55
|
-
},
|
|
56
|
-
|
|
53
|
+
}, _ResimulateHelper_getResimulatableTransactions = function _ResimulateHelper_getResimulatableTransactions() {
|
|
54
|
+
return __classPrivateFieldGet(this, _ResimulateHelper_getTransactions, "f").call(this).filter((tx) => tx.status === TransactionStatus.unapproved && tx.isActive);
|
|
55
|
+
}, _ResimulateHelper_start = function _ResimulateHelper_start(transactionId) {
|
|
57
56
|
if (__classPrivateFieldGet(this, _ResimulateHelper_timeoutIds, "f").has(transactionId)) {
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
59
|
const listener = () => {
|
|
60
|
+
// Read the latest transaction on each tick rather than capturing it in
|
|
61
|
+
// the closure. Otherwise an update to the transaction (e.g. editing a
|
|
62
|
+
// batch approval amount) would keep resimulating the stale data, as
|
|
63
|
+
// `#start` returns early when a timer already exists for the id.
|
|
64
|
+
const transactionMeta = __classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_getResimulatableTransactions).call(this).find((tx) => tx.id === transactionId);
|
|
65
|
+
if (!transactionMeta) {
|
|
66
|
+
__classPrivateFieldGet(this, _ResimulateHelper_instances, "m", _ResimulateHelper_stop).call(this, transactionId);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
61
69
|
__classPrivateFieldGet(this, _ResimulateHelper_simulateTransaction, "f").call(this, transactionMeta)
|
|
62
70
|
.catch((error) => {
|
|
63
71
|
/* istanbul ignore next */
|
|
@@ -1 +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 <=> 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(): void {\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): void {\n const { id: transactionId } = transactionMeta;\n if (this.#timeoutIds.has(transactionId)) {\n return;\n }\n\n const listener = (): void => {\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): void {\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#timeoutIds.set(transactionId, timeoutId);\n }\n\n #stop(transactionId: string): void {\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): void {\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): ResimulateResponse {\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"]}
|
|
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 <=> 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(): void {\n const resimulatableTransactionIds = new Set(\n this.#getResimulatableTransactions().map((tx) => tx.id),\n );\n\n // Combine resimulatable transaction IDs and currently active resimulations\n const allTransactionIds = new Set([\n ...resimulatableTransactionIds,\n ...this.#timeoutIds.keys(),\n ]);\n\n allTransactionIds.forEach((transactionId) => {\n if (resimulatableTransactionIds.has(transactionId)) {\n this.#start(transactionId);\n } else {\n this.#stop(transactionId);\n }\n });\n }\n\n #getResimulatableTransactions(): TransactionMeta[] {\n return this.#getTransactions().filter(\n (tx) => tx.status === TransactionStatus.unapproved && tx.isActive,\n );\n }\n\n #start(transactionId: string): void {\n if (this.#timeoutIds.has(transactionId)) {\n return;\n }\n\n const listener = (): void => {\n // Read the latest transaction on each tick rather than capturing it in\n // the closure. Otherwise an update to the transaction (e.g. editing a\n // batch approval amount) would keep resimulating the stale data, as\n // `#start` returns early when a timer already exists for the id.\n const transactionMeta = this.#getResimulatableTransactions().find(\n (tx) => tx.id === transactionId,\n );\n\n if (!transactionMeta) {\n this.#stop(transactionId);\n return;\n }\n\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): void {\n const timeoutId = setTimeout(listener, RESIMULATE_INTERVAL_MS);\n this.#timeoutIds.set(transactionId, timeoutId);\n }\n\n #stop(transactionId: string): void {\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): void {\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): ResimulateResponse {\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/transaction-controller",
|
|
3
|
-
"version": "68.2.0-preview-
|
|
3
|
+
"version": "68.2.0-preview-d7951629b",
|
|
4
4
|
"description": "Stores transactions alongside their periodically updated statuses and manages interactions such as approval and cancellation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|