@metamask/transaction-controller 52.0.0 → 52.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/TransactionController.cjs +24 -12
  3. package/dist/TransactionController.cjs.map +1 -1
  4. package/dist/TransactionController.d.cts +3 -0
  5. package/dist/TransactionController.d.cts.map +1 -1
  6. package/dist/TransactionController.d.mts +3 -0
  7. package/dist/TransactionController.d.mts.map +1 -1
  8. package/dist/TransactionController.mjs +25 -13
  9. package/dist/TransactionController.mjs.map +1 -1
  10. package/dist/helpers/GasFeePoller.cjs +73 -1
  11. package/dist/helpers/GasFeePoller.cjs.map +1 -1
  12. package/dist/helpers/GasFeePoller.d.cts +20 -2
  13. package/dist/helpers/GasFeePoller.d.cts.map +1 -1
  14. package/dist/helpers/GasFeePoller.d.mts +20 -2
  15. package/dist/helpers/GasFeePoller.d.mts.map +1 -1
  16. package/dist/helpers/GasFeePoller.mjs +72 -1
  17. package/dist/helpers/GasFeePoller.mjs.map +1 -1
  18. package/dist/utils/feature-flags.cjs +2 -2
  19. package/dist/utils/feature-flags.cjs.map +1 -1
  20. package/dist/utils/feature-flags.d.cts +2 -2
  21. package/dist/utils/feature-flags.d.mts +2 -2
  22. package/dist/utils/feature-flags.mjs +2 -2
  23. package/dist/utils/feature-flags.mjs.map +1 -1
  24. package/dist/utils/gas.cjs +108 -8
  25. package/dist/utils/gas.cjs.map +1 -1
  26. package/dist/utils/gas.d.cts +16 -5
  27. package/dist/utils/gas.d.cts.map +1 -1
  28. package/dist/utils/gas.d.mts +16 -5
  29. package/dist/utils/gas.d.mts.map +1 -1
  30. package/dist/utils/gas.mjs +108 -8
  31. package/dist/utils/gas.mjs.map +1 -1
  32. package/dist/utils/simulation-api.cjs.map +1 -1
  33. package/dist/utils/simulation-api.d.cts +9 -5
  34. package/dist/utils/simulation-api.d.cts.map +1 -1
  35. package/dist/utils/simulation-api.d.mts +9 -5
  36. package/dist/utils/simulation-api.d.mts.map +1 -1
  37. package/dist/utils/simulation-api.mjs.map +1 -1
  38. package/package.json +2 -2
@@ -1,15 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addGasBuffer = exports.estimateGas = exports.updateGas = exports.MAX_GAS_BLOCK_PERCENT = exports.GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = exports.DEFAULT_GAS_MULTIPLIER = exports.FIXED_GAS = exports.log = void 0;
3
+ exports.addGasBuffer = exports.estimateGas = exports.updateGas = exports.DUMMY_AUTHORIZATION_SIGNATURE = exports.INTRINSIC_GAS = exports.MAX_GAS_BLOCK_PERCENT = exports.GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = exports.DEFAULT_GAS_MULTIPLIER = exports.FIXED_GAS = exports.log = void 0;
4
4
  const controller_utils_1 = require("@metamask/controller-utils");
5
5
  const utils_1 = require("@metamask/utils");
6
+ const eip7702_1 = require("./eip7702.cjs");
7
+ const simulation_api_1 = require("./simulation-api.cjs");
6
8
  const constants_1 = require("../constants.cjs");
7
9
  const logger_1 = require("../logger.cjs");
10
+ const types_1 = require("../types.cjs");
8
11
  exports.log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'gas');
9
12
  exports.FIXED_GAS = '0x5208';
10
13
  exports.DEFAULT_GAS_MULTIPLIER = 1.5;
11
14
  exports.GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;
12
15
  exports.MAX_GAS_BLOCK_PERCENT = 90;
16
+ exports.INTRINSIC_GAS = 21000;
17
+ exports.DUMMY_AUTHORIZATION_SIGNATURE = '0x1111111111111111111111111111111111111111111111111111111111111111';
13
18
  /**
14
19
  * Populate the gas properties of the provided transaction meta.
15
20
  *
@@ -35,25 +40,39 @@ exports.updateGas = updateGas;
35
40
  * Estimate the gas for the provided transaction parameters.
36
41
  * If the gas estimate fails, the fallback value is returned.
37
42
  *
38
- * @param txParams - The transaction parameters.
39
- * @param ethQuery - The EthQuery instance to interact with the network.
43
+ * @param options - The options object.
44
+ * @param options.chainId - The chain ID of the transaction.
45
+ * @param options.ethQuery - The EthQuery instance to interact with the network.
46
+ * @param options.isSimulationEnabled - Whether the simulation is enabled.
47
+ * @param options.txParams - The transaction parameters.
40
48
  * @returns The estimated gas and related info.
41
49
  */
42
- async function estimateGas(txParams, ethQuery) {
50
+ async function estimateGas({ chainId, ethQuery, isSimulationEnabled, txParams, }) {
43
51
  const request = { ...txParams };
44
- const { data, value } = request;
52
+ const { authorizationList, data, from, value, to } = request;
45
53
  const { gasLimit: blockGasLimit, number: blockNumber } = await getLatestBlock(ethQuery);
46
54
  const blockGasLimitBN = (0, controller_utils_1.hexToBN)(blockGasLimit);
47
55
  const fallback = (0, controller_utils_1.BNToHex)((0, controller_utils_1.fractionBN)(blockGasLimitBN, exports.GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT, 100));
48
56
  request.data = data ? (0, utils_1.add0x)(data) : data;
49
57
  request.value = value || '0x0';
58
+ request.authorizationList = normalizeAuthorizationList(request.authorizationList, chainId);
50
59
  delete request.gasPrice;
51
60
  delete request.maxFeePerGas;
52
61
  delete request.maxPriorityFeePerGas;
53
62
  let estimatedGas = fallback;
54
63
  let simulationFails;
64
+ const isUpgradeWithDataToSelf = txParams.type === types_1.TransactionEnvelopeType.setCode &&
65
+ authorizationList?.length &&
66
+ data &&
67
+ data !== '0x' &&
68
+ from?.toLowerCase() === to?.toLowerCase();
55
69
  try {
56
- estimatedGas = await (0, controller_utils_1.query)(ethQuery, 'estimateGas', [request]);
70
+ if (isSimulationEnabled && isUpgradeWithDataToSelf) {
71
+ estimatedGas = await estimateGasUpgradeWithDataToSelf(request, ethQuery, chainId);
72
+ }
73
+ else {
74
+ estimatedGas = await (0, controller_utils_1.query)(ethQuery, 'estimateGas', [request]);
75
+ }
57
76
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
77
  }
59
78
  catch (error) {
@@ -109,7 +128,7 @@ exports.addGasBuffer = addGasBuffer;
109
128
  * @returns The final gas value and the estimate used.
110
129
  */
111
130
  async function getGas(request) {
112
- const { isCustomNetwork, chainId, txMeta } = request;
131
+ const { chainId, isCustomNetwork, isSimulationEnabled, txMeta } = request;
113
132
  if (txMeta.txParams.gas) {
114
133
  (0, exports.log)('Using value from request', txMeta.txParams.gas);
115
134
  return [txMeta.txParams.gas, undefined, txMeta.txParams.gas];
@@ -118,7 +137,12 @@ async function getGas(request) {
118
137
  (0, exports.log)('Using fixed value', exports.FIXED_GAS);
119
138
  return [exports.FIXED_GAS, undefined, exports.FIXED_GAS];
120
139
  }
121
- const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas(txMeta.txParams, request.ethQuery);
140
+ const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas({
141
+ chainId: request.chainId,
142
+ ethQuery: request.ethQuery,
143
+ isSimulationEnabled,
144
+ txParams: txMeta.txParams,
145
+ });
122
146
  if (isCustomNetwork || simulationFails) {
123
147
  (0, exports.log)(isCustomNetwork
124
148
  ? 'Using original estimate as custom network'
@@ -165,4 +189,80 @@ async function getCode(ethQuery, address) {
165
189
  async function getLatestBlock(ethQuery) {
166
190
  return await (0, controller_utils_1.query)(ethQuery, 'getBlockByNumber', ['latest', false]);
167
191
  }
192
+ /**
193
+ * Estimate the gas for a type 4 transaction.
194
+ *
195
+ * @param txParams - The transaction parameters.
196
+ * @param ethQuery - The EthQuery instance to interact with the network.
197
+ * @param chainId - The chain ID of the transaction.
198
+ * @returns The estimated gas.
199
+ */
200
+ async function estimateGasUpgradeWithDataToSelf(txParams, ethQuery, chainId) {
201
+ const upgradeGas = await (0, controller_utils_1.query)(ethQuery, 'estimateGas', [
202
+ {
203
+ ...txParams,
204
+ data: '0x',
205
+ },
206
+ ]);
207
+ (0, exports.log)('Upgrade only gas', upgradeGas);
208
+ const delegationAddress = txParams.authorizationList?.[0].address;
209
+ const executeGas = await simulateGas({
210
+ chainId: chainId,
211
+ delegationAddress,
212
+ transaction: txParams,
213
+ });
214
+ (0, exports.log)('Execute gas', executeGas);
215
+ const total = (0, controller_utils_1.BNToHex)((0, controller_utils_1.hexToBN)(upgradeGas).add((0, controller_utils_1.hexToBN)(executeGas)).subn(exports.INTRINSIC_GAS));
216
+ (0, exports.log)('Total type 4 gas', total);
217
+ return total;
218
+ }
219
+ /**
220
+ * Simulate the required gas using the simulation API.
221
+ *
222
+ * @param options - The options object.
223
+ * @param options.chainId - The chain ID of the transaction.
224
+ * @param options.delegationAddress - The delegation address of the sender to mock.
225
+ * @param options.transaction - The transaction parameters.
226
+ * @returns The simulated gas.
227
+ */
228
+ async function simulateGas({ chainId, delegationAddress, transaction, }) {
229
+ const response = await (0, simulation_api_1.simulateTransactions)(chainId, {
230
+ transactions: [
231
+ {
232
+ to: transaction.to,
233
+ from: transaction.from,
234
+ data: transaction.data,
235
+ value: transaction.value,
236
+ },
237
+ ],
238
+ overrides: {
239
+ [transaction.from]: {
240
+ code: delegationAddress &&
241
+ (eip7702_1.DELEGATION_PREFIX + (0, utils_1.remove0x)(delegationAddress)),
242
+ },
243
+ },
244
+ });
245
+ const gasUsed = response?.transactions?.[0].gasUsed;
246
+ if (!gasUsed) {
247
+ throw new Error('No simulated gas returned');
248
+ }
249
+ return gasUsed;
250
+ }
251
+ /**
252
+ * Populate the authorization list with dummy values.
253
+ *
254
+ * @param authorizationList - The authorization list to prepare.
255
+ * @param chainId - The chain ID to use.
256
+ * @returns The authorization list with dummy values.
257
+ */
258
+ function normalizeAuthorizationList(authorizationList, chainId) {
259
+ return authorizationList?.map((authorization) => ({
260
+ ...authorization,
261
+ chainId: authorization.chainId ?? chainId,
262
+ nonce: authorization.nonce ?? '0x1',
263
+ r: authorization.r ?? exports.DUMMY_AUTHORIZATION_SIGNATURE,
264
+ s: authorization.s ?? exports.DUMMY_AUTHORIZATION_SIGNATURE,
265
+ yParity: authorization.yParity ?? '0x1',
266
+ }));
267
+ }
168
268
  //# sourceMappingURL=gas.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"gas.cjs","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BNToHex,\n fractionBN,\n hexToBN,\n query,\n} from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger } from '@metamask/utils';\n\nimport { GAS_BUFFER_CHAIN_OVERRIDES } from '../constants';\nimport { projectLogger } from '../logger';\nimport type { TransactionMeta, TransactionParams } from '../types';\n\nexport type UpdateGasRequest = {\n ethQuery: EthQuery;\n isCustomNetwork: boolean;\n chainId: Hex;\n txMeta: TransactionMeta;\n};\n\nexport const log = createModuleLogger(projectLogger, 'gas');\n\nexport const FIXED_GAS = '0x5208';\nexport const DEFAULT_GAS_MULTIPLIER = 1.5;\nexport const GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;\nexport const MAX_GAS_BLOCK_PERCENT = 90;\n\n/**\n * Populate the gas properties of the provided transaction meta.\n *\n * @param request - The request object including the necessary parameters.\n */\nexport async function updateGas(request: UpdateGasRequest) {\n const { txMeta } = request;\n const initialParams = { ...txMeta.txParams };\n\n const [gas, simulationFails, gasLimitNoBuffer] = await getGas(request);\n\n txMeta.txParams.gas = gas;\n txMeta.simulationFails = simulationFails;\n txMeta.gasLimitNoBuffer = gasLimitNoBuffer;\n\n if (!initialParams.gas) {\n txMeta.originalGasEstimate = txMeta.txParams.gas;\n }\n\n if (!txMeta.defaultGasEstimates) {\n txMeta.defaultGasEstimates = {};\n }\n\n txMeta.defaultGasEstimates.gas = txMeta.txParams.gas;\n}\n\n/**\n * Estimate the gas for the provided transaction parameters.\n * If the gas estimate fails, the fallback value is returned.\n *\n * @param txParams - The transaction parameters.\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @returns The estimated gas and related info.\n */\nexport async function estimateGas(\n txParams: TransactionParams,\n ethQuery: EthQuery,\n) {\n const request = { ...txParams };\n const { data, value } = request;\n\n const { gasLimit: blockGasLimit, number: blockNumber } =\n await getLatestBlock(ethQuery);\n\n const blockGasLimitBN = hexToBN(blockGasLimit);\n\n const fallback = BNToHex(\n fractionBN(blockGasLimitBN, GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT, 100),\n );\n\n request.data = data ? add0x(data) : data;\n request.value = value || '0x0';\n\n delete request.gasPrice;\n delete request.maxFeePerGas;\n delete request.maxPriorityFeePerGas;\n\n let estimatedGas = fallback;\n let simulationFails: TransactionMeta['simulationFails'];\n\n try {\n estimatedGas = await query(ethQuery, 'estimateGas', [request]);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n simulationFails = {\n reason: error.message,\n errorKey: error.errorKey,\n debug: {\n blockNumber,\n blockGasLimit,\n },\n };\n\n log('Estimation failed', { ...simulationFails, fallback });\n }\n\n return {\n blockGasLimit,\n estimatedGas,\n simulationFails,\n };\n}\n\n/**\n * Add a buffer to the provided estimated gas.\n * The buffer is calculated based on the block gas limit and a multiplier.\n *\n * @param estimatedGas - The estimated gas.\n * @param blockGasLimit - The block gas limit.\n * @param multiplier - The multiplier to apply to the estimated gas.\n * @returns The gas with the buffer applied.\n */\nexport function addGasBuffer(\n estimatedGas: string,\n blockGasLimit: string,\n multiplier: number,\n) {\n const estimatedGasBN = hexToBN(estimatedGas);\n\n const maxGasBN = fractionBN(\n hexToBN(blockGasLimit),\n MAX_GAS_BLOCK_PERCENT,\n 100,\n );\n\n const paddedGasBN = fractionBN(estimatedGasBN, multiplier * 100, 100);\n\n if (estimatedGasBN.gt(maxGasBN)) {\n const estimatedGasHex = add0x(estimatedGas);\n log('Using estimated value', estimatedGasHex);\n return estimatedGasHex;\n }\n\n if (paddedGasBN.lt(maxGasBN)) {\n const paddedHex = add0x(BNToHex(paddedGasBN));\n log('Using padded estimate', paddedHex, multiplier);\n return paddedHex;\n }\n\n const maxHex = add0x(BNToHex(maxGasBN));\n log('Using 90% of block gas limit', maxHex);\n return maxHex;\n}\n\n/**\n * Determine the gas for the provided request.\n *\n * @param request - The request object including the necessary parameters.\n * @returns The final gas value and the estimate used.\n */\nasync function getGas(\n request: UpdateGasRequest,\n): Promise<[string, TransactionMeta['simulationFails']?, string?]> {\n const { isCustomNetwork, chainId, txMeta } = request;\n\n if (txMeta.txParams.gas) {\n log('Using value from request', txMeta.txParams.gas);\n return [txMeta.txParams.gas, undefined, txMeta.txParams.gas];\n }\n\n if (await requiresFixedGas(request)) {\n log('Using fixed value', FIXED_GAS);\n return [FIXED_GAS, undefined, FIXED_GAS];\n }\n\n const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas(\n txMeta.txParams,\n request.ethQuery,\n );\n\n if (isCustomNetwork || simulationFails) {\n log(\n isCustomNetwork\n ? 'Using original estimate as custom network'\n : 'Using original fallback estimate as simulation failed',\n );\n return [estimatedGas, simulationFails, estimatedGas];\n }\n\n const bufferMultiplier =\n GAS_BUFFER_CHAIN_OVERRIDES[\n chainId as keyof typeof GAS_BUFFER_CHAIN_OVERRIDES\n ] ?? DEFAULT_GAS_MULTIPLIER;\n\n const bufferedGas = addGasBuffer(\n estimatedGas,\n blockGasLimit,\n bufferMultiplier,\n );\n\n return [bufferedGas, simulationFails, estimatedGas];\n}\n\n/**\n * Determine if the gas for the provided request should be fixed.\n *\n * @param options - The options object.\n * @param options.ethQuery - The EthQuery instance to interact with the network.\n * @param options.txMeta - The transaction meta object.\n * @param options.isCustomNetwork - Whether the network is a custom network.\n * @returns Whether the gas should be fixed.\n */\nasync function requiresFixedGas({\n ethQuery,\n txMeta,\n isCustomNetwork,\n}: UpdateGasRequest): Promise<boolean> {\n const {\n txParams: { to, data },\n } = txMeta;\n\n if (isCustomNetwork || !to || data) {\n return false;\n }\n\n const code = await getCode(ethQuery, to);\n\n return !code || code === '0x';\n}\n\n/**\n * Get the contract code for the provided address.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @param address - The address to get the code for.\n * @returns The contract code.\n */\nasync function getCode(\n ethQuery: EthQuery,\n address: string,\n): Promise<string | undefined> {\n return await query(ethQuery, 'getCode', [address]);\n}\n\n/**\n * Get the latest block from the network.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @returns The latest block number.\n */\nasync function getLatestBlock(\n ethQuery: EthQuery,\n): Promise<{ gasLimit: string; number: string }> {\n return await query(ethQuery, 'getBlockByNumber', ['latest', false]);\n}\n"]}
1
+ {"version":3,"file":"gas.cjs","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BNToHex,\n fractionBN,\n hexToBN,\n query,\n} from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger, remove0x } from '@metamask/utils';\n\nimport { DELEGATION_PREFIX } from './eip7702';\nimport { simulateTransactions } from './simulation-api';\nimport { GAS_BUFFER_CHAIN_OVERRIDES } from '../constants';\nimport { projectLogger } from '../logger';\nimport {\n TransactionEnvelopeType,\n type TransactionMeta,\n type TransactionParams,\n} from '../types';\n\nexport type UpdateGasRequest = {\n chainId: Hex;\n ethQuery: EthQuery;\n isCustomNetwork: boolean;\n isSimulationEnabled: boolean;\n txMeta: TransactionMeta;\n};\n\nexport const log = createModuleLogger(projectLogger, 'gas');\n\nexport const FIXED_GAS = '0x5208';\nexport const DEFAULT_GAS_MULTIPLIER = 1.5;\nexport const GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;\nexport const MAX_GAS_BLOCK_PERCENT = 90;\nexport const INTRINSIC_GAS = 21000;\n\nexport const DUMMY_AUTHORIZATION_SIGNATURE =\n '0x1111111111111111111111111111111111111111111111111111111111111111';\n\n/**\n * Populate the gas properties of the provided transaction meta.\n *\n * @param request - The request object including the necessary parameters.\n */\nexport async function updateGas(request: UpdateGasRequest) {\n const { txMeta } = request;\n const initialParams = { ...txMeta.txParams };\n\n const [gas, simulationFails, gasLimitNoBuffer] = await getGas(request);\n\n txMeta.txParams.gas = gas;\n txMeta.simulationFails = simulationFails;\n txMeta.gasLimitNoBuffer = gasLimitNoBuffer;\n\n if (!initialParams.gas) {\n txMeta.originalGasEstimate = txMeta.txParams.gas;\n }\n\n if (!txMeta.defaultGasEstimates) {\n txMeta.defaultGasEstimates = {};\n }\n\n txMeta.defaultGasEstimates.gas = txMeta.txParams.gas;\n}\n\n/**\n * Estimate the gas for the provided transaction parameters.\n * If the gas estimate fails, the fallback value is returned.\n *\n * @param options - The options object.\n * @param options.chainId - The chain ID of the transaction.\n * @param options.ethQuery - The EthQuery instance to interact with the network.\n * @param options.isSimulationEnabled - Whether the simulation is enabled.\n * @param options.txParams - The transaction parameters.\n * @returns The estimated gas and related info.\n */\nexport async function estimateGas({\n chainId,\n ethQuery,\n isSimulationEnabled,\n txParams,\n}: {\n chainId: Hex;\n ethQuery: EthQuery;\n isSimulationEnabled: boolean;\n txParams: TransactionParams;\n}) {\n const request = { ...txParams };\n const { authorizationList, data, from, value, to } = request;\n\n const { gasLimit: blockGasLimit, number: blockNumber } =\n await getLatestBlock(ethQuery);\n\n const blockGasLimitBN = hexToBN(blockGasLimit);\n\n const fallback = BNToHex(\n fractionBN(blockGasLimitBN, GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT, 100),\n );\n\n request.data = data ? add0x(data) : data;\n request.value = value || '0x0';\n\n request.authorizationList = normalizeAuthorizationList(\n request.authorizationList,\n chainId,\n );\n\n delete request.gasPrice;\n delete request.maxFeePerGas;\n delete request.maxPriorityFeePerGas;\n\n let estimatedGas = fallback;\n let simulationFails: TransactionMeta['simulationFails'];\n\n const isUpgradeWithDataToSelf =\n txParams.type === TransactionEnvelopeType.setCode &&\n authorizationList?.length &&\n data &&\n data !== '0x' &&\n from?.toLowerCase() === to?.toLowerCase();\n\n try {\n if (isSimulationEnabled && isUpgradeWithDataToSelf) {\n estimatedGas = await estimateGasUpgradeWithDataToSelf(\n request,\n ethQuery,\n chainId,\n );\n } else {\n estimatedGas = await query(ethQuery, 'estimateGas', [request]);\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n simulationFails = {\n reason: error.message,\n errorKey: error.errorKey,\n debug: {\n blockNumber,\n blockGasLimit,\n },\n };\n\n log('Estimation failed', { ...simulationFails, fallback });\n }\n\n return {\n blockGasLimit,\n estimatedGas,\n simulationFails,\n };\n}\n\n/**\n * Add a buffer to the provided estimated gas.\n * The buffer is calculated based on the block gas limit and a multiplier.\n *\n * @param estimatedGas - The estimated gas.\n * @param blockGasLimit - The block gas limit.\n * @param multiplier - The multiplier to apply to the estimated gas.\n * @returns The gas with the buffer applied.\n */\nexport function addGasBuffer(\n estimatedGas: string,\n blockGasLimit: string,\n multiplier: number,\n) {\n const estimatedGasBN = hexToBN(estimatedGas);\n\n const maxGasBN = fractionBN(\n hexToBN(blockGasLimit),\n MAX_GAS_BLOCK_PERCENT,\n 100,\n );\n\n const paddedGasBN = fractionBN(estimatedGasBN, multiplier * 100, 100);\n\n if (estimatedGasBN.gt(maxGasBN)) {\n const estimatedGasHex = add0x(estimatedGas);\n log('Using estimated value', estimatedGasHex);\n return estimatedGasHex;\n }\n\n if (paddedGasBN.lt(maxGasBN)) {\n const paddedHex = add0x(BNToHex(paddedGasBN));\n log('Using padded estimate', paddedHex, multiplier);\n return paddedHex;\n }\n\n const maxHex = add0x(BNToHex(maxGasBN));\n log('Using 90% of block gas limit', maxHex);\n return maxHex;\n}\n\n/**\n * Determine the gas for the provided request.\n *\n * @param request - The request object including the necessary parameters.\n * @returns The final gas value and the estimate used.\n */\nasync function getGas(\n request: UpdateGasRequest,\n): Promise<[string, TransactionMeta['simulationFails']?, string?]> {\n const { chainId, isCustomNetwork, isSimulationEnabled, txMeta } = request;\n\n if (txMeta.txParams.gas) {\n log('Using value from request', txMeta.txParams.gas);\n return [txMeta.txParams.gas, undefined, txMeta.txParams.gas];\n }\n\n if (await requiresFixedGas(request)) {\n log('Using fixed value', FIXED_GAS);\n return [FIXED_GAS, undefined, FIXED_GAS];\n }\n\n const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas({\n chainId: request.chainId,\n ethQuery: request.ethQuery,\n isSimulationEnabled,\n txParams: txMeta.txParams,\n });\n\n if (isCustomNetwork || simulationFails) {\n log(\n isCustomNetwork\n ? 'Using original estimate as custom network'\n : 'Using original fallback estimate as simulation failed',\n );\n return [estimatedGas, simulationFails, estimatedGas];\n }\n\n const bufferMultiplier =\n GAS_BUFFER_CHAIN_OVERRIDES[\n chainId as keyof typeof GAS_BUFFER_CHAIN_OVERRIDES\n ] ?? DEFAULT_GAS_MULTIPLIER;\n\n const bufferedGas = addGasBuffer(\n estimatedGas,\n blockGasLimit,\n bufferMultiplier,\n );\n\n return [bufferedGas, simulationFails, estimatedGas];\n}\n\n/**\n * Determine if the gas for the provided request should be fixed.\n *\n * @param options - The options object.\n * @param options.ethQuery - The EthQuery instance to interact with the network.\n * @param options.txMeta - The transaction meta object.\n * @param options.isCustomNetwork - Whether the network is a custom network.\n * @returns Whether the gas should be fixed.\n */\nasync function requiresFixedGas({\n ethQuery,\n txMeta,\n isCustomNetwork,\n}: UpdateGasRequest): Promise<boolean> {\n const {\n txParams: { to, data },\n } = txMeta;\n\n if (isCustomNetwork || !to || data) {\n return false;\n }\n\n const code = await getCode(ethQuery, to);\n\n return !code || code === '0x';\n}\n\n/**\n * Get the contract code for the provided address.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @param address - The address to get the code for.\n * @returns The contract code.\n */\nasync function getCode(\n ethQuery: EthQuery,\n address: string,\n): Promise<string | undefined> {\n return await query(ethQuery, 'getCode', [address]);\n}\n\n/**\n * Get the latest block from the network.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @returns The latest block number.\n */\nasync function getLatestBlock(\n ethQuery: EthQuery,\n): Promise<{ gasLimit: string; number: string }> {\n return await query(ethQuery, 'getBlockByNumber', ['latest', false]);\n}\n\n/**\n * Estimate the gas for a type 4 transaction.\n *\n * @param txParams - The transaction parameters.\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @param chainId - The chain ID of the transaction.\n * @returns The estimated gas.\n */\nasync function estimateGasUpgradeWithDataToSelf(\n txParams: TransactionParams,\n ethQuery: EthQuery,\n chainId: Hex,\n) {\n const upgradeGas = await query(ethQuery, 'estimateGas', [\n {\n ...txParams,\n data: '0x',\n },\n ]);\n\n log('Upgrade only gas', upgradeGas);\n\n const delegationAddress = txParams.authorizationList?.[0].address as Hex;\n\n const executeGas = await simulateGas({\n chainId: chainId as Hex,\n delegationAddress,\n transaction: txParams,\n });\n\n log('Execute gas', executeGas);\n\n const total = BNToHex(\n hexToBN(upgradeGas).add(hexToBN(executeGas)).subn(INTRINSIC_GAS),\n );\n\n log('Total type 4 gas', total);\n\n return total;\n}\n\n/**\n * Simulate the required gas using the simulation API.\n *\n * @param options - The options object.\n * @param options.chainId - The chain ID of the transaction.\n * @param options.delegationAddress - The delegation address of the sender to mock.\n * @param options.transaction - The transaction parameters.\n * @returns The simulated gas.\n */\nasync function simulateGas({\n chainId,\n delegationAddress,\n transaction,\n}: {\n chainId: Hex;\n delegationAddress?: Hex;\n transaction: TransactionParams;\n}): Promise<Hex> {\n const response = await simulateTransactions(chainId, {\n transactions: [\n {\n to: transaction.to as Hex,\n from: transaction.from as Hex,\n data: transaction.data as Hex,\n value: transaction.value as Hex,\n },\n ],\n overrides: {\n [transaction.from as string]: {\n code:\n delegationAddress &&\n ((DELEGATION_PREFIX + remove0x(delegationAddress)) as Hex),\n },\n },\n });\n\n const gasUsed = response?.transactions?.[0].gasUsed;\n\n if (!gasUsed) {\n throw new Error('No simulated gas returned');\n }\n\n return gasUsed;\n}\n\n/**\n * Populate the authorization list with dummy values.\n *\n * @param authorizationList - The authorization list to prepare.\n * @param chainId - The chain ID to use.\n * @returns The authorization list with dummy values.\n */\nfunction normalizeAuthorizationList(\n authorizationList: TransactionParams['authorizationList'],\n chainId: Hex,\n) {\n return authorizationList?.map((authorization) => ({\n ...authorization,\n chainId: authorization.chainId ?? chainId,\n nonce: authorization.nonce ?? '0x1',\n r: authorization.r ?? DUMMY_AUTHORIZATION_SIGNATURE,\n s: authorization.s ?? DUMMY_AUTHORIZATION_SIGNATURE,\n yParity: authorization.yParity ?? '0x1',\n }));\n}\n"]}
@@ -1,11 +1,12 @@
1
1
  /// <reference types="debug" />
2
2
  import type EthQuery from "@metamask/eth-query";
3
3
  import type { Hex } from "@metamask/utils";
4
- import type { TransactionMeta, TransactionParams } from "../types.cjs";
4
+ import { type TransactionMeta, type TransactionParams } from "../types.cjs";
5
5
  export type UpdateGasRequest = {
6
+ chainId: Hex;
6
7
  ethQuery: EthQuery;
7
8
  isCustomNetwork: boolean;
8
- chainId: Hex;
9
+ isSimulationEnabled: boolean;
9
10
  txMeta: TransactionMeta;
10
11
  };
11
12
  export declare const log: import("debug").Debugger;
@@ -13,6 +14,8 @@ export declare const FIXED_GAS = "0x5208";
13
14
  export declare const DEFAULT_GAS_MULTIPLIER = 1.5;
14
15
  export declare const GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;
15
16
  export declare const MAX_GAS_BLOCK_PERCENT = 90;
17
+ export declare const INTRINSIC_GAS = 21000;
18
+ export declare const DUMMY_AUTHORIZATION_SIGNATURE = "0x1111111111111111111111111111111111111111111111111111111111111111";
16
19
  /**
17
20
  * Populate the gas properties of the provided transaction meta.
18
21
  *
@@ -23,11 +26,19 @@ export declare function updateGas(request: UpdateGasRequest): Promise<void>;
23
26
  * Estimate the gas for the provided transaction parameters.
24
27
  * If the gas estimate fails, the fallback value is returned.
25
28
  *
26
- * @param txParams - The transaction parameters.
27
- * @param ethQuery - The EthQuery instance to interact with the network.
29
+ * @param options - The options object.
30
+ * @param options.chainId - The chain ID of the transaction.
31
+ * @param options.ethQuery - The EthQuery instance to interact with the network.
32
+ * @param options.isSimulationEnabled - Whether the simulation is enabled.
33
+ * @param options.txParams - The transaction parameters.
28
34
  * @returns The estimated gas and related info.
29
35
  */
30
- export declare function estimateGas(txParams: TransactionParams, ethQuery: EthQuery): Promise<{
36
+ export declare function estimateGas({ chainId, ethQuery, isSimulationEnabled, txParams, }: {
37
+ chainId: Hex;
38
+ ethQuery: EthQuery;
39
+ isSimulationEnabled: boolean;
40
+ txParams: TransactionParams;
41
+ }): Promise<{
31
42
  blockGasLimit: string;
32
43
  estimatedGas: `0x${string}`;
33
44
  simulationFails: {
@@ -1 +1 @@
1
- {"version":3,"file":"gas.d.cts","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":";AAMA,OAAO,KAAK,QAAQ,4BAA4B;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAiB;AAEnE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,GAAG,0BAA2C,CAAC;AAE5D,eAAO,MAAM,SAAS,WAAW,CAAC;AAClC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,mCAAmC,KAAK,CAAC;AACtD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,iBAmBxD;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,iBAAiB,EAC3B,QAAQ,EAAE,QAAQ;;;;;;;;;;;GA6CnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,iBA2BnB"}
1
+ {"version":3,"file":"gas.d.cts","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":";AAMA,OAAO,KAAK,QAAQ,4BAA4B;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAO3C,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,qBAAiB;AAElB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,GAAG,0BAA2C,CAAC;AAE5D,eAAO,MAAM,SAAS,WAAW,CAAC;AAClC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,mCAAmC,KAAK,CAAC;AACtD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,aAAa,QAAQ,CAAC;AAEnC,eAAO,MAAM,6BAA6B,uEAC4B,CAAC;AAEvE;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,iBAmBxD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,EAChC,OAAO,EACP,QAAQ,EACR,mBAAmB,EACnB,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;;;;;;;;;;;GAgEA;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,iBA2BnB"}
@@ -1,11 +1,12 @@
1
1
  /// <reference types="debug" />
2
2
  import type EthQuery from "@metamask/eth-query";
3
3
  import type { Hex } from "@metamask/utils";
4
- import type { TransactionMeta, TransactionParams } from "../types.mjs";
4
+ import { type TransactionMeta, type TransactionParams } from "../types.mjs";
5
5
  export type UpdateGasRequest = {
6
+ chainId: Hex;
6
7
  ethQuery: EthQuery;
7
8
  isCustomNetwork: boolean;
8
- chainId: Hex;
9
+ isSimulationEnabled: boolean;
9
10
  txMeta: TransactionMeta;
10
11
  };
11
12
  export declare const log: import("debug").Debugger;
@@ -13,6 +14,8 @@ export declare const FIXED_GAS = "0x5208";
13
14
  export declare const DEFAULT_GAS_MULTIPLIER = 1.5;
14
15
  export declare const GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;
15
16
  export declare const MAX_GAS_BLOCK_PERCENT = 90;
17
+ export declare const INTRINSIC_GAS = 21000;
18
+ export declare const DUMMY_AUTHORIZATION_SIGNATURE = "0x1111111111111111111111111111111111111111111111111111111111111111";
16
19
  /**
17
20
  * Populate the gas properties of the provided transaction meta.
18
21
  *
@@ -23,11 +26,19 @@ export declare function updateGas(request: UpdateGasRequest): Promise<void>;
23
26
  * Estimate the gas for the provided transaction parameters.
24
27
  * If the gas estimate fails, the fallback value is returned.
25
28
  *
26
- * @param txParams - The transaction parameters.
27
- * @param ethQuery - The EthQuery instance to interact with the network.
29
+ * @param options - The options object.
30
+ * @param options.chainId - The chain ID of the transaction.
31
+ * @param options.ethQuery - The EthQuery instance to interact with the network.
32
+ * @param options.isSimulationEnabled - Whether the simulation is enabled.
33
+ * @param options.txParams - The transaction parameters.
28
34
  * @returns The estimated gas and related info.
29
35
  */
30
- export declare function estimateGas(txParams: TransactionParams, ethQuery: EthQuery): Promise<{
36
+ export declare function estimateGas({ chainId, ethQuery, isSimulationEnabled, txParams, }: {
37
+ chainId: Hex;
38
+ ethQuery: EthQuery;
39
+ isSimulationEnabled: boolean;
40
+ txParams: TransactionParams;
41
+ }): Promise<{
31
42
  blockGasLimit: string;
32
43
  estimatedGas: `0x${string}`;
33
44
  simulationFails: {
@@ -1 +1 @@
1
- {"version":3,"file":"gas.d.mts","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":";AAMA,OAAO,KAAK,QAAQ,4BAA4B;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAiB;AAEnE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,GAAG,0BAA2C,CAAC;AAE5D,eAAO,MAAM,SAAS,WAAW,CAAC;AAClC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,mCAAmC,KAAK,CAAC;AACtD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,iBAmBxD;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,iBAAiB,EAC3B,QAAQ,EAAE,QAAQ;;;;;;;;;;;GA6CnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,iBA2BnB"}
1
+ {"version":3,"file":"gas.d.mts","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":";AAMA,OAAO,KAAK,QAAQ,4BAA4B;AAChD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAO3C,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,qBAAiB;AAElB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,GAAG,0BAA2C,CAAC;AAE5D,eAAO,MAAM,SAAS,WAAW,CAAC;AAClC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,mCAAmC,KAAK,CAAC;AACtD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,aAAa,QAAQ,CAAC;AAEnC,eAAO,MAAM,6BAA6B,uEAC4B,CAAC;AAEvE;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,iBAmBxD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAAC,EAChC,OAAO,EACP,QAAQ,EACR,mBAAmB,EACnB,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;;;;;;;;;;;GAgEA;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,iBA2BnB"}
@@ -1,12 +1,17 @@
1
1
  import { BNToHex, fractionBN, hexToBN, query } from "@metamask/controller-utils";
2
- import { add0x, createModuleLogger } from "@metamask/utils";
2
+ import { add0x, createModuleLogger, remove0x } from "@metamask/utils";
3
+ import { DELEGATION_PREFIX } from "./eip7702.mjs";
4
+ import { simulateTransactions } from "./simulation-api.mjs";
3
5
  import { GAS_BUFFER_CHAIN_OVERRIDES } from "../constants.mjs";
4
6
  import { projectLogger } from "../logger.mjs";
7
+ import { TransactionEnvelopeType } from "../types.mjs";
5
8
  export const log = createModuleLogger(projectLogger, 'gas');
6
9
  export const FIXED_GAS = '0x5208';
7
10
  export const DEFAULT_GAS_MULTIPLIER = 1.5;
8
11
  export const GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;
9
12
  export const MAX_GAS_BLOCK_PERCENT = 90;
13
+ export const INTRINSIC_GAS = 21000;
14
+ export const DUMMY_AUTHORIZATION_SIGNATURE = '0x1111111111111111111111111111111111111111111111111111111111111111';
10
15
  /**
11
16
  * Populate the gas properties of the provided transaction meta.
12
17
  *
@@ -31,25 +36,39 @@ export async function updateGas(request) {
31
36
  * Estimate the gas for the provided transaction parameters.
32
37
  * If the gas estimate fails, the fallback value is returned.
33
38
  *
34
- * @param txParams - The transaction parameters.
35
- * @param ethQuery - The EthQuery instance to interact with the network.
39
+ * @param options - The options object.
40
+ * @param options.chainId - The chain ID of the transaction.
41
+ * @param options.ethQuery - The EthQuery instance to interact with the network.
42
+ * @param options.isSimulationEnabled - Whether the simulation is enabled.
43
+ * @param options.txParams - The transaction parameters.
36
44
  * @returns The estimated gas and related info.
37
45
  */
38
- export async function estimateGas(txParams, ethQuery) {
46
+ export async function estimateGas({ chainId, ethQuery, isSimulationEnabled, txParams, }) {
39
47
  const request = { ...txParams };
40
- const { data, value } = request;
48
+ const { authorizationList, data, from, value, to } = request;
41
49
  const { gasLimit: blockGasLimit, number: blockNumber } = await getLatestBlock(ethQuery);
42
50
  const blockGasLimitBN = hexToBN(blockGasLimit);
43
51
  const fallback = BNToHex(fractionBN(blockGasLimitBN, GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT, 100));
44
52
  request.data = data ? add0x(data) : data;
45
53
  request.value = value || '0x0';
54
+ request.authorizationList = normalizeAuthorizationList(request.authorizationList, chainId);
46
55
  delete request.gasPrice;
47
56
  delete request.maxFeePerGas;
48
57
  delete request.maxPriorityFeePerGas;
49
58
  let estimatedGas = fallback;
50
59
  let simulationFails;
60
+ const isUpgradeWithDataToSelf = txParams.type === TransactionEnvelopeType.setCode &&
61
+ authorizationList?.length &&
62
+ data &&
63
+ data !== '0x' &&
64
+ from?.toLowerCase() === to?.toLowerCase();
51
65
  try {
52
- estimatedGas = await query(ethQuery, 'estimateGas', [request]);
66
+ if (isSimulationEnabled && isUpgradeWithDataToSelf) {
67
+ estimatedGas = await estimateGasUpgradeWithDataToSelf(request, ethQuery, chainId);
68
+ }
69
+ else {
70
+ estimatedGas = await query(ethQuery, 'estimateGas', [request]);
71
+ }
53
72
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
73
  }
55
74
  catch (error) {
@@ -103,7 +122,7 @@ export function addGasBuffer(estimatedGas, blockGasLimit, multiplier) {
103
122
  * @returns The final gas value and the estimate used.
104
123
  */
105
124
  async function getGas(request) {
106
- const { isCustomNetwork, chainId, txMeta } = request;
125
+ const { chainId, isCustomNetwork, isSimulationEnabled, txMeta } = request;
107
126
  if (txMeta.txParams.gas) {
108
127
  log('Using value from request', txMeta.txParams.gas);
109
128
  return [txMeta.txParams.gas, undefined, txMeta.txParams.gas];
@@ -112,7 +131,12 @@ async function getGas(request) {
112
131
  log('Using fixed value', FIXED_GAS);
113
132
  return [FIXED_GAS, undefined, FIXED_GAS];
114
133
  }
115
- const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas(txMeta.txParams, request.ethQuery);
134
+ const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas({
135
+ chainId: request.chainId,
136
+ ethQuery: request.ethQuery,
137
+ isSimulationEnabled,
138
+ txParams: txMeta.txParams,
139
+ });
116
140
  if (isCustomNetwork || simulationFails) {
117
141
  log(isCustomNetwork
118
142
  ? 'Using original estimate as custom network'
@@ -159,4 +183,80 @@ async function getCode(ethQuery, address) {
159
183
  async function getLatestBlock(ethQuery) {
160
184
  return await query(ethQuery, 'getBlockByNumber', ['latest', false]);
161
185
  }
186
+ /**
187
+ * Estimate the gas for a type 4 transaction.
188
+ *
189
+ * @param txParams - The transaction parameters.
190
+ * @param ethQuery - The EthQuery instance to interact with the network.
191
+ * @param chainId - The chain ID of the transaction.
192
+ * @returns The estimated gas.
193
+ */
194
+ async function estimateGasUpgradeWithDataToSelf(txParams, ethQuery, chainId) {
195
+ const upgradeGas = await query(ethQuery, 'estimateGas', [
196
+ {
197
+ ...txParams,
198
+ data: '0x',
199
+ },
200
+ ]);
201
+ log('Upgrade only gas', upgradeGas);
202
+ const delegationAddress = txParams.authorizationList?.[0].address;
203
+ const executeGas = await simulateGas({
204
+ chainId: chainId,
205
+ delegationAddress,
206
+ transaction: txParams,
207
+ });
208
+ log('Execute gas', executeGas);
209
+ const total = BNToHex(hexToBN(upgradeGas).add(hexToBN(executeGas)).subn(INTRINSIC_GAS));
210
+ log('Total type 4 gas', total);
211
+ return total;
212
+ }
213
+ /**
214
+ * Simulate the required gas using the simulation API.
215
+ *
216
+ * @param options - The options object.
217
+ * @param options.chainId - The chain ID of the transaction.
218
+ * @param options.delegationAddress - The delegation address of the sender to mock.
219
+ * @param options.transaction - The transaction parameters.
220
+ * @returns The simulated gas.
221
+ */
222
+ async function simulateGas({ chainId, delegationAddress, transaction, }) {
223
+ const response = await simulateTransactions(chainId, {
224
+ transactions: [
225
+ {
226
+ to: transaction.to,
227
+ from: transaction.from,
228
+ data: transaction.data,
229
+ value: transaction.value,
230
+ },
231
+ ],
232
+ overrides: {
233
+ [transaction.from]: {
234
+ code: delegationAddress &&
235
+ (DELEGATION_PREFIX + remove0x(delegationAddress)),
236
+ },
237
+ },
238
+ });
239
+ const gasUsed = response?.transactions?.[0].gasUsed;
240
+ if (!gasUsed) {
241
+ throw new Error('No simulated gas returned');
242
+ }
243
+ return gasUsed;
244
+ }
245
+ /**
246
+ * Populate the authorization list with dummy values.
247
+ *
248
+ * @param authorizationList - The authorization list to prepare.
249
+ * @param chainId - The chain ID to use.
250
+ * @returns The authorization list with dummy values.
251
+ */
252
+ function normalizeAuthorizationList(authorizationList, chainId) {
253
+ return authorizationList?.map((authorization) => ({
254
+ ...authorization,
255
+ chainId: authorization.chainId ?? chainId,
256
+ nonce: authorization.nonce ?? '0x1',
257
+ r: authorization.r ?? DUMMY_AUTHORIZATION_SIGNATURE,
258
+ s: authorization.s ?? DUMMY_AUTHORIZATION_SIGNATURE,
259
+ yParity: authorization.yParity ?? '0x1',
260
+ }));
261
+ }
162
262
  //# sourceMappingURL=gas.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"gas.mjs","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BNToHex,\n fractionBN,\n hexToBN,\n query,\n} from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger } from '@metamask/utils';\n\nimport { GAS_BUFFER_CHAIN_OVERRIDES } from '../constants';\nimport { projectLogger } from '../logger';\nimport type { TransactionMeta, TransactionParams } from '../types';\n\nexport type UpdateGasRequest = {\n ethQuery: EthQuery;\n isCustomNetwork: boolean;\n chainId: Hex;\n txMeta: TransactionMeta;\n};\n\nexport const log = createModuleLogger(projectLogger, 'gas');\n\nexport const FIXED_GAS = '0x5208';\nexport const DEFAULT_GAS_MULTIPLIER = 1.5;\nexport const GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;\nexport const MAX_GAS_BLOCK_PERCENT = 90;\n\n/**\n * Populate the gas properties of the provided transaction meta.\n *\n * @param request - The request object including the necessary parameters.\n */\nexport async function updateGas(request: UpdateGasRequest) {\n const { txMeta } = request;\n const initialParams = { ...txMeta.txParams };\n\n const [gas, simulationFails, gasLimitNoBuffer] = await getGas(request);\n\n txMeta.txParams.gas = gas;\n txMeta.simulationFails = simulationFails;\n txMeta.gasLimitNoBuffer = gasLimitNoBuffer;\n\n if (!initialParams.gas) {\n txMeta.originalGasEstimate = txMeta.txParams.gas;\n }\n\n if (!txMeta.defaultGasEstimates) {\n txMeta.defaultGasEstimates = {};\n }\n\n txMeta.defaultGasEstimates.gas = txMeta.txParams.gas;\n}\n\n/**\n * Estimate the gas for the provided transaction parameters.\n * If the gas estimate fails, the fallback value is returned.\n *\n * @param txParams - The transaction parameters.\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @returns The estimated gas and related info.\n */\nexport async function estimateGas(\n txParams: TransactionParams,\n ethQuery: EthQuery,\n) {\n const request = { ...txParams };\n const { data, value } = request;\n\n const { gasLimit: blockGasLimit, number: blockNumber } =\n await getLatestBlock(ethQuery);\n\n const blockGasLimitBN = hexToBN(blockGasLimit);\n\n const fallback = BNToHex(\n fractionBN(blockGasLimitBN, GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT, 100),\n );\n\n request.data = data ? add0x(data) : data;\n request.value = value || '0x0';\n\n delete request.gasPrice;\n delete request.maxFeePerGas;\n delete request.maxPriorityFeePerGas;\n\n let estimatedGas = fallback;\n let simulationFails: TransactionMeta['simulationFails'];\n\n try {\n estimatedGas = await query(ethQuery, 'estimateGas', [request]);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n simulationFails = {\n reason: error.message,\n errorKey: error.errorKey,\n debug: {\n blockNumber,\n blockGasLimit,\n },\n };\n\n log('Estimation failed', { ...simulationFails, fallback });\n }\n\n return {\n blockGasLimit,\n estimatedGas,\n simulationFails,\n };\n}\n\n/**\n * Add a buffer to the provided estimated gas.\n * The buffer is calculated based on the block gas limit and a multiplier.\n *\n * @param estimatedGas - The estimated gas.\n * @param blockGasLimit - The block gas limit.\n * @param multiplier - The multiplier to apply to the estimated gas.\n * @returns The gas with the buffer applied.\n */\nexport function addGasBuffer(\n estimatedGas: string,\n blockGasLimit: string,\n multiplier: number,\n) {\n const estimatedGasBN = hexToBN(estimatedGas);\n\n const maxGasBN = fractionBN(\n hexToBN(blockGasLimit),\n MAX_GAS_BLOCK_PERCENT,\n 100,\n );\n\n const paddedGasBN = fractionBN(estimatedGasBN, multiplier * 100, 100);\n\n if (estimatedGasBN.gt(maxGasBN)) {\n const estimatedGasHex = add0x(estimatedGas);\n log('Using estimated value', estimatedGasHex);\n return estimatedGasHex;\n }\n\n if (paddedGasBN.lt(maxGasBN)) {\n const paddedHex = add0x(BNToHex(paddedGasBN));\n log('Using padded estimate', paddedHex, multiplier);\n return paddedHex;\n }\n\n const maxHex = add0x(BNToHex(maxGasBN));\n log('Using 90% of block gas limit', maxHex);\n return maxHex;\n}\n\n/**\n * Determine the gas for the provided request.\n *\n * @param request - The request object including the necessary parameters.\n * @returns The final gas value and the estimate used.\n */\nasync function getGas(\n request: UpdateGasRequest,\n): Promise<[string, TransactionMeta['simulationFails']?, string?]> {\n const { isCustomNetwork, chainId, txMeta } = request;\n\n if (txMeta.txParams.gas) {\n log('Using value from request', txMeta.txParams.gas);\n return [txMeta.txParams.gas, undefined, txMeta.txParams.gas];\n }\n\n if (await requiresFixedGas(request)) {\n log('Using fixed value', FIXED_GAS);\n return [FIXED_GAS, undefined, FIXED_GAS];\n }\n\n const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas(\n txMeta.txParams,\n request.ethQuery,\n );\n\n if (isCustomNetwork || simulationFails) {\n log(\n isCustomNetwork\n ? 'Using original estimate as custom network'\n : 'Using original fallback estimate as simulation failed',\n );\n return [estimatedGas, simulationFails, estimatedGas];\n }\n\n const bufferMultiplier =\n GAS_BUFFER_CHAIN_OVERRIDES[\n chainId as keyof typeof GAS_BUFFER_CHAIN_OVERRIDES\n ] ?? DEFAULT_GAS_MULTIPLIER;\n\n const bufferedGas = addGasBuffer(\n estimatedGas,\n blockGasLimit,\n bufferMultiplier,\n );\n\n return [bufferedGas, simulationFails, estimatedGas];\n}\n\n/**\n * Determine if the gas for the provided request should be fixed.\n *\n * @param options - The options object.\n * @param options.ethQuery - The EthQuery instance to interact with the network.\n * @param options.txMeta - The transaction meta object.\n * @param options.isCustomNetwork - Whether the network is a custom network.\n * @returns Whether the gas should be fixed.\n */\nasync function requiresFixedGas({\n ethQuery,\n txMeta,\n isCustomNetwork,\n}: UpdateGasRequest): Promise<boolean> {\n const {\n txParams: { to, data },\n } = txMeta;\n\n if (isCustomNetwork || !to || data) {\n return false;\n }\n\n const code = await getCode(ethQuery, to);\n\n return !code || code === '0x';\n}\n\n/**\n * Get the contract code for the provided address.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @param address - The address to get the code for.\n * @returns The contract code.\n */\nasync function getCode(\n ethQuery: EthQuery,\n address: string,\n): Promise<string | undefined> {\n return await query(ethQuery, 'getCode', [address]);\n}\n\n/**\n * Get the latest block from the network.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @returns The latest block number.\n */\nasync function getLatestBlock(\n ethQuery: EthQuery,\n): Promise<{ gasLimit: string; number: string }> {\n return await query(ethQuery, 'getBlockByNumber', ['latest', false]);\n}\n"]}
1
+ {"version":3,"file":"gas.mjs","sourceRoot":"","sources":["../../src/utils/gas.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BNToHex,\n fractionBN,\n hexToBN,\n query,\n} from '@metamask/controller-utils';\nimport type EthQuery from '@metamask/eth-query';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger, remove0x } from '@metamask/utils';\n\nimport { DELEGATION_PREFIX } from './eip7702';\nimport { simulateTransactions } from './simulation-api';\nimport { GAS_BUFFER_CHAIN_OVERRIDES } from '../constants';\nimport { projectLogger } from '../logger';\nimport {\n TransactionEnvelopeType,\n type TransactionMeta,\n type TransactionParams,\n} from '../types';\n\nexport type UpdateGasRequest = {\n chainId: Hex;\n ethQuery: EthQuery;\n isCustomNetwork: boolean;\n isSimulationEnabled: boolean;\n txMeta: TransactionMeta;\n};\n\nexport const log = createModuleLogger(projectLogger, 'gas');\n\nexport const FIXED_GAS = '0x5208';\nexport const DEFAULT_GAS_MULTIPLIER = 1.5;\nexport const GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT = 35;\nexport const MAX_GAS_BLOCK_PERCENT = 90;\nexport const INTRINSIC_GAS = 21000;\n\nexport const DUMMY_AUTHORIZATION_SIGNATURE =\n '0x1111111111111111111111111111111111111111111111111111111111111111';\n\n/**\n * Populate the gas properties of the provided transaction meta.\n *\n * @param request - The request object including the necessary parameters.\n */\nexport async function updateGas(request: UpdateGasRequest) {\n const { txMeta } = request;\n const initialParams = { ...txMeta.txParams };\n\n const [gas, simulationFails, gasLimitNoBuffer] = await getGas(request);\n\n txMeta.txParams.gas = gas;\n txMeta.simulationFails = simulationFails;\n txMeta.gasLimitNoBuffer = gasLimitNoBuffer;\n\n if (!initialParams.gas) {\n txMeta.originalGasEstimate = txMeta.txParams.gas;\n }\n\n if (!txMeta.defaultGasEstimates) {\n txMeta.defaultGasEstimates = {};\n }\n\n txMeta.defaultGasEstimates.gas = txMeta.txParams.gas;\n}\n\n/**\n * Estimate the gas for the provided transaction parameters.\n * If the gas estimate fails, the fallback value is returned.\n *\n * @param options - The options object.\n * @param options.chainId - The chain ID of the transaction.\n * @param options.ethQuery - The EthQuery instance to interact with the network.\n * @param options.isSimulationEnabled - Whether the simulation is enabled.\n * @param options.txParams - The transaction parameters.\n * @returns The estimated gas and related info.\n */\nexport async function estimateGas({\n chainId,\n ethQuery,\n isSimulationEnabled,\n txParams,\n}: {\n chainId: Hex;\n ethQuery: EthQuery;\n isSimulationEnabled: boolean;\n txParams: TransactionParams;\n}) {\n const request = { ...txParams };\n const { authorizationList, data, from, value, to } = request;\n\n const { gasLimit: blockGasLimit, number: blockNumber } =\n await getLatestBlock(ethQuery);\n\n const blockGasLimitBN = hexToBN(blockGasLimit);\n\n const fallback = BNToHex(\n fractionBN(blockGasLimitBN, GAS_ESTIMATE_FALLBACK_BLOCK_PERCENT, 100),\n );\n\n request.data = data ? add0x(data) : data;\n request.value = value || '0x0';\n\n request.authorizationList = normalizeAuthorizationList(\n request.authorizationList,\n chainId,\n );\n\n delete request.gasPrice;\n delete request.maxFeePerGas;\n delete request.maxPriorityFeePerGas;\n\n let estimatedGas = fallback;\n let simulationFails: TransactionMeta['simulationFails'];\n\n const isUpgradeWithDataToSelf =\n txParams.type === TransactionEnvelopeType.setCode &&\n authorizationList?.length &&\n data &&\n data !== '0x' &&\n from?.toLowerCase() === to?.toLowerCase();\n\n try {\n if (isSimulationEnabled && isUpgradeWithDataToSelf) {\n estimatedGas = await estimateGasUpgradeWithDataToSelf(\n request,\n ethQuery,\n chainId,\n );\n } else {\n estimatedGas = await query(ethQuery, 'estimateGas', [request]);\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n simulationFails = {\n reason: error.message,\n errorKey: error.errorKey,\n debug: {\n blockNumber,\n blockGasLimit,\n },\n };\n\n log('Estimation failed', { ...simulationFails, fallback });\n }\n\n return {\n blockGasLimit,\n estimatedGas,\n simulationFails,\n };\n}\n\n/**\n * Add a buffer to the provided estimated gas.\n * The buffer is calculated based on the block gas limit and a multiplier.\n *\n * @param estimatedGas - The estimated gas.\n * @param blockGasLimit - The block gas limit.\n * @param multiplier - The multiplier to apply to the estimated gas.\n * @returns The gas with the buffer applied.\n */\nexport function addGasBuffer(\n estimatedGas: string,\n blockGasLimit: string,\n multiplier: number,\n) {\n const estimatedGasBN = hexToBN(estimatedGas);\n\n const maxGasBN = fractionBN(\n hexToBN(blockGasLimit),\n MAX_GAS_BLOCK_PERCENT,\n 100,\n );\n\n const paddedGasBN = fractionBN(estimatedGasBN, multiplier * 100, 100);\n\n if (estimatedGasBN.gt(maxGasBN)) {\n const estimatedGasHex = add0x(estimatedGas);\n log('Using estimated value', estimatedGasHex);\n return estimatedGasHex;\n }\n\n if (paddedGasBN.lt(maxGasBN)) {\n const paddedHex = add0x(BNToHex(paddedGasBN));\n log('Using padded estimate', paddedHex, multiplier);\n return paddedHex;\n }\n\n const maxHex = add0x(BNToHex(maxGasBN));\n log('Using 90% of block gas limit', maxHex);\n return maxHex;\n}\n\n/**\n * Determine the gas for the provided request.\n *\n * @param request - The request object including the necessary parameters.\n * @returns The final gas value and the estimate used.\n */\nasync function getGas(\n request: UpdateGasRequest,\n): Promise<[string, TransactionMeta['simulationFails']?, string?]> {\n const { chainId, isCustomNetwork, isSimulationEnabled, txMeta } = request;\n\n if (txMeta.txParams.gas) {\n log('Using value from request', txMeta.txParams.gas);\n return [txMeta.txParams.gas, undefined, txMeta.txParams.gas];\n }\n\n if (await requiresFixedGas(request)) {\n log('Using fixed value', FIXED_GAS);\n return [FIXED_GAS, undefined, FIXED_GAS];\n }\n\n const { blockGasLimit, estimatedGas, simulationFails } = await estimateGas({\n chainId: request.chainId,\n ethQuery: request.ethQuery,\n isSimulationEnabled,\n txParams: txMeta.txParams,\n });\n\n if (isCustomNetwork || simulationFails) {\n log(\n isCustomNetwork\n ? 'Using original estimate as custom network'\n : 'Using original fallback estimate as simulation failed',\n );\n return [estimatedGas, simulationFails, estimatedGas];\n }\n\n const bufferMultiplier =\n GAS_BUFFER_CHAIN_OVERRIDES[\n chainId as keyof typeof GAS_BUFFER_CHAIN_OVERRIDES\n ] ?? DEFAULT_GAS_MULTIPLIER;\n\n const bufferedGas = addGasBuffer(\n estimatedGas,\n blockGasLimit,\n bufferMultiplier,\n );\n\n return [bufferedGas, simulationFails, estimatedGas];\n}\n\n/**\n * Determine if the gas for the provided request should be fixed.\n *\n * @param options - The options object.\n * @param options.ethQuery - The EthQuery instance to interact with the network.\n * @param options.txMeta - The transaction meta object.\n * @param options.isCustomNetwork - Whether the network is a custom network.\n * @returns Whether the gas should be fixed.\n */\nasync function requiresFixedGas({\n ethQuery,\n txMeta,\n isCustomNetwork,\n}: UpdateGasRequest): Promise<boolean> {\n const {\n txParams: { to, data },\n } = txMeta;\n\n if (isCustomNetwork || !to || data) {\n return false;\n }\n\n const code = await getCode(ethQuery, to);\n\n return !code || code === '0x';\n}\n\n/**\n * Get the contract code for the provided address.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @param address - The address to get the code for.\n * @returns The contract code.\n */\nasync function getCode(\n ethQuery: EthQuery,\n address: string,\n): Promise<string | undefined> {\n return await query(ethQuery, 'getCode', [address]);\n}\n\n/**\n * Get the latest block from the network.\n *\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @returns The latest block number.\n */\nasync function getLatestBlock(\n ethQuery: EthQuery,\n): Promise<{ gasLimit: string; number: string }> {\n return await query(ethQuery, 'getBlockByNumber', ['latest', false]);\n}\n\n/**\n * Estimate the gas for a type 4 transaction.\n *\n * @param txParams - The transaction parameters.\n * @param ethQuery - The EthQuery instance to interact with the network.\n * @param chainId - The chain ID of the transaction.\n * @returns The estimated gas.\n */\nasync function estimateGasUpgradeWithDataToSelf(\n txParams: TransactionParams,\n ethQuery: EthQuery,\n chainId: Hex,\n) {\n const upgradeGas = await query(ethQuery, 'estimateGas', [\n {\n ...txParams,\n data: '0x',\n },\n ]);\n\n log('Upgrade only gas', upgradeGas);\n\n const delegationAddress = txParams.authorizationList?.[0].address as Hex;\n\n const executeGas = await simulateGas({\n chainId: chainId as Hex,\n delegationAddress,\n transaction: txParams,\n });\n\n log('Execute gas', executeGas);\n\n const total = BNToHex(\n hexToBN(upgradeGas).add(hexToBN(executeGas)).subn(INTRINSIC_GAS),\n );\n\n log('Total type 4 gas', total);\n\n return total;\n}\n\n/**\n * Simulate the required gas using the simulation API.\n *\n * @param options - The options object.\n * @param options.chainId - The chain ID of the transaction.\n * @param options.delegationAddress - The delegation address of the sender to mock.\n * @param options.transaction - The transaction parameters.\n * @returns The simulated gas.\n */\nasync function simulateGas({\n chainId,\n delegationAddress,\n transaction,\n}: {\n chainId: Hex;\n delegationAddress?: Hex;\n transaction: TransactionParams;\n}): Promise<Hex> {\n const response = await simulateTransactions(chainId, {\n transactions: [\n {\n to: transaction.to as Hex,\n from: transaction.from as Hex,\n data: transaction.data as Hex,\n value: transaction.value as Hex,\n },\n ],\n overrides: {\n [transaction.from as string]: {\n code:\n delegationAddress &&\n ((DELEGATION_PREFIX + remove0x(delegationAddress)) as Hex),\n },\n },\n });\n\n const gasUsed = response?.transactions?.[0].gasUsed;\n\n if (!gasUsed) {\n throw new Error('No simulated gas returned');\n }\n\n return gasUsed;\n}\n\n/**\n * Populate the authorization list with dummy values.\n *\n * @param authorizationList - The authorization list to prepare.\n * @param chainId - The chain ID to use.\n * @returns The authorization list with dummy values.\n */\nfunction normalizeAuthorizationList(\n authorizationList: TransactionParams['authorizationList'],\n chainId: Hex,\n) {\n return authorizationList?.map((authorization) => ({\n ...authorization,\n chainId: authorization.chainId ?? chainId,\n nonce: authorization.nonce ?? '0x1',\n r: authorization.r ?? DUMMY_AUTHORIZATION_SIGNATURE,\n s: authorization.s ?? DUMMY_AUTHORIZATION_SIGNATURE,\n yParity: authorization.yParity ?? '0x1',\n }));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"simulation-api.cjs","sourceRoot":"","sources":["../../src/utils/simulation-api.ts"],"names":[],"mappings":";;;AAAA,iEAAiE;AACjE,2CAA+D;AAE/D,0CAA8E;AAC9E,0CAA0C;AAE1C,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,gBAAgB,CAAC,CAAC;AAEhE,MAAM,UAAU,GAAG,6BAA6B,CAAC;AACjD,MAAM,QAAQ,GAAG,6CAA6C,CAAC;AAC/D,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAgJrC,IAAI,gBAAgB,GAAG,CAAC,CAAC;AAEzB;;;;;;GAMG;AACI,KAAK,UAAU,oBAAoB,CACxC,OAAY,EACZ,OAA0B;IAE1B,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE5C,GAAG,CAAC,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAErC,MAAM,SAAS,GAAG,gBAAgB,CAAC;IACnC,gBAAgB,IAAI,CAAC,CAAC;IAEtB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,CAAC,OAAO,CAAC;SAClB,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAE3C,GAAG,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;IAEvC,IAAI,YAAY,CAAC,KAAK,EAAE;QACtB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC;QAC7C,MAAM,IAAI,wBAAe,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;KAC1C;IAED,OAAO,YAAY,EAAE,MAAM,CAAC;AAC9B,CAAC;AA/BD,oDA+BC;AAED;;;;;GAKG;AACH,KAAK,UAAU,gBAAgB,CAAC,OAAY;IAC1C,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAG,IAAA,sCAAmB,EAAC,OAAO,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE;QAC3B,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,yCAAgC,CAAC,OAAO,CAAC,CAAC;KACrD;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc;IAC3B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,iBAAiB,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,SAAS,MAAM,CAAC,SAAiB;IAC/B,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { convertHexToDecimal } from '@metamask/controller-utils';\nimport { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { SimulationChainNotSupportedError, SimulationError } from '../errors';\nimport { projectLogger } from '../logger';\n\nconst log = createModuleLogger(projectLogger, 'simulation-api');\n\nconst RPC_METHOD = 'infura_simulateTransactions';\nconst BASE_URL = 'https://tx-sentinel-{0}.api.cx.metamask.io/';\nconst ENDPOINT_NETWORKS = 'networks';\n\n/** Single transaction to simulate in a simulation API request. */\nexport type SimulationRequestTransaction = {\n /** Data to send with the transaction. */\n data?: Hex;\n\n /** Sender of the transaction. */\n from: Hex;\n\n /** Gas limit for the transaction. */\n gas?: Hex;\n\n /** Maximum fee per gas for the transaction. */\n maxFeePerGas?: Hex;\n\n /** Maximum priority fee per gas for the transaction. */\n maxPriorityFeePerGas?: Hex;\n\n /** Recipient of the transaction. */\n to?: Hex;\n\n /** Value to send with the transaction. */\n value?: Hex;\n};\n\n/** Request to the simulation API to simulate transactions. */\nexport type SimulationRequest = {\n /**\n * Transactions to be sequentially simulated.\n * State changes impact subsequent transactions in the list.\n */\n transactions: SimulationRequestTransaction[];\n\n blockOverrides?: {\n time?: Hex;\n };\n\n /**\n * Overrides to the state of the blockchain, keyed by smart contract address.\n */\n overrides?: {\n [address: Hex]: {\n /** Overrides to the storage slots for a smart contract account. */\n stateDiff: {\n [slot: Hex]: Hex;\n };\n };\n };\n\n /**\n * Whether to include call traces in the response.\n * Defaults to false.\n */\n withCallTrace?: boolean;\n\n /**\n * Whether to include event logs in the response.\n * Defaults to false.\n */\n withLogs?: boolean;\n};\n\n/** Raw event log emitted by a simulated transaction. */\nexport type SimulationResponseLog = {\n /** Address of the account that created the event. */\n address: Hex;\n\n /** Raw data in the event that is not indexed. */\n data: Hex;\n\n /** Raw indexed data from the event. */\n topics: Hex[];\n};\n\n/** Call trace of a single simulated transaction. */\nexport type SimulationResponseCallTrace = {\n /** Nested calls. */\n calls: SimulationResponseCallTrace[];\n\n /** Raw event logs created by the call. */\n logs: SimulationResponseLog[];\n};\n\n/**\n * Changes to the blockchain state.\n * Keyed by account address.\n */\nexport type SimulationResponseStateDiff = {\n [address: Hex]: {\n /** Native balance of the account. */\n balance?: Hex;\n\n /** Nonce of the account. */\n nonce?: Hex;\n\n /** Storage values per slot. */\n storage?: {\n [slot: Hex]: Hex;\n };\n };\n};\n\n/** Response from the simulation API for a single transaction. */\nexport type SimulationResponseTransaction = {\n /** An error message indicating the transaction could not be simulated. */\n error?: string;\n\n /** Return value of the transaction, such as the balance if calling balanceOf. */\n return: Hex;\n\n /** Hierarchy of call data including nested calls and logs. */\n callTrace?: SimulationResponseCallTrace;\n\n /** Changes to the blockchain state. */\n stateDiff?: {\n /** Initial blockchain state before the transaction. */\n pre?: SimulationResponseStateDiff;\n\n /** Updated blockchain state after the transaction. */\n post?: SimulationResponseStateDiff;\n };\n};\n\n/** Response from the simulation API. */\nexport type SimulationResponse = {\n /** Simulation data for each transaction in the request. */\n transactions: SimulationResponseTransaction[];\n};\n\n/** Data for a network supported by the Simulation API. */\ntype SimulationNetwork = {\n /** Subdomain of the API for the network. */\n network: string;\n\n /** Whether the network supports confirmation simulations. */\n confirmations: boolean;\n};\n\n/** Response from the simulation API containing supported networks. */\ntype SimulationNetworkResponse = {\n [chainIdDecimal: string]: SimulationNetwork;\n};\n\nlet requestIdCounter = 0;\n\n/**\n * Simulate transactions using the transaction simulation API.\n *\n * @param chainId - The chain ID to simulate transactions on.\n * @param request - The request to simulate transactions.\n * @returns The response from the simulation API.\n */\nexport async function simulateTransactions(\n chainId: Hex,\n request: SimulationRequest,\n): Promise<SimulationResponse> {\n const url = await getSimulationUrl(chainId);\n\n log('Sending request', url, request);\n\n const requestId = requestIdCounter;\n requestIdCounter += 1;\n\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n id: String(requestId),\n jsonrpc: '2.0',\n method: RPC_METHOD,\n params: [request],\n }),\n });\n\n const responseJson = await response.json();\n\n log('Received response', responseJson);\n\n if (responseJson.error) {\n const { code, message } = responseJson.error;\n throw new SimulationError(message, code);\n }\n\n return responseJson?.result;\n}\n\n/**\n * Get the URL for the transaction simulation API.\n *\n * @param chainId - The chain ID to get the URL for.\n * @returns The URL for the transaction simulation API.\n */\nasync function getSimulationUrl(chainId: Hex): Promise<string> {\n const networkData = await getNetworkData();\n const chainIdDecimal = convertHexToDecimal(chainId);\n const network = networkData[chainIdDecimal];\n\n if (!network?.confirmations) {\n log('Chain is not supported', chainId);\n throw new SimulationChainNotSupportedError(chainId);\n }\n\n return getUrl(network.network);\n}\n\n/**\n * Retrieve the supported network data from the simulation API.\n *\n * @returns The network data response from the simulation API.\n */\nasync function getNetworkData(): Promise<SimulationNetworkResponse> {\n const url = `${getUrl('ethereum-mainnet')}${ENDPOINT_NETWORKS}`;\n const response = await fetch(url);\n return response.json();\n}\n\n/**\n * Generate the URL for the specified subdomain in the simulation API.\n *\n * @param subdomain - The subdomain to generate the URL for.\n * @returns The URL for the transaction simulation API.\n */\nfunction getUrl(subdomain: string): string {\n return BASE_URL.replace('{0}', subdomain);\n}\n"]}
1
+ {"version":3,"file":"simulation-api.cjs","sourceRoot":"","sources":["../../src/utils/simulation-api.ts"],"names":[],"mappings":";;;AAAA,iEAAiE;AACjE,2CAA+D;AAE/D,0CAA8E;AAC9E,0CAA0C;AAE1C,MAAM,GAAG,GAAG,IAAA,0BAAkB,EAAC,sBAAa,EAAE,gBAAgB,CAAC,CAAC;AAEhE,MAAM,UAAU,GAAG,6BAA6B,CAAC;AACjD,MAAM,QAAQ,GAAG,6CAA6C,CAAC;AAC/D,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAsJrC,IAAI,gBAAgB,GAAG,CAAC,CAAC;AAEzB;;;;;;GAMG;AACI,KAAK,UAAU,oBAAoB,CACxC,OAAY,EACZ,OAA0B;IAE1B,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE5C,GAAG,CAAC,iBAAiB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IAErC,MAAM,SAAS,GAAG,gBAAgB,CAAC;IACnC,gBAAgB,IAAI,CAAC,CAAC;IAEtB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;YACrB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,CAAC,OAAO,CAAC;SAClB,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAE3C,GAAG,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;IAEvC,IAAI,YAAY,CAAC,KAAK,EAAE;QACtB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC;QAC7C,MAAM,IAAI,wBAAe,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;KAC1C;IAED,OAAO,YAAY,EAAE,MAAM,CAAC;AAC9B,CAAC;AA/BD,oDA+BC;AAED;;;;;GAKG;AACH,KAAK,UAAU,gBAAgB,CAAC,OAAY;IAC1C,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAG,IAAA,sCAAmB,EAAC,OAAO,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE;QAC3B,GAAG,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,yCAAgC,CAAC,OAAO,CAAC,CAAC;KACrD;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc;IAC3B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,kBAAkB,CAAC,GAAG,iBAAiB,EAAE,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,SAAS,MAAM,CAAC,SAAiB;IAC/B,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["import { convertHexToDecimal } from '@metamask/controller-utils';\nimport { createModuleLogger, type Hex } from '@metamask/utils';\n\nimport { SimulationChainNotSupportedError, SimulationError } from '../errors';\nimport { projectLogger } from '../logger';\n\nconst log = createModuleLogger(projectLogger, 'simulation-api');\n\nconst RPC_METHOD = 'infura_simulateTransactions';\nconst BASE_URL = 'https://tx-sentinel-{0}.api.cx.metamask.io/';\nconst ENDPOINT_NETWORKS = 'networks';\n\n/** Single transaction to simulate in a simulation API request. */\nexport type SimulationRequestTransaction = {\n /** Data to send with the transaction. */\n data?: Hex;\n\n /** Sender of the transaction. */\n from: Hex;\n\n /** Gas limit for the transaction. */\n gas?: Hex;\n\n /** Maximum fee per gas for the transaction. */\n maxFeePerGas?: Hex;\n\n /** Maximum priority fee per gas for the transaction. */\n maxPriorityFeePerGas?: Hex;\n\n /** Recipient of the transaction. */\n to?: Hex;\n\n /** Value to send with the transaction. */\n value?: Hex;\n};\n\n/** Request to the simulation API to simulate transactions. */\nexport type SimulationRequest = {\n /**\n * Transactions to be sequentially simulated.\n * State changes impact subsequent transactions in the list.\n */\n transactions: SimulationRequestTransaction[];\n\n blockOverrides?: {\n time?: Hex;\n };\n\n /**\n * Overrides to the state of the blockchain, keyed by address.\n */\n overrides?: {\n [address: Hex]: {\n /** Override the code for an address. */\n code?: Hex;\n\n /** Overrides to the storage slots for an address. */\n stateDiff?: {\n [slot: Hex]: Hex;\n };\n };\n };\n\n /**\n * Whether to include call traces in the response.\n * Defaults to false.\n */\n withCallTrace?: boolean;\n\n /**\n * Whether to include event logs in the response.\n * Defaults to false.\n */\n withLogs?: boolean;\n};\n\n/** Raw event log emitted by a simulated transaction. */\nexport type SimulationResponseLog = {\n /** Address of the account that created the event. */\n address: Hex;\n\n /** Raw data in the event that is not indexed. */\n data: Hex;\n\n /** Raw indexed data from the event. */\n topics: Hex[];\n};\n\n/** Call trace of a single simulated transaction. */\nexport type SimulationResponseCallTrace = {\n /** Nested calls. */\n calls: SimulationResponseCallTrace[];\n\n /** Raw event logs created by the call. */\n logs: SimulationResponseLog[];\n};\n\n/**\n * Changes to the blockchain state.\n * Keyed by account address.\n */\nexport type SimulationResponseStateDiff = {\n [address: Hex]: {\n /** Native balance of the account. */\n balance?: Hex;\n\n /** Nonce of the account. */\n nonce?: Hex;\n\n /** Storage values per slot. */\n storage?: {\n [slot: Hex]: Hex;\n };\n };\n};\n\n/** Response from the simulation API for a single transaction. */\nexport type SimulationResponseTransaction = {\n /** Hierarchy of call data including nested calls and logs. */\n callTrace?: SimulationResponseCallTrace;\n\n /** An error message indicating the transaction could not be simulated. */\n error?: string;\n\n /** The total gas used by the transaction. */\n gasUsed?: Hex;\n\n /** Return value of the transaction, such as the balance if calling balanceOf. */\n return: Hex;\n\n /** Changes to the blockchain state. */\n stateDiff?: {\n /** Initial blockchain state before the transaction. */\n pre?: SimulationResponseStateDiff;\n\n /** Updated blockchain state after the transaction. */\n post?: SimulationResponseStateDiff;\n };\n};\n\n/** Response from the simulation API. */\nexport type SimulationResponse = {\n /** Simulation data for each transaction in the request. */\n transactions: SimulationResponseTransaction[];\n};\n\n/** Data for a network supported by the Simulation API. */\ntype SimulationNetwork = {\n /** Subdomain of the API for the network. */\n network: string;\n\n /** Whether the network supports confirmation simulations. */\n confirmations: boolean;\n};\n\n/** Response from the simulation API containing supported networks. */\ntype SimulationNetworkResponse = {\n [chainIdDecimal: string]: SimulationNetwork;\n};\n\nlet requestIdCounter = 0;\n\n/**\n * Simulate transactions using the transaction simulation API.\n *\n * @param chainId - The chain ID to simulate transactions on.\n * @param request - The request to simulate transactions.\n * @returns The response from the simulation API.\n */\nexport async function simulateTransactions(\n chainId: Hex,\n request: SimulationRequest,\n): Promise<SimulationResponse> {\n const url = await getSimulationUrl(chainId);\n\n log('Sending request', url, request);\n\n const requestId = requestIdCounter;\n requestIdCounter += 1;\n\n const response = await fetch(url, {\n method: 'POST',\n body: JSON.stringify({\n id: String(requestId),\n jsonrpc: '2.0',\n method: RPC_METHOD,\n params: [request],\n }),\n });\n\n const responseJson = await response.json();\n\n log('Received response', responseJson);\n\n if (responseJson.error) {\n const { code, message } = responseJson.error;\n throw new SimulationError(message, code);\n }\n\n return responseJson?.result;\n}\n\n/**\n * Get the URL for the transaction simulation API.\n *\n * @param chainId - The chain ID to get the URL for.\n * @returns The URL for the transaction simulation API.\n */\nasync function getSimulationUrl(chainId: Hex): Promise<string> {\n const networkData = await getNetworkData();\n const chainIdDecimal = convertHexToDecimal(chainId);\n const network = networkData[chainIdDecimal];\n\n if (!network?.confirmations) {\n log('Chain is not supported', chainId);\n throw new SimulationChainNotSupportedError(chainId);\n }\n\n return getUrl(network.network);\n}\n\n/**\n * Retrieve the supported network data from the simulation API.\n *\n * @returns The network data response from the simulation API.\n */\nasync function getNetworkData(): Promise<SimulationNetworkResponse> {\n const url = `${getUrl('ethereum-mainnet')}${ENDPOINT_NETWORKS}`;\n const response = await fetch(url);\n return response.json();\n}\n\n/**\n * Generate the URL for the specified subdomain in the simulation API.\n *\n * @param subdomain - The subdomain to generate the URL for.\n * @returns The URL for the transaction simulation API.\n */\nfunction getUrl(subdomain: string): string {\n return BASE_URL.replace('{0}', subdomain);\n}\n"]}