@metamask-previews/transaction-controller 72.2.1-preview-eefc6963e → 72.2.1-preview-2a7a9a077

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 CHANGED
@@ -12,11 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12
12
  - Bump `@metamask/accounts-controller` from `^40.0.0` to `^40.1.0` ([#10851](https://github.com/MetaMask/core/pull/10851))
13
13
  - Bump `@metamask/core-backend` from `^12.1.0` to `^12.2.0` ([#10857](https://github.com/MetaMask/core/pull/10857))
14
14
 
15
- ### Fixed
16
-
17
- - Exclude the unused gas refund from `nativeBalanceChange` when the simulation credits the sender without debiting the gas cost ([#10614](https://github.com/MetaMask/core/pull/10614))
18
- - On Arc the simulated state diff credits the fee recipient and, when the gas limit exceeds the gas used, refunds the sender's unused gas, but never debits the upfront gas, so a value-0 call was reported as an incoming native balance and a native send under-reported its decrease.
19
-
20
15
  ## [72.2.1]
21
16
 
22
17
  ### Changed
@@ -118,10 +118,6 @@ export async function getBalanceChanges(request) {
118
118
  /**
119
119
  * Extract the native balance change from a simulation response.
120
120
  *
121
- * The simulated gas cost is added back only when the sender was charged it, and
122
- * the unused gas refund is removed only when the simulation created native
123
- * balance without charging the sender; the two adjustments never apply together.
124
- *
125
121
  * @param request - Simulation request.
126
122
  * @param response - Simulation response.
127
123
  * @returns Native balance change or undefined if unchanged.
@@ -140,17 +136,10 @@ function getNativeBalanceChange(request, response) {
140
136
  if (!previousBalance || !newBalance) {
141
137
  return undefined;
142
138
  }
143
- const isBalanceCreated = isNativeBalanceCreated(stateDiff);
144
- const senderGainExcludingValue = getNativeBalanceChangeExcludingValue(txParams, previousBalance, newBalance, request.nestedTransactions);
145
- const gasCost = isGasCostDeductedFromSender(txParams, senderGainExcludingValue, isBalanceCreated)
139
+ const gasCost = isGasCostDeductedFromSender(txParams, previousBalance, newBalance, stateDiff)
146
140
  ? transactionResponse.gasCost
147
141
  : undefined;
148
- const unusedGasRefund = isBalanceCreated
149
- ? getUnusedGasRefund(txParams, transactionResponse)
150
- : new BN(0);
151
- const refund = BN.min(unusedGasRefund, BN.max(senderGainExcludingValue, new BN(0)));
152
- const offset = new BN(String(gasCost ?? 0)).sub(refund);
153
- return getSimulationBalanceChange(previousBalance, newBalance, offset);
142
+ return getSimulationBalanceChange(previousBalance, newBalance, gasCost);
154
143
  }
155
144
  /**
156
145
  * Determine whether the simulated gas cost was deducted from the sender.
@@ -160,25 +149,28 @@ function getNativeBalanceChange(request, response) {
160
149
  *
161
150
  * - The sender is only charged when the simulated transaction specifies a fee
162
151
  * per gas.
163
- * - If the sender lost exactly the transferred value, gas was not charged.
152
+ * - If the sender lost exactly the transaction value, gas was not charged.
164
153
  * - Some chains credit the fee recipient without debiting the sender, which is
165
154
  * detectable because it increases the total native balance.
166
155
  *
167
156
  * @param txParams - Parameters of the simulated transaction.
168
- * @param balanceChangeExcludingValue - Sender native balance change excluding the transferred value.
169
- * @param isBalanceCreated - Whether the simulation increased the total native
170
- * balance.
157
+ * @param previousBalance - Sender native balance before the simulation.
158
+ * @param newBalance - Sender native balance after the simulation.
159
+ * @param stateDiff - Native balances before and after the simulation.
171
160
  * @returns Whether the gas cost was deducted from the sender.
172
161
  */
173
- function isGasCostDeductedFromSender(txParams, balanceChangeExcludingValue, isBalanceCreated) {
162
+ function isGasCostDeductedFromSender(txParams, previousBalance, newBalance, stateDiff) {
174
163
  const feePerGas = (txParams.maxFeePerGas ?? txParams.gasPrice);
175
164
  if (!feePerGas || hexToBN(feePerGas).isZero()) {
176
165
  return false;
177
166
  }
178
- if (balanceChangeExcludingValue.isZero()) {
167
+ const extraLoss = hexToBN(previousBalance)
168
+ .sub(hexToBN(newBalance))
169
+ .sub(hexToBN(txParams.value ?? '0x0'));
170
+ if (extraLoss.isZero()) {
179
171
  return false;
180
172
  }
181
- return !isBalanceCreated;
173
+ return !isNativeBalanceCreated(stateDiff);
182
174
  }
183
175
  /**
184
176
  * Determine whether a state diff increases the total native balance.
@@ -203,31 +195,6 @@ function isNativeBalanceCreated(stateDiff) {
203
195
  }, new BN(0));
204
196
  return totalBalanceChange.gt(new BN(0));
205
197
  }
206
- /**
207
- * Calculate the unused gas refund credited to the sender when the simulation
208
- * reports gas fees without debiting the sender.
209
- *
210
- * @param txParams - Parameters of the simulated transaction.
211
- * @param transactionResponse - Simulation response for the transaction.
212
- * @returns The refund in wei, or zero if it cannot be derived.
213
- */
214
- function getUnusedGasRefund(txParams, transactionResponse) {
215
- const { gasCost, gasUsed } = transactionResponse;
216
- const gasLimit = txParams.gas;
217
- if (!gasLimit || !gasUsed || gasCost === undefined || gasCost === null) {
218
- return new BN(0);
219
- }
220
- const gasUsedBN = hexToBN(gasUsed);
221
- if (gasUsedBN.isZero()) {
222
- return new BN(0);
223
- }
224
- const unusedGas = hexToBN(gasLimit).sub(gasUsedBN);
225
- if (unusedGas.lte(new BN(0))) {
226
- return new BN(0);
227
- }
228
- const price = new BN(String(gasCost)).add(gasUsedBN.shrn(1)).div(gasUsedBN);
229
- return unusedGas.mul(price);
230
- }
231
198
  /**
232
199
  * Extract events from a simulation response.
233
200
  *
@@ -565,8 +532,8 @@ function extractRootRevert(call) {
565
532
  * @param offset - Optional offset to apply to the new balance.
566
533
  * @returns The balance change data or undefined if unchanged.
567
534
  */
568
- function getSimulationBalanceChange(previousBalance, newBalance, offset = new BN(0)) {
569
- const newBalanceBN = hexToBN(newBalance).add(offset);
535
+ function getSimulationBalanceChange(previousBalance, newBalance, offset = 0) {
536
+ const newBalanceBN = hexToBN(newBalance).add(new BN(offset));
570
537
  const previousBalanceBN = hexToBN(previousBalance);
571
538
  const differenceBN = newBalanceBN.sub(previousBalanceBN);
572
539
  const isDecrease = differenceBN.isNeg();
@@ -667,35 +634,9 @@ function getRequiredBalance(request) {
667
634
  const gasLimit = hexToBN(txParams.gas ?? '0x0');
668
635
  const gasPrice = hexToBN(txParams.maxFeePerGas ?? txParams.gasPrice ?? '0x0');
669
636
  const value = hexToBN(txParams.value ?? '0x0');
670
- const nestedValue = getNestedValue(request.nestedTransactions);
671
- return gasLimit.mul(gasPrice).add(value).add(nestedValue);
672
- }
673
- /**
674
- * Sum the native values of nested transactions.
675
- *
676
- * @param nestedTransactions - The nested transactions of a batch.
677
- * @returns The total native value as a BN.
678
- */
679
- function getNestedValue(nestedTransactions) {
680
- return (nestedTransactions ?? [])
637
+ const nestedValue = (request.nestedTransactions ?? [])
681
638
  .map((tx) => hexToBN(tx.value ?? '0x0'))
682
639
  .reduce((acc, val) => acc.add(val), new BN(0));
683
- }
684
- /**
685
- * Calculate the sender's native balance change excluding the value sent by
686
- * the transaction and any nested transactions.
687
- *
688
- * @param txParams - Parameters of the simulated transaction.
689
- * @param previousBalance - Sender native balance before the simulation.
690
- * @param newBalance - Sender native balance after the simulation.
691
- * @param nestedTransactions - Nested transactions of a batch, if any.
692
- * @returns The balance change excluding the transferred value. Positive when
693
- * the sender gained, negative when the sender lost.
694
- */
695
- function getNativeBalanceChangeExcludingValue(txParams, previousBalance, newBalance, nestedTransactions) {
696
- return hexToBN(newBalance)
697
- .sub(hexToBN(previousBalance))
698
- .add(hexToBN(txParams.value ?? '0x0'))
699
- .add(getNestedValue(nestedTransactions));
640
+ return gasLimit.mul(gasPrice).add(value).add(nestedValue);
700
641
  }
701
642
  //# sourceMappingURL=balance-changes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"balance-changes.js","sourceRoot":"","sources":["../../src/utils/balance-changes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Fragment, LogDescription, Result } from '@ethersproject/abi';\nimport { Interface } from '@ethersproject/abi';\nimport { hexToBN, toHex } from '@metamask/controller-utils';\nimport { abiERC20, abiERC721, abiERC1155 } from '@metamask/metamask-eth-abis';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { simulateTransactions } from '../api/simulation-api.js';\nimport type {\n SimulationResponseLog,\n SimulationRequestTransaction,\n SimulationResponse,\n SimulationResponseCallTrace,\n SimulationResponseTransaction,\n SimulationRequest,\n} from '../api/simulation-api.js';\nimport {\n ABI_SIMULATION_ERC20_WRAPPED,\n ABI_SIMULATION_ERC721_LEGACY,\n} from '../constants.js';\nimport {\n SimulationError,\n SimulationInvalidResponseError,\n SimulationRevertedError,\n} from '../errors.js';\nimport { projectLogger } from '../logger.js';\nimport type { TransactionControllerMessenger } from '../TransactionController.js';\nimport type {\n Revert,\n SimulationBalanceChange,\n SimulationData,\n SimulationTokenBalanceChange,\n SimulationToken,\n TransactionParams,\n NestedTransactionMetadata,\n GetSimulationConfig,\n} from '../types.js';\nimport { SimulationTokenStandard } from '../types.js';\nimport { getNativeBalance } from './balance.js';\nimport { decodeRevert } from './revert-reason.js';\n\nexport enum SupportedToken {\n ERC20 = 'erc20',\n ERC721 = 'erc721',\n ERC1155 = 'erc1155',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ERC20_WRAPPED = 'erc20Wrapped',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ERC721_LEGACY = 'erc721Legacy',\n}\n\ntype ABI = Fragment[];\n\nexport type GetBalanceChangesRequest = {\n blockTime?: number;\n chainId: Hex;\n messenger: TransactionControllerMessenger;\n networkClientId: NetworkClientId;\n getSimulationConfig: GetSimulationConfig;\n nestedTransactions?: NestedTransactionMetadata[];\n txParams: TransactionParams;\n};\n\ntype ParsedEvent = {\n contractAddress: Hex;\n tokenStandard: SimulationTokenStandard;\n name: string;\n args: Record<string, Hex | Hex[]>;\n abi: ABI;\n};\n\nconst log = createModuleLogger(projectLogger, 'balance-changes');\n\nconst SUPPORTED_EVENTS = [\n 'Transfer',\n 'TransferSingle',\n 'TransferBatch',\n 'Deposit',\n 'Withdrawal',\n];\n\nconst SUPPORTED_TOKEN_ABIS = {\n [SupportedToken.ERC20]: {\n abi: abiERC20,\n standard: SimulationTokenStandard.erc20,\n },\n [SupportedToken.ERC721]: {\n abi: abiERC721,\n standard: SimulationTokenStandard.erc721,\n },\n [SupportedToken.ERC1155]: {\n abi: abiERC1155,\n standard: SimulationTokenStandard.erc1155,\n },\n [SupportedToken.ERC20_WRAPPED]: {\n abi: ABI_SIMULATION_ERC20_WRAPPED,\n standard: SimulationTokenStandard.erc20,\n },\n [SupportedToken.ERC721_LEGACY]: {\n abi: ABI_SIMULATION_ERC721_LEGACY,\n standard: SimulationTokenStandard.erc721,\n },\n};\n\nconst REVERTED_ERRORS = ['execution reverted', 'insufficient funds for gas'];\n\ntype BalanceTransactionMap = Map<SimulationToken, SimulationRequestTransaction>;\n\n/**\n * Generate simulation data for a transaction.\n *\n * @param request - The transaction to simulate.\n * @param request.chainId - The chain ID of the transaction.\n * @param request.from - The sender of the transaction.\n * @param request.to - The recipient of the transaction.\n * @param request.value - The value of the transaction.\n * @param request.data - The data of the transaction.\n * @param request.getSimulationConfig - Optional transaction simulation parameters.\n * @returns The simulation data.\n */\nexport async function getBalanceChanges(\n request: GetBalanceChangesRequest,\n): Promise<{\n simulationData: SimulationData;\n gasUsed?: Hex;\n simulationRevert?: Revert;\n}> {\n log('Request', request);\n\n let callTraceErrors: string[] | undefined;\n let simulationRevert: Revert | undefined;\n\n try {\n const response = await baseRequest({\n request,\n params: {\n withCallTrace: true,\n withLogs: true,\n },\n });\n\n const transactionResponse = response.transactions?.[0];\n callTraceErrors = extractCallTraceErrors(transactionResponse?.callTrace);\n simulationRevert = extractRootRevert(transactionResponse?.callTrace);\n const transactionError = transactionResponse?.error;\n\n if (transactionError) {\n throw new SimulationError(transactionError);\n }\n\n const nativeBalanceChange = getNativeBalanceChange(request, response);\n const events = getEvents(response);\n\n log('Parsed events', events);\n\n const tokenBalanceChanges = await getTokenBalanceChanges(request, events);\n\n const gasUsed = transactionResponse?.gasUsed;\n const simulationData = {\n callTraceErrors,\n nativeBalanceChange,\n tokenBalanceChanges,\n };\n\n return { simulationData, gasUsed, simulationRevert };\n } catch (error) {\n log('Failed to get balance changes', error, request);\n\n let simulationError = error as SimulationError;\n\n if (\n REVERTED_ERRORS.some((revertErrorMessage) =>\n simulationError.message?.includes(revertErrorMessage),\n )\n ) {\n simulationError = new SimulationRevertedError();\n }\n\n const { code, message } = simulationError;\n\n return {\n simulationData: {\n callTraceErrors,\n tokenBalanceChanges: [],\n error: {\n code,\n message,\n },\n },\n gasUsed: undefined,\n simulationRevert,\n };\n }\n}\n\n/**\n * Extract the native balance change from a simulation response.\n *\n * The simulated gas cost is added back only when the sender was charged it, and\n * the unused gas refund is removed only when the simulation created native\n * balance without charging the sender; the two adjustments never apply together.\n *\n * @param request - Simulation request.\n * @param response - Simulation response.\n * @returns Native balance change or undefined if unchanged.\n */\nfunction getNativeBalanceChange(\n request: GetBalanceChangesRequest,\n response: SimulationResponse,\n): SimulationBalanceChange | undefined {\n const transactionResponse = response.transactions[0];\n\n /* istanbul ignore next */\n if (!transactionResponse) {\n return undefined;\n }\n\n const { txParams } = request;\n const userAddress = txParams.from.toLowerCase() as Hex;\n const { stateDiff } = transactionResponse;\n const previousBalance = stateDiff?.pre?.[userAddress]?.balance;\n const newBalance = stateDiff?.post?.[userAddress]?.balance;\n\n if (!previousBalance || !newBalance) {\n return undefined;\n }\n\n const isBalanceCreated = isNativeBalanceCreated(stateDiff);\n\n const senderGainExcludingValue = getNativeBalanceChangeExcludingValue(\n txParams,\n previousBalance,\n newBalance,\n request.nestedTransactions,\n );\n\n const gasCost = isGasCostDeductedFromSender(\n txParams,\n senderGainExcludingValue,\n isBalanceCreated,\n )\n ? transactionResponse.gasCost\n : undefined;\n\n const unusedGasRefund = isBalanceCreated\n ? getUnusedGasRefund(txParams, transactionResponse)\n : new BN(0);\n\n const refund = BN.min(\n unusedGasRefund,\n BN.max(senderGainExcludingValue, new BN(0)),\n );\n const offset = new BN(String(gasCost ?? 0)).sub(refund);\n\n return getSimulationBalanceChange(previousBalance, newBalance, offset);\n}\n\n/**\n * Determine whether the simulated gas cost was deducted from the sender.\n *\n * The gas cost is reported whether or not the simulation charged it, so it can\n * only be added back to the new balance when the sender actually paid it:\n *\n * - The sender is only charged when the simulated transaction specifies a fee\n * per gas.\n * - If the sender lost exactly the transferred value, gas was not charged.\n * - Some chains credit the fee recipient without debiting the sender, which is\n * detectable because it increases the total native balance.\n *\n * @param txParams - Parameters of the simulated transaction.\n * @param balanceChangeExcludingValue - Sender native balance change excluding the transferred value.\n * @param isBalanceCreated - Whether the simulation increased the total native\n * balance.\n * @returns Whether the gas cost was deducted from the sender.\n */\nfunction isGasCostDeductedFromSender(\n txParams: TransactionParams,\n balanceChangeExcludingValue: BN,\n isBalanceCreated: boolean,\n): boolean {\n const feePerGas = (txParams.maxFeePerGas ?? txParams.gasPrice) as\n | Hex\n | undefined;\n\n if (!feePerGas || hexToBN(feePerGas).isZero()) {\n return false;\n }\n\n if (balanceChangeExcludingValue.isZero()) {\n return false;\n }\n\n return !isBalanceCreated;\n}\n\n/**\n * Determine whether a state diff increases the total native balance.\n *\n * Executing a transaction cannot create native balance, so a positive total\n * means the simulation credited an account without debiting another.\n *\n * @param stateDiff - Native balances before and after the simulation.\n * @returns Whether the total native balance increased.\n */\nfunction isNativeBalanceCreated(\n stateDiff: SimulationResponseTransaction['stateDiff'],\n): boolean {\n const previousState = stateDiff?.pre ?? {};\n const newState = stateDiff?.post ?? {};\n const addresses = new Set([\n ...Object.keys(previousState),\n ...Object.keys(newState),\n ]);\n\n const totalBalanceChange = [...addresses].reduce((total, address) => {\n const previousBalance = previousState[address as Hex]?.balance ?? '0x0';\n const newBalance = newState[address as Hex]?.balance ?? '0x0';\n\n return total.add(hexToBN(newBalance).sub(hexToBN(previousBalance)));\n }, new BN(0));\n\n return totalBalanceChange.gt(new BN(0));\n}\n\n/**\n * Calculate the unused gas refund credited to the sender when the simulation\n * reports gas fees without debiting the sender.\n *\n * @param txParams - Parameters of the simulated transaction.\n * @param transactionResponse - Simulation response for the transaction.\n * @returns The refund in wei, or zero if it cannot be derived.\n */\nfunction getUnusedGasRefund(\n txParams: TransactionParams,\n transactionResponse: SimulationResponseTransaction,\n): BN {\n const { gasCost, gasUsed } = transactionResponse;\n const gasLimit = txParams.gas as Hex | undefined;\n\n if (!gasLimit || !gasUsed || gasCost === undefined || gasCost === null) {\n return new BN(0);\n }\n\n const gasUsedBN = hexToBN(gasUsed);\n\n if (gasUsedBN.isZero()) {\n return new BN(0);\n }\n\n const unusedGas = hexToBN(gasLimit).sub(gasUsedBN);\n\n if (unusedGas.lte(new BN(0))) {\n return new BN(0);\n }\n\n const price = new BN(String(gasCost)).add(gasUsedBN.shrn(1)).div(gasUsedBN);\n\n return unusedGas.mul(price);\n}\n\n/**\n * Extract events from a simulation response.\n *\n * @param response - The simulation response.\n * @returns The parsed events.\n */\nfunction getEvents(response: SimulationResponse): ParsedEvent[] {\n /* istanbul ignore next */\n const logs = extractLogs(response.transactions[0]?.callTrace ?? {});\n\n log('Extracted logs', logs);\n\n const interfaces = getContractInterfaces();\n\n return logs\n .map((currentLog) => {\n const event = parseLog(currentLog, interfaces);\n\n if (!event) {\n log('Failed to parse log', currentLog);\n return;\n }\n\n /* istanbul ignore next */\n const inputs = event.abi.find(\n (eventAbi) => eventAbi.name === event.name,\n )?.inputs;\n\n /* istanbul ignore if */\n if (!inputs) {\n log('Failed to find inputs for event', event);\n return;\n }\n\n if (!SUPPORTED_EVENTS.includes(event.name)) {\n log('Ignoring unsupported event', event.name, event);\n return;\n }\n\n log('Normalizing event args', event.name, event);\n\n const args = normalizeEventArgs(event.args, inputs);\n\n return {\n contractAddress: currentLog.address,\n tokenStandard: event.standard,\n name: event.name,\n args,\n abi: event.abi,\n };\n })\n .filter((parsedEvent) => parsedEvent !== undefined);\n}\n\n/**\n * Normalize event arguments using ABI input definitions.\n *\n * @param args - The raw event arguments.\n * @param abiInputs - The ABI input definitions.\n * @returns The normalized event arguments.\n */\nfunction normalizeEventArgs(\n args: Result,\n abiInputs: { name: string }[],\n): Record<string, Hex | Hex[]> {\n return args.reduce((result, arg, index) => {\n const name = abiInputs[index].name.replace('_', '');\n const value = normalizeEventArgValue(arg);\n\n result[name] = value;\n\n return result;\n }, {});\n}\n\n/**\n * Normalize an event argument value.\n *\n * @param value - The event argument value.\n * @returns The normalized event argument value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction normalizeEventArgValue(value: any): any {\n if (Array.isArray(value)) {\n return value.map(normalizeEventArgValue);\n }\n\n let normalizedValue = value;\n\n normalizedValue = normalizedValue.toHexString?.() ?? normalizedValue;\n normalizedValue = normalizedValue.toLowerCase?.() ?? normalizedValue;\n\n return normalizedValue;\n}\n\n/**\n * Generate token balance changes from parsed events.\n *\n * @param request - The transaction that was simulated.\n * @param events - The parsed events.\n * @returns An array of token balance changes.\n */\nasync function getTokenBalanceChanges(\n request: GetBalanceChangesRequest,\n events: ParsedEvent[],\n): Promise<SimulationTokenBalanceChange[]> {\n const { txParams } = request;\n const from = txParams.from as Hex;\n const balanceTxs = getTokenBalanceTransactions(request, events);\n\n log('Generated balance transactions', [...balanceTxs.after.values()]);\n\n const transactionCount = balanceTxs.before.size + balanceTxs.after.size + 1;\n\n if (transactionCount === 1) {\n return [];\n }\n\n const response = await baseRequest({\n request,\n before: [...balanceTxs.before.values()],\n after: [...balanceTxs.after.values()],\n });\n\n log('Balance simulation response', response);\n\n if (response.transactions.length !== transactionCount) {\n throw new SimulationInvalidResponseError();\n }\n\n let prevBalanceTxIndex = 0;\n return [...balanceTxs.after.keys()]\n .map((token, index) => {\n const previousBalanceCheckSkipped = !balanceTxs.before.get(token);\n const previousBalance = previousBalanceCheckSkipped\n ? '0x0'\n : getAmountFromBalanceTransactionResult(\n from,\n token,\n // eslint-disable-next-line no-plusplus\n response.transactions[prevBalanceTxIndex++],\n );\n\n const newBalance = getAmountFromBalanceTransactionResult(\n from,\n token,\n response.transactions[index + balanceTxs.before.size + 1],\n );\n\n const balanceChange = getSimulationBalanceChange(\n previousBalance,\n newBalance,\n );\n\n if (!balanceChange) {\n return;\n }\n\n return {\n ...token,\n ...balanceChange,\n };\n })\n .filter((change) => change !== undefined);\n}\n\n/**\n * Generate transactions to check token balances.\n *\n * @param request - The transaction that was simulated.\n * @param events - The parsed events.\n * @returns A map of token balance transactions keyed by token.\n */\nfunction getTokenBalanceTransactions(\n request: GetBalanceChangesRequest,\n events: ParsedEvent[],\n): {\n before: BalanceTransactionMap;\n after: BalanceTransactionMap;\n} {\n const tokenKeys = new Set();\n const before = new Map();\n const after = new Map();\n const from = request.txParams.from as Hex;\n\n const userEvents = events.filter((event) =>\n [event.args.from, event.args.to].includes(from),\n );\n\n log('Filtered user events', userEvents);\n\n for (const event of userEvents) {\n const tokenIds = getEventTokenIds(event);\n\n log('Extracted token IDs', tokenIds);\n\n for (const tokenId of tokenIds) {\n const simulationToken: SimulationToken = {\n address: event.contractAddress,\n standard: event.tokenStandard,\n id: tokenId,\n };\n\n const tokenKey = JSON.stringify(simulationToken);\n\n if (tokenKeys.has(tokenKey)) {\n log(\n 'Ignoring additional event with same contract and token ID',\n simulationToken,\n );\n continue;\n }\n\n tokenKeys.add(tokenKey);\n\n const data = getBalanceTransactionData(\n event.tokenStandard,\n from,\n tokenId,\n );\n\n const transaction: SimulationRequestTransaction = {\n from,\n to: event.contractAddress,\n data,\n };\n\n if (skipPriorBalanceCheck(event)) {\n after.set(simulationToken, transaction);\n } else {\n before.set(simulationToken, transaction);\n after.set(simulationToken, transaction);\n }\n }\n }\n\n return { before, after };\n}\n\n/**\n * Check if an event needs to check the previous balance.\n *\n * @param event - The parsed event.\n * @returns True if the prior balance check should be skipped.\n */\nfunction skipPriorBalanceCheck(event: ParsedEvent): boolean {\n // In the case of an NFT mint, we cannot check the NFT owner before the mint\n // as the balance check transaction would revert.\n return (\n event.name === 'Transfer' &&\n event.tokenStandard === SimulationTokenStandard.erc721 &&\n parseInt(event.args.from as string, 16) === 0\n );\n}\n\n/**\n * Extract token IDs from a parsed event.\n *\n * @param event - The parsed event.\n * @returns An array of token IDs.\n */\nfunction getEventTokenIds(event: ParsedEvent): (Hex | undefined)[] {\n if (event.tokenStandard === SimulationTokenStandard.erc721) {\n return [event.args.tokenId as Hex];\n }\n\n if (\n event.tokenStandard === SimulationTokenStandard.erc1155 &&\n event.name === 'TransferSingle'\n ) {\n return [event.args.id as Hex];\n }\n\n if (\n event.tokenStandard === SimulationTokenStandard.erc1155 &&\n event.name === 'TransferBatch'\n ) {\n return event.args.ids as Hex[];\n }\n\n // ERC-20 does not have a token ID so default to undefined.\n return [undefined];\n}\n\n/**\n * Get the interface for a token standard.\n *\n * @param tokenStandard - The token standard.\n * @returns The interface for the token standard.\n */\nfunction getContractInterface(\n tokenStandard: SimulationTokenStandard,\n): Interface {\n switch (tokenStandard) {\n case SimulationTokenStandard.erc721:\n return new Interface(abiERC721);\n case SimulationTokenStandard.erc1155:\n return new Interface(abiERC1155);\n default:\n return new Interface(abiERC20);\n }\n}\n\n/**\n * Extract the value from a balance transaction response using the correct ABI.\n *\n * @param from - The address to check the balance of.\n * @param token - The token to check the balance of.\n * @param response - The balance transaction response.\n * @returns The value of the balance transaction as Hex.\n */\nfunction getAmountFromBalanceTransactionResult(\n from: Hex,\n token: SimulationToken,\n response: SimulationResponseTransaction,\n): Hex {\n const contract = getContractInterface(token.standard);\n\n try {\n if (token.standard === SimulationTokenStandard.erc721) {\n const result = contract.decodeFunctionResult('ownerOf', response.return);\n const owner = result[0];\n return owner.toLowerCase() === from.toLowerCase() ? '0x1' : '0x0';\n }\n\n const result = contract.decodeFunctionResult('balanceOf', response.return);\n return toHex(result[0]);\n } catch (error) {\n log('Failed to decode balance transaction', error, { token, response });\n throw new SimulationError(\n `Failed to decode balance transaction for token ${\n token.address\n }: ${String(error)}`,\n );\n }\n}\n\n/**\n * Generate the balance transaction data for a token.\n *\n * @param tokenStandard - The token standard.\n * @param from - The address to check the balance of.\n * @param tokenId - The token ID to check the balance of.\n * @returns The balance transaction data.\n */\nfunction getBalanceTransactionData(\n tokenStandard: SimulationTokenStandard,\n from: Hex,\n tokenId?: Hex,\n): Hex {\n const contract = getContractInterface(tokenStandard);\n switch (tokenStandard) {\n case SimulationTokenStandard.erc721:\n return contract.encodeFunctionData('ownerOf', [tokenId]) as Hex;\n\n case SimulationTokenStandard.erc1155:\n return contract.encodeFunctionData('balanceOf', [from, tokenId]) as Hex;\n\n default:\n return contract.encodeFunctionData('balanceOf', [from]) as Hex;\n }\n}\n\n/**\n * Parse a raw event log using known ABIs.\n *\n * @param eventLog - The raw event log.\n * @param interfaces - The contract interfaces.\n * @returns The parsed event log or undefined if it could not be parsed.\n */\nfunction parseLog(\n eventLog: SimulationResponseLog,\n interfaces: Map<SupportedToken, Interface>,\n):\n | (LogDescription & { abi: ABI; standard: SimulationTokenStandard })\n | undefined {\n const supportedTokens = Object.values(SupportedToken);\n\n for (const token of supportedTokens) {\n try {\n const contractInterface = interfaces.get(token) as Interface;\n const { abi, standard } = SUPPORTED_TOKEN_ABIS[token];\n\n return {\n ...contractInterface.parseLog(eventLog),\n abi,\n standard,\n };\n } catch {\n continue;\n }\n }\n\n return undefined;\n}\n\n/**\n * Extract all logs from a call trace tree.\n *\n * @param call - The root call trace.\n * @returns An array of logs.\n */\nfunction extractLogs(\n call: SimulationResponseCallTrace,\n): SimulationResponseLog[] {\n /* istanbul ignore next */\n const logs = call.logs ?? [];\n\n /* istanbul ignore next */\n const nestedCalls = call.calls ?? [];\n\n return [\n ...logs,\n ...nestedCalls.map((nestedCall) => extractLogs(nestedCall)).flat(),\n ];\n}\n\n/**\n * Extract all error messages from a call trace tree.\n *\n * @param call - The root call trace.\n * @returns An array of error messages.\n */\nfunction extractCallTraceErrors(call?: SimulationResponseCallTrace): string[] {\n if (!call) {\n return [];\n }\n\n const errors = call.error ? [call.error] : [];\n const nestedCalls = call.calls ?? [];\n const nestedErrors = nestedCalls.flatMap((nestedCall) =>\n extractCallTraceErrors(nestedCall),\n );\n\n return [...errors, ...nestedErrors];\n}\n\n/**\n * Build a `Revert` from the root call trace frame. Reads only the raw\n * `output` hex and decodes it locally; the upstream `error` message string\n * is never parsed. Only the root frame's output is considered, since\n * nested frame errors may have been caught and recovered by their callers.\n *\n * @param call - The root call trace frame.\n * @returns A `Revert` if the root frame reverted with output data,\n * otherwise `undefined`.\n */\nfunction extractRootRevert(\n call?: SimulationResponseCallTrace,\n): Revert | undefined {\n if (!call?.error) {\n return undefined;\n }\n return decodeRevert(call.output, 'simulation');\n}\n\n/**\n * Generate balance change data from previous and new balances.\n *\n * @param previousBalance - The previous balance.\n * @param newBalance - The new balance.\n * @param offset - Optional offset to apply to the new balance.\n * @returns The balance change data or undefined if unchanged.\n */\nfunction getSimulationBalanceChange(\n previousBalance: Hex,\n newBalance: Hex,\n offset: BN = new BN(0),\n): SimulationBalanceChange | undefined {\n const newBalanceBN = hexToBN(newBalance).add(offset);\n const previousBalanceBN = hexToBN(previousBalance);\n const differenceBN = newBalanceBN.sub(previousBalanceBN);\n const isDecrease = differenceBN.isNeg();\n const difference = toHex(differenceBN.abs());\n\n if (differenceBN.isZero()) {\n log('Balance change is zero');\n return undefined;\n }\n\n return {\n previousBalance,\n newBalance: toHex(newBalanceBN),\n difference,\n isDecrease,\n };\n}\n\n/**\n * Get the contract interfaces for all supported tokens.\n *\n * @returns A map of supported tokens to their contract interfaces.\n */\nfunction getContractInterfaces(): Map<SupportedToken, Interface> {\n const supportedTokens = Object.values(SupportedToken);\n\n return new Map(\n supportedTokens.map((tokenType) => {\n const { abi } = SUPPORTED_TOKEN_ABIS[tokenType];\n const contractInterface = new Interface(abi);\n return [tokenType, contractInterface];\n }),\n );\n}\n\n/**\n * Base request to simulation API.\n *\n * @param options - Options bag.\n * @param options.after - Transactions to simulate after user's transaction.\n * @param options.before - Transactions to simulate before user's transaction.\n * @param options.params - Additional parameters for the request.\n * @param options.request - Original request object.\n * @returns The simulation response.\n */\nasync function baseRequest({\n request,\n params,\n before = [],\n after = [],\n}: {\n request: GetBalanceChangesRequest;\n params?: Partial<SimulationRequest>;\n before?: SimulationRequestTransaction[];\n after?: SimulationRequestTransaction[];\n}): Promise<SimulationResponse> {\n const {\n blockTime,\n chainId,\n messenger,\n networkClientId,\n getSimulationConfig,\n txParams,\n } = request;\n const { authorizationList } = txParams;\n const from = txParams.from as Hex;\n\n const authorizationListFinal = authorizationList?.map((authorization) => ({\n address: authorization.address,\n from,\n }));\n\n const userTransaction: SimulationRequestTransaction = {\n authorizationList: authorizationListFinal,\n data: txParams.data as Hex,\n from: txParams.from as Hex,\n gas: txParams.gas as Hex,\n maxFeePerGas: (txParams.maxFeePerGas ?? txParams.gasPrice) as Hex,\n maxPriorityFeePerGas: (txParams.maxPriorityFeePerGas ??\n txParams.gasPrice) as Hex,\n to: txParams.to as Hex,\n value: txParams.value as Hex,\n };\n\n const transactions = [...before, userTransaction, ...after];\n const requiredBalanceBN = getRequiredBalance(request);\n const requiredBalanceHex = toHex(requiredBalanceBN);\n\n log('Required balance', requiredBalanceHex);\n\n const { balanceRaw } = await getNativeBalance(\n from,\n messenger,\n networkClientId,\n );\n const currentBalanceHex = toHex(balanceRaw);\n const currentBalanceBN = hexToBN(currentBalanceHex);\n\n log('Current balance', currentBalanceHex);\n\n const isInsufficientBalance = currentBalanceBN.lt(requiredBalanceBN);\n\n return await simulateTransactions(chainId, {\n ...params,\n getSimulationConfig,\n transactions,\n withGas: true,\n withDefaultBlockOverrides: true,\n ...(blockTime && {\n blockOverrides: {\n ...params?.blockOverrides,\n time: toHex(blockTime),\n },\n }),\n ...(isInsufficientBalance && {\n overrides: {\n ...params?.overrides,\n [from]: {\n ...params?.overrides?.[from],\n balance: requiredBalanceHex,\n },\n },\n }),\n });\n}\n\n/**\n * Calculate the required minimum balance for a transaction.\n *\n * @param request - The transaction request.\n * @returns The minimal balance as a BN.\n */\nfunction getRequiredBalance(request: GetBalanceChangesRequest): BN {\n const { txParams } = request;\n const gasLimit = hexToBN(txParams.gas ?? '0x0');\n const gasPrice = hexToBN(txParams.maxFeePerGas ?? txParams.gasPrice ?? '0x0');\n const value = hexToBN(txParams.value ?? '0x0');\n\n const nestedValue = getNestedValue(request.nestedTransactions);\n\n return gasLimit.mul(gasPrice).add(value).add(nestedValue);\n}\n\n/**\n * Sum the native values of nested transactions.\n *\n * @param nestedTransactions - The nested transactions of a batch.\n * @returns The total native value as a BN.\n */\nfunction getNestedValue(nestedTransactions?: NestedTransactionMetadata[]): BN {\n return (nestedTransactions ?? [])\n .map((tx) => hexToBN(tx.value ?? '0x0'))\n .reduce((acc, val) => acc.add(val), new BN(0));\n}\n\n/**\n * Calculate the sender's native balance change excluding the value sent by\n * the transaction and any nested transactions.\n *\n * @param txParams - Parameters of the simulated transaction.\n * @param previousBalance - Sender native balance before the simulation.\n * @param newBalance - Sender native balance after the simulation.\n * @param nestedTransactions - Nested transactions of a batch, if any.\n * @returns The balance change excluding the transferred value. Positive when\n * the sender gained, negative when the sender lost.\n */\nfunction getNativeBalanceChangeExcludingValue(\n txParams: TransactionParams,\n previousBalance: Hex,\n newBalance: Hex,\n nestedTransactions?: NestedTransactionMetadata[],\n): BN {\n return hexToBN(newBalance)\n .sub(hexToBN(previousBalance))\n .add(hexToBN(txParams.value ?? '0x0'))\n .add(getNestedValue(nestedTransactions));\n}\n"]}
1
+ {"version":3,"file":"balance-changes.js","sourceRoot":"","sources":["../../src/utils/balance-changes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Fragment, LogDescription, Result } from '@ethersproject/abi';\nimport { Interface } from '@ethersproject/abi';\nimport { hexToBN, toHex } from '@metamask/controller-utils';\nimport { abiERC20, abiERC721, abiERC1155 } from '@metamask/metamask-eth-abis';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport { createModuleLogger } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { simulateTransactions } from '../api/simulation-api.js';\nimport type {\n SimulationResponseLog,\n SimulationRequestTransaction,\n SimulationResponse,\n SimulationResponseCallTrace,\n SimulationResponseTransaction,\n SimulationRequest,\n} from '../api/simulation-api.js';\nimport {\n ABI_SIMULATION_ERC20_WRAPPED,\n ABI_SIMULATION_ERC721_LEGACY,\n} from '../constants.js';\nimport {\n SimulationError,\n SimulationInvalidResponseError,\n SimulationRevertedError,\n} from '../errors.js';\nimport { projectLogger } from '../logger.js';\nimport type { TransactionControllerMessenger } from '../TransactionController.js';\nimport type {\n Revert,\n SimulationBalanceChange,\n SimulationData,\n SimulationTokenBalanceChange,\n SimulationToken,\n TransactionParams,\n NestedTransactionMetadata,\n GetSimulationConfig,\n} from '../types.js';\nimport { SimulationTokenStandard } from '../types.js';\nimport { getNativeBalance } from './balance.js';\nimport { decodeRevert } from './revert-reason.js';\n\nexport enum SupportedToken {\n ERC20 = 'erc20',\n ERC721 = 'erc721',\n ERC1155 = 'erc1155',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ERC20_WRAPPED = 'erc20Wrapped',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ERC721_LEGACY = 'erc721Legacy',\n}\n\ntype ABI = Fragment[];\n\nexport type GetBalanceChangesRequest = {\n blockTime?: number;\n chainId: Hex;\n messenger: TransactionControllerMessenger;\n networkClientId: NetworkClientId;\n getSimulationConfig: GetSimulationConfig;\n nestedTransactions?: NestedTransactionMetadata[];\n txParams: TransactionParams;\n};\n\ntype ParsedEvent = {\n contractAddress: Hex;\n tokenStandard: SimulationTokenStandard;\n name: string;\n args: Record<string, Hex | Hex[]>;\n abi: ABI;\n};\n\nconst log = createModuleLogger(projectLogger, 'balance-changes');\n\nconst SUPPORTED_EVENTS = [\n 'Transfer',\n 'TransferSingle',\n 'TransferBatch',\n 'Deposit',\n 'Withdrawal',\n];\n\nconst SUPPORTED_TOKEN_ABIS = {\n [SupportedToken.ERC20]: {\n abi: abiERC20,\n standard: SimulationTokenStandard.erc20,\n },\n [SupportedToken.ERC721]: {\n abi: abiERC721,\n standard: SimulationTokenStandard.erc721,\n },\n [SupportedToken.ERC1155]: {\n abi: abiERC1155,\n standard: SimulationTokenStandard.erc1155,\n },\n [SupportedToken.ERC20_WRAPPED]: {\n abi: ABI_SIMULATION_ERC20_WRAPPED,\n standard: SimulationTokenStandard.erc20,\n },\n [SupportedToken.ERC721_LEGACY]: {\n abi: ABI_SIMULATION_ERC721_LEGACY,\n standard: SimulationTokenStandard.erc721,\n },\n};\n\nconst REVERTED_ERRORS = ['execution reverted', 'insufficient funds for gas'];\n\ntype BalanceTransactionMap = Map<SimulationToken, SimulationRequestTransaction>;\n\n/**\n * Generate simulation data for a transaction.\n *\n * @param request - The transaction to simulate.\n * @param request.chainId - The chain ID of the transaction.\n * @param request.from - The sender of the transaction.\n * @param request.to - The recipient of the transaction.\n * @param request.value - The value of the transaction.\n * @param request.data - The data of the transaction.\n * @param request.getSimulationConfig - Optional transaction simulation parameters.\n * @returns The simulation data.\n */\nexport async function getBalanceChanges(\n request: GetBalanceChangesRequest,\n): Promise<{\n simulationData: SimulationData;\n gasUsed?: Hex;\n simulationRevert?: Revert;\n}> {\n log('Request', request);\n\n let callTraceErrors: string[] | undefined;\n let simulationRevert: Revert | undefined;\n\n try {\n const response = await baseRequest({\n request,\n params: {\n withCallTrace: true,\n withLogs: true,\n },\n });\n\n const transactionResponse = response.transactions?.[0];\n callTraceErrors = extractCallTraceErrors(transactionResponse?.callTrace);\n simulationRevert = extractRootRevert(transactionResponse?.callTrace);\n const transactionError = transactionResponse?.error;\n\n if (transactionError) {\n throw new SimulationError(transactionError);\n }\n\n const nativeBalanceChange = getNativeBalanceChange(request, response);\n const events = getEvents(response);\n\n log('Parsed events', events);\n\n const tokenBalanceChanges = await getTokenBalanceChanges(request, events);\n\n const gasUsed = transactionResponse?.gasUsed;\n const simulationData = {\n callTraceErrors,\n nativeBalanceChange,\n tokenBalanceChanges,\n };\n\n return { simulationData, gasUsed, simulationRevert };\n } catch (error) {\n log('Failed to get balance changes', error, request);\n\n let simulationError = error as SimulationError;\n\n if (\n REVERTED_ERRORS.some((revertErrorMessage) =>\n simulationError.message?.includes(revertErrorMessage),\n )\n ) {\n simulationError = new SimulationRevertedError();\n }\n\n const { code, message } = simulationError;\n\n return {\n simulationData: {\n callTraceErrors,\n tokenBalanceChanges: [],\n error: {\n code,\n message,\n },\n },\n gasUsed: undefined,\n simulationRevert,\n };\n }\n}\n\n/**\n * Extract the native balance change from a simulation response.\n *\n * @param request - Simulation request.\n * @param response - Simulation response.\n * @returns Native balance change or undefined if unchanged.\n */\nfunction getNativeBalanceChange(\n request: GetBalanceChangesRequest,\n response: SimulationResponse,\n): SimulationBalanceChange | undefined {\n const transactionResponse = response.transactions[0];\n\n /* istanbul ignore next */\n if (!transactionResponse) {\n return undefined;\n }\n\n const { txParams } = request;\n const userAddress = txParams.from.toLowerCase() as Hex;\n const { stateDiff } = transactionResponse;\n const previousBalance = stateDiff?.pre?.[userAddress]?.balance;\n const newBalance = stateDiff?.post?.[userAddress]?.balance;\n\n if (!previousBalance || !newBalance) {\n return undefined;\n }\n\n const gasCost = isGasCostDeductedFromSender(\n txParams,\n previousBalance,\n newBalance,\n stateDiff,\n )\n ? transactionResponse.gasCost\n : undefined;\n\n return getSimulationBalanceChange(previousBalance, newBalance, gasCost);\n}\n\n/**\n * Determine whether the simulated gas cost was deducted from the sender.\n *\n * The gas cost is reported whether or not the simulation charged it, so it can\n * only be added back to the new balance when the sender actually paid it:\n *\n * - The sender is only charged when the simulated transaction specifies a fee\n * per gas.\n * - If the sender lost exactly the transaction value, gas was not charged.\n * - Some chains credit the fee recipient without debiting the sender, which is\n * detectable because it increases the total native balance.\n *\n * @param txParams - Parameters of the simulated transaction.\n * @param previousBalance - Sender native balance before the simulation.\n * @param newBalance - Sender native balance after the simulation.\n * @param stateDiff - Native balances before and after the simulation.\n * @returns Whether the gas cost was deducted from the sender.\n */\nfunction isGasCostDeductedFromSender(\n txParams: TransactionParams,\n previousBalance: Hex,\n newBalance: Hex,\n stateDiff: SimulationResponseTransaction['stateDiff'],\n): boolean {\n const feePerGas = (txParams.maxFeePerGas ?? txParams.gasPrice) as\n | Hex\n | undefined;\n\n if (!feePerGas || hexToBN(feePerGas).isZero()) {\n return false;\n }\n\n const extraLoss = hexToBN(previousBalance)\n .sub(hexToBN(newBalance))\n .sub(hexToBN(txParams.value ?? '0x0'));\n\n if (extraLoss.isZero()) {\n return false;\n }\n\n return !isNativeBalanceCreated(stateDiff);\n}\n\n/**\n * Determine whether a state diff increases the total native balance.\n *\n * Executing a transaction cannot create native balance, so a positive total\n * means the simulation credited an account without debiting another.\n *\n * @param stateDiff - Native balances before and after the simulation.\n * @returns Whether the total native balance increased.\n */\nfunction isNativeBalanceCreated(\n stateDiff: SimulationResponseTransaction['stateDiff'],\n): boolean {\n const previousState = stateDiff?.pre ?? {};\n const newState = stateDiff?.post ?? {};\n const addresses = new Set([\n ...Object.keys(previousState),\n ...Object.keys(newState),\n ]);\n\n const totalBalanceChange = [...addresses].reduce((total, address) => {\n const previousBalance = previousState[address as Hex]?.balance ?? '0x0';\n const newBalance = newState[address as Hex]?.balance ?? '0x0';\n\n return total.add(hexToBN(newBalance).sub(hexToBN(previousBalance)));\n }, new BN(0));\n\n return totalBalanceChange.gt(new BN(0));\n}\n\n/**\n * Extract events from a simulation response.\n *\n * @param response - The simulation response.\n * @returns The parsed events.\n */\nfunction getEvents(response: SimulationResponse): ParsedEvent[] {\n /* istanbul ignore next */\n const logs = extractLogs(response.transactions[0]?.callTrace ?? {});\n\n log('Extracted logs', logs);\n\n const interfaces = getContractInterfaces();\n\n return logs\n .map((currentLog) => {\n const event = parseLog(currentLog, interfaces);\n\n if (!event) {\n log('Failed to parse log', currentLog);\n return;\n }\n\n /* istanbul ignore next */\n const inputs = event.abi.find(\n (eventAbi) => eventAbi.name === event.name,\n )?.inputs;\n\n /* istanbul ignore if */\n if (!inputs) {\n log('Failed to find inputs for event', event);\n return;\n }\n\n if (!SUPPORTED_EVENTS.includes(event.name)) {\n log('Ignoring unsupported event', event.name, event);\n return;\n }\n\n log('Normalizing event args', event.name, event);\n\n const args = normalizeEventArgs(event.args, inputs);\n\n return {\n contractAddress: currentLog.address,\n tokenStandard: event.standard,\n name: event.name,\n args,\n abi: event.abi,\n };\n })\n .filter((parsedEvent) => parsedEvent !== undefined);\n}\n\n/**\n * Normalize event arguments using ABI input definitions.\n *\n * @param args - The raw event arguments.\n * @param abiInputs - The ABI input definitions.\n * @returns The normalized event arguments.\n */\nfunction normalizeEventArgs(\n args: Result,\n abiInputs: { name: string }[],\n): Record<string, Hex | Hex[]> {\n return args.reduce((result, arg, index) => {\n const name = abiInputs[index].name.replace('_', '');\n const value = normalizeEventArgValue(arg);\n\n result[name] = value;\n\n return result;\n }, {});\n}\n\n/**\n * Normalize an event argument value.\n *\n * @param value - The event argument value.\n * @returns The normalized event argument value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction normalizeEventArgValue(value: any): any {\n if (Array.isArray(value)) {\n return value.map(normalizeEventArgValue);\n }\n\n let normalizedValue = value;\n\n normalizedValue = normalizedValue.toHexString?.() ?? normalizedValue;\n normalizedValue = normalizedValue.toLowerCase?.() ?? normalizedValue;\n\n return normalizedValue;\n}\n\n/**\n * Generate token balance changes from parsed events.\n *\n * @param request - The transaction that was simulated.\n * @param events - The parsed events.\n * @returns An array of token balance changes.\n */\nasync function getTokenBalanceChanges(\n request: GetBalanceChangesRequest,\n events: ParsedEvent[],\n): Promise<SimulationTokenBalanceChange[]> {\n const { txParams } = request;\n const from = txParams.from as Hex;\n const balanceTxs = getTokenBalanceTransactions(request, events);\n\n log('Generated balance transactions', [...balanceTxs.after.values()]);\n\n const transactionCount = balanceTxs.before.size + balanceTxs.after.size + 1;\n\n if (transactionCount === 1) {\n return [];\n }\n\n const response = await baseRequest({\n request,\n before: [...balanceTxs.before.values()],\n after: [...balanceTxs.after.values()],\n });\n\n log('Balance simulation response', response);\n\n if (response.transactions.length !== transactionCount) {\n throw new SimulationInvalidResponseError();\n }\n\n let prevBalanceTxIndex = 0;\n return [...balanceTxs.after.keys()]\n .map((token, index) => {\n const previousBalanceCheckSkipped = !balanceTxs.before.get(token);\n const previousBalance = previousBalanceCheckSkipped\n ? '0x0'\n : getAmountFromBalanceTransactionResult(\n from,\n token,\n // eslint-disable-next-line no-plusplus\n response.transactions[prevBalanceTxIndex++],\n );\n\n const newBalance = getAmountFromBalanceTransactionResult(\n from,\n token,\n response.transactions[index + balanceTxs.before.size + 1],\n );\n\n const balanceChange = getSimulationBalanceChange(\n previousBalance,\n newBalance,\n );\n\n if (!balanceChange) {\n return;\n }\n\n return {\n ...token,\n ...balanceChange,\n };\n })\n .filter((change) => change !== undefined);\n}\n\n/**\n * Generate transactions to check token balances.\n *\n * @param request - The transaction that was simulated.\n * @param events - The parsed events.\n * @returns A map of token balance transactions keyed by token.\n */\nfunction getTokenBalanceTransactions(\n request: GetBalanceChangesRequest,\n events: ParsedEvent[],\n): {\n before: BalanceTransactionMap;\n after: BalanceTransactionMap;\n} {\n const tokenKeys = new Set();\n const before = new Map();\n const after = new Map();\n const from = request.txParams.from as Hex;\n\n const userEvents = events.filter((event) =>\n [event.args.from, event.args.to].includes(from),\n );\n\n log('Filtered user events', userEvents);\n\n for (const event of userEvents) {\n const tokenIds = getEventTokenIds(event);\n\n log('Extracted token IDs', tokenIds);\n\n for (const tokenId of tokenIds) {\n const simulationToken: SimulationToken = {\n address: event.contractAddress,\n standard: event.tokenStandard,\n id: tokenId,\n };\n\n const tokenKey = JSON.stringify(simulationToken);\n\n if (tokenKeys.has(tokenKey)) {\n log(\n 'Ignoring additional event with same contract and token ID',\n simulationToken,\n );\n continue;\n }\n\n tokenKeys.add(tokenKey);\n\n const data = getBalanceTransactionData(\n event.tokenStandard,\n from,\n tokenId,\n );\n\n const transaction: SimulationRequestTransaction = {\n from,\n to: event.contractAddress,\n data,\n };\n\n if (skipPriorBalanceCheck(event)) {\n after.set(simulationToken, transaction);\n } else {\n before.set(simulationToken, transaction);\n after.set(simulationToken, transaction);\n }\n }\n }\n\n return { before, after };\n}\n\n/**\n * Check if an event needs to check the previous balance.\n *\n * @param event - The parsed event.\n * @returns True if the prior balance check should be skipped.\n */\nfunction skipPriorBalanceCheck(event: ParsedEvent): boolean {\n // In the case of an NFT mint, we cannot check the NFT owner before the mint\n // as the balance check transaction would revert.\n return (\n event.name === 'Transfer' &&\n event.tokenStandard === SimulationTokenStandard.erc721 &&\n parseInt(event.args.from as string, 16) === 0\n );\n}\n\n/**\n * Extract token IDs from a parsed event.\n *\n * @param event - The parsed event.\n * @returns An array of token IDs.\n */\nfunction getEventTokenIds(event: ParsedEvent): (Hex | undefined)[] {\n if (event.tokenStandard === SimulationTokenStandard.erc721) {\n return [event.args.tokenId as Hex];\n }\n\n if (\n event.tokenStandard === SimulationTokenStandard.erc1155 &&\n event.name === 'TransferSingle'\n ) {\n return [event.args.id as Hex];\n }\n\n if (\n event.tokenStandard === SimulationTokenStandard.erc1155 &&\n event.name === 'TransferBatch'\n ) {\n return event.args.ids as Hex[];\n }\n\n // ERC-20 does not have a token ID so default to undefined.\n return [undefined];\n}\n\n/**\n * Get the interface for a token standard.\n *\n * @param tokenStandard - The token standard.\n * @returns The interface for the token standard.\n */\nfunction getContractInterface(\n tokenStandard: SimulationTokenStandard,\n): Interface {\n switch (tokenStandard) {\n case SimulationTokenStandard.erc721:\n return new Interface(abiERC721);\n case SimulationTokenStandard.erc1155:\n return new Interface(abiERC1155);\n default:\n return new Interface(abiERC20);\n }\n}\n\n/**\n * Extract the value from a balance transaction response using the correct ABI.\n *\n * @param from - The address to check the balance of.\n * @param token - The token to check the balance of.\n * @param response - The balance transaction response.\n * @returns The value of the balance transaction as Hex.\n */\nfunction getAmountFromBalanceTransactionResult(\n from: Hex,\n token: SimulationToken,\n response: SimulationResponseTransaction,\n): Hex {\n const contract = getContractInterface(token.standard);\n\n try {\n if (token.standard === SimulationTokenStandard.erc721) {\n const result = contract.decodeFunctionResult('ownerOf', response.return);\n const owner = result[0];\n return owner.toLowerCase() === from.toLowerCase() ? '0x1' : '0x0';\n }\n\n const result = contract.decodeFunctionResult('balanceOf', response.return);\n return toHex(result[0]);\n } catch (error) {\n log('Failed to decode balance transaction', error, { token, response });\n throw new SimulationError(\n `Failed to decode balance transaction for token ${\n token.address\n }: ${String(error)}`,\n );\n }\n}\n\n/**\n * Generate the balance transaction data for a token.\n *\n * @param tokenStandard - The token standard.\n * @param from - The address to check the balance of.\n * @param tokenId - The token ID to check the balance of.\n * @returns The balance transaction data.\n */\nfunction getBalanceTransactionData(\n tokenStandard: SimulationTokenStandard,\n from: Hex,\n tokenId?: Hex,\n): Hex {\n const contract = getContractInterface(tokenStandard);\n switch (tokenStandard) {\n case SimulationTokenStandard.erc721:\n return contract.encodeFunctionData('ownerOf', [tokenId]) as Hex;\n\n case SimulationTokenStandard.erc1155:\n return contract.encodeFunctionData('balanceOf', [from, tokenId]) as Hex;\n\n default:\n return contract.encodeFunctionData('balanceOf', [from]) as Hex;\n }\n}\n\n/**\n * Parse a raw event log using known ABIs.\n *\n * @param eventLog - The raw event log.\n * @param interfaces - The contract interfaces.\n * @returns The parsed event log or undefined if it could not be parsed.\n */\nfunction parseLog(\n eventLog: SimulationResponseLog,\n interfaces: Map<SupportedToken, Interface>,\n):\n | (LogDescription & { abi: ABI; standard: SimulationTokenStandard })\n | undefined {\n const supportedTokens = Object.values(SupportedToken);\n\n for (const token of supportedTokens) {\n try {\n const contractInterface = interfaces.get(token) as Interface;\n const { abi, standard } = SUPPORTED_TOKEN_ABIS[token];\n\n return {\n ...contractInterface.parseLog(eventLog),\n abi,\n standard,\n };\n } catch {\n continue;\n }\n }\n\n return undefined;\n}\n\n/**\n * Extract all logs from a call trace tree.\n *\n * @param call - The root call trace.\n * @returns An array of logs.\n */\nfunction extractLogs(\n call: SimulationResponseCallTrace,\n): SimulationResponseLog[] {\n /* istanbul ignore next */\n const logs = call.logs ?? [];\n\n /* istanbul ignore next */\n const nestedCalls = call.calls ?? [];\n\n return [\n ...logs,\n ...nestedCalls.map((nestedCall) => extractLogs(nestedCall)).flat(),\n ];\n}\n\n/**\n * Extract all error messages from a call trace tree.\n *\n * @param call - The root call trace.\n * @returns An array of error messages.\n */\nfunction extractCallTraceErrors(call?: SimulationResponseCallTrace): string[] {\n if (!call) {\n return [];\n }\n\n const errors = call.error ? [call.error] : [];\n const nestedCalls = call.calls ?? [];\n const nestedErrors = nestedCalls.flatMap((nestedCall) =>\n extractCallTraceErrors(nestedCall),\n );\n\n return [...errors, ...nestedErrors];\n}\n\n/**\n * Build a `Revert` from the root call trace frame. Reads only the raw\n * `output` hex and decodes it locally; the upstream `error` message string\n * is never parsed. Only the root frame's output is considered, since\n * nested frame errors may have been caught and recovered by their callers.\n *\n * @param call - The root call trace frame.\n * @returns A `Revert` if the root frame reverted with output data,\n * otherwise `undefined`.\n */\nfunction extractRootRevert(\n call?: SimulationResponseCallTrace,\n): Revert | undefined {\n if (!call?.error) {\n return undefined;\n }\n return decodeRevert(call.output, 'simulation');\n}\n\n/**\n * Generate balance change data from previous and new balances.\n *\n * @param previousBalance - The previous balance.\n * @param newBalance - The new balance.\n * @param offset - Optional offset to apply to the new balance.\n * @returns The balance change data or undefined if unchanged.\n */\nfunction getSimulationBalanceChange(\n previousBalance: Hex,\n newBalance: Hex,\n offset: number = 0,\n): SimulationBalanceChange | undefined {\n const newBalanceBN = hexToBN(newBalance).add(new BN(offset));\n const previousBalanceBN = hexToBN(previousBalance);\n const differenceBN = newBalanceBN.sub(previousBalanceBN);\n const isDecrease = differenceBN.isNeg();\n const difference = toHex(differenceBN.abs());\n\n if (differenceBN.isZero()) {\n log('Balance change is zero');\n return undefined;\n }\n\n return {\n previousBalance,\n newBalance: toHex(newBalanceBN),\n difference,\n isDecrease,\n };\n}\n\n/**\n * Get the contract interfaces for all supported tokens.\n *\n * @returns A map of supported tokens to their contract interfaces.\n */\nfunction getContractInterfaces(): Map<SupportedToken, Interface> {\n const supportedTokens = Object.values(SupportedToken);\n\n return new Map(\n supportedTokens.map((tokenType) => {\n const { abi } = SUPPORTED_TOKEN_ABIS[tokenType];\n const contractInterface = new Interface(abi);\n return [tokenType, contractInterface];\n }),\n );\n}\n\n/**\n * Base request to simulation API.\n *\n * @param options - Options bag.\n * @param options.after - Transactions to simulate after user's transaction.\n * @param options.before - Transactions to simulate before user's transaction.\n * @param options.params - Additional parameters for the request.\n * @param options.request - Original request object.\n * @returns The simulation response.\n */\nasync function baseRequest({\n request,\n params,\n before = [],\n after = [],\n}: {\n request: GetBalanceChangesRequest;\n params?: Partial<SimulationRequest>;\n before?: SimulationRequestTransaction[];\n after?: SimulationRequestTransaction[];\n}): Promise<SimulationResponse> {\n const {\n blockTime,\n chainId,\n messenger,\n networkClientId,\n getSimulationConfig,\n txParams,\n } = request;\n const { authorizationList } = txParams;\n const from = txParams.from as Hex;\n\n const authorizationListFinal = authorizationList?.map((authorization) => ({\n address: authorization.address,\n from,\n }));\n\n const userTransaction: SimulationRequestTransaction = {\n authorizationList: authorizationListFinal,\n data: txParams.data as Hex,\n from: txParams.from as Hex,\n gas: txParams.gas as Hex,\n maxFeePerGas: (txParams.maxFeePerGas ?? txParams.gasPrice) as Hex,\n maxPriorityFeePerGas: (txParams.maxPriorityFeePerGas ??\n txParams.gasPrice) as Hex,\n to: txParams.to as Hex,\n value: txParams.value as Hex,\n };\n\n const transactions = [...before, userTransaction, ...after];\n const requiredBalanceBN = getRequiredBalance(request);\n const requiredBalanceHex = toHex(requiredBalanceBN);\n\n log('Required balance', requiredBalanceHex);\n\n const { balanceRaw } = await getNativeBalance(\n from,\n messenger,\n networkClientId,\n );\n const currentBalanceHex = toHex(balanceRaw);\n const currentBalanceBN = hexToBN(currentBalanceHex);\n\n log('Current balance', currentBalanceHex);\n\n const isInsufficientBalance = currentBalanceBN.lt(requiredBalanceBN);\n\n return await simulateTransactions(chainId, {\n ...params,\n getSimulationConfig,\n transactions,\n withGas: true,\n withDefaultBlockOverrides: true,\n ...(blockTime && {\n blockOverrides: {\n ...params?.blockOverrides,\n time: toHex(blockTime),\n },\n }),\n ...(isInsufficientBalance && {\n overrides: {\n ...params?.overrides,\n [from]: {\n ...params?.overrides?.[from],\n balance: requiredBalanceHex,\n },\n },\n }),\n });\n}\n\n/**\n * Calculate the required minimum balance for a transaction.\n *\n * @param request - The transaction request.\n * @returns The minimal balance as a BN.\n */\nfunction getRequiredBalance(request: GetBalanceChangesRequest): BN {\n const { txParams } = request;\n const gasLimit = hexToBN(txParams.gas ?? '0x0');\n const gasPrice = hexToBN(txParams.maxFeePerGas ?? txParams.gasPrice ?? '0x0');\n const value = hexToBN(txParams.value ?? '0x0');\n\n const nestedValue = (request.nestedTransactions ?? [])\n .map((tx) => hexToBN(tx.value ?? '0x0'))\n .reduce((acc, val) => acc.add(val), new BN(0));\n\n return gasLimit.mul(gasPrice).add(value).add(nestedValue);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/transaction-controller",
3
- "version": "72.2.1-preview-eefc6963e",
3
+ "version": "72.2.1-preview-2a7a9a077",
4
4
  "description": "Stores transactions alongside their periodically updated statuses and manages interactions such as approval and cancellation",
5
5
  "keywords": [
6
6
  "Ethereum",