@metamask/transaction-controller 62.2.0 → 62.3.1

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.
@@ -97,7 +97,10 @@ async function checkGasFeeTokenBeforePublish({ ethQuery, fetchGasFeeTokens, tran
97
97
  });
98
98
  return;
99
99
  }
100
- const gasFeeTokens = await fetchGasFeeTokens(transaction);
100
+ const gasFeeTokens = await fetchGasFeeTokens({
101
+ ...transaction,
102
+ isExternalSign: true,
103
+ });
101
104
  updateTransaction(transaction.id, (tx) => {
102
105
  tx.gasFeeTokens = gasFeeTokens;
103
106
  tx.isExternalSign = true;
@@ -1 +1 @@
1
- {"version":3,"file":"gas-fee-tokens.cjs","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { isNativeBalanceSufficientForGas } from './balance';\nimport { ERROR_MESSAGE_NO_UPGRADE_CONTRACT } from './batch';\nimport { ERROR_MESSGE_PUBLIC_KEY, doesChainSupportEIP7702 } from './eip7702';\nimport { getEIP7702UpgradeContractAddress } from './feature-flags';\nimport type {\n GasFeeToken,\n TransactionControllerMessenger,\n TransactionMeta,\n} from '..';\nimport type { SimulationRequestTransaction } from '../api/simulation-api';\nimport {\n simulateTransactions,\n type SimulationResponse,\n type SimulationResponseTransaction,\n} from '../api/simulation-api';\nimport { projectLogger } from '../logger';\nimport type { GetSimulationConfig } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'gas-fee-tokens');\n\nexport type GetGasFeeTokensRequest = {\n chainId: Hex;\n isEIP7702GasFeeTokensEnabled: (\n transactionMeta: TransactionMeta,\n ) => Promise<boolean>;\n getSimulationConfig: GetSimulationConfig;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n transactionMeta: TransactionMeta;\n};\n\n/**\n * Get gas fee tokens for a transaction.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID of the transaction.\n * @param request.isEIP7702GasFeeTokensEnabled - Callback to check if EIP-7702 gas fee tokens are enabled.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - Public key to validate EIP-7702 contract signatures.\n * @param request.transactionMeta - The transaction metadata.\n * @param request.getSimulationConfig - Optional transaction simulation parameters.\n * @returns An array of gas fee tokens.\n */\nexport async function getGasFeeTokens({\n chainId,\n isEIP7702GasFeeTokensEnabled,\n messenger,\n publicKeyEIP7702,\n transactionMeta,\n getSimulationConfig,\n}: GetGasFeeTokensRequest) {\n const { delegationAddress, txParams } = transactionMeta;\n const { authorizationList: authorizationListRequest } = txParams;\n const data = txParams.data as Hex;\n const from = txParams.from as Hex;\n const to = txParams.to as Hex;\n const value = txParams.value as Hex;\n\n log('Request', { chainId, txParams });\n\n const is7702GasFeeTokensEnabled =\n await isEIP7702GasFeeTokensEnabled(transactionMeta);\n\n const with7702 =\n is7702GasFeeTokensEnabled && doesChainSupportEIP7702(chainId, messenger);\n\n let authorizationList:\n | SimulationRequestTransaction['authorizationList']\n | undefined = authorizationListRequest?.map((authorization) => ({\n address: authorization.address,\n from: from as Hex,\n }));\n\n if (with7702 && !delegationAddress && !authorizationList) {\n authorizationList = buildAuthorizationList({\n chainId,\n from: from as Hex,\n messenger,\n publicKeyEIP7702,\n });\n }\n\n try {\n const response = await simulateTransactions(chainId, {\n getSimulationConfig,\n transactions: [\n {\n authorizationList,\n data,\n from,\n to,\n value,\n },\n ],\n suggestFees: {\n withTransfer: true,\n withFeeTransfer: true,\n with7702,\n },\n });\n\n log('Response', response);\n\n const result = parseGasFeeTokens(response);\n\n log('Gas fee tokens', result);\n\n return result;\n } catch (error) {\n log('Failed to gas fee tokens', error);\n return { gasFeeTokens: [], isGasFeeSponsored: false };\n }\n}\n\n/**\n * Check and update gas fee token selection before publishing a transaction.\n *\n * @param request - Request object.\n * @param request.ethQuery - EthQuery instance.\n * @param request.fetchGasFeeTokens - Function to fetch gas fee tokens.\n * @param request.transaction - Transaction metadata.\n * @param request.updateTransaction - Function to update the transaction.\n */\nexport async function checkGasFeeTokenBeforePublish({\n ethQuery,\n fetchGasFeeTokens,\n transaction,\n updateTransaction,\n}: {\n ethQuery: EthQuery;\n fetchGasFeeTokens: (transaction: TransactionMeta) => Promise<GasFeeToken[]>;\n transaction: TransactionMeta;\n updateTransaction: (\n transactionId: string,\n fn: (tx: TransactionMeta) => void,\n ) => void;\n}) {\n const { isGasFeeTokenIgnoredIfBalance, selectedGasFeeToken } = transaction;\n\n if (!selectedGasFeeToken || !isGasFeeTokenIgnoredIfBalance) {\n return;\n }\n\n log('Checking gas fee token before publish', { selectedGasFeeToken });\n\n const hasNativeBalance = await isNativeBalanceSufficientForGas(\n transaction,\n ethQuery,\n );\n\n if (hasNativeBalance) {\n log(\n 'Ignoring gas fee token before publish due to sufficient native balance',\n );\n\n updateTransaction(transaction.id, (tx) => {\n tx.isExternalSign = false;\n tx.selectedGasFeeToken = undefined;\n });\n\n return;\n }\n\n const gasFeeTokens = await fetchGasFeeTokens(transaction);\n\n updateTransaction(transaction.id, (tx) => {\n tx.gasFeeTokens = gasFeeTokens;\n tx.isExternalSign = true;\n tx.txParams.nonce = undefined;\n });\n\n log('Updated gas fee tokens before publish', gasFeeTokens);\n\n if (\n !gasFeeTokens?.some(\n (t) => t.tokenAddress.toLowerCase() === selectedGasFeeToken.toLowerCase(),\n )\n ) {\n throw new Error('Gas fee token not found and insufficient native balance');\n }\n\n log('Publishing with selected gas fee token', { selectedGasFeeToken });\n}\n\n/**\n * Extract gas fee tokens from a simulation response.\n *\n * @param response - The simulation response.\n * @returns gasFeeTokens: An array of gas fee tokens. isGasFeeSponsored: Whether the transaction is sponsored\n */\nfunction parseGasFeeTokens(response: SimulationResponse): {\n gasFeeTokens: GasFeeToken[];\n isGasFeeSponsored: boolean;\n} {\n const feeLevel = response.transactions?.[0]\n ?.fees?.[0] as Required<SimulationResponseTransaction>['fees'][0];\n\n const isGasFeeSponsored = response.sponsorship?.isSponsored ?? false;\n\n const tokenFees = feeLevel?.tokenFees ?? [];\n\n return {\n gasFeeTokens: tokenFees.map((tokenFee) => ({\n amount: tokenFee.balanceNeededToken,\n balance: tokenFee.currentBalanceToken,\n decimals: tokenFee.token.decimals,\n fee: tokenFee.serviceFee,\n gas: feeLevel.gas,\n gasTransfer: tokenFee.transferEstimate,\n maxFeePerGas: feeLevel.maxFeePerGas,\n maxPriorityFeePerGas: feeLevel.maxPriorityFeePerGas,\n rateWei: tokenFee.rateWei,\n recipient: tokenFee.feeRecipient,\n symbol: tokenFee.token.symbol,\n tokenAddress: tokenFee.token.address,\n })),\n isGasFeeSponsored,\n };\n}\n\n/**\n * Generate the authorization list for the request.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID.\n * @param request.from - The sender's address.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - The public key for EIP-7702.\n * @returns The authorization list.\n */\nfunction buildAuthorizationList({\n chainId,\n from,\n messenger,\n publicKeyEIP7702,\n}: {\n chainId: Hex;\n from: Hex;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n}): SimulationRequestTransaction['authorizationList'] | undefined {\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal(ERROR_MESSGE_PUBLIC_KEY);\n }\n\n const upgradeAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeAddress) {\n throw rpcErrors.internal(ERROR_MESSAGE_NO_UPGRADE_CONTRACT);\n }\n\n return [\n {\n address: upgradeAddress,\n from: from as Hex,\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"gas-fee-tokens.cjs","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { isNativeBalanceSufficientForGas } from './balance';\nimport { ERROR_MESSAGE_NO_UPGRADE_CONTRACT } from './batch';\nimport { ERROR_MESSGE_PUBLIC_KEY, doesChainSupportEIP7702 } from './eip7702';\nimport { getEIP7702UpgradeContractAddress } from './feature-flags';\nimport type {\n GasFeeToken,\n TransactionControllerMessenger,\n TransactionMeta,\n} from '..';\nimport type { SimulationRequestTransaction } from '../api/simulation-api';\nimport {\n simulateTransactions,\n type SimulationResponse,\n type SimulationResponseTransaction,\n} from '../api/simulation-api';\nimport { projectLogger } from '../logger';\nimport type { GetSimulationConfig } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'gas-fee-tokens');\n\nexport type GetGasFeeTokensRequest = {\n chainId: Hex;\n isEIP7702GasFeeTokensEnabled: (\n transactionMeta: TransactionMeta,\n ) => Promise<boolean>;\n getSimulationConfig: GetSimulationConfig;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n transactionMeta: TransactionMeta;\n};\n\n/**\n * Get gas fee tokens for a transaction.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID of the transaction.\n * @param request.isEIP7702GasFeeTokensEnabled - Callback to check if EIP-7702 gas fee tokens are enabled.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - Public key to validate EIP-7702 contract signatures.\n * @param request.transactionMeta - The transaction metadata.\n * @param request.getSimulationConfig - Optional transaction simulation parameters.\n * @returns An array of gas fee tokens.\n */\nexport async function getGasFeeTokens({\n chainId,\n isEIP7702GasFeeTokensEnabled,\n messenger,\n publicKeyEIP7702,\n transactionMeta,\n getSimulationConfig,\n}: GetGasFeeTokensRequest) {\n const { delegationAddress, txParams } = transactionMeta;\n const { authorizationList: authorizationListRequest } = txParams;\n const data = txParams.data as Hex;\n const from = txParams.from as Hex;\n const to = txParams.to as Hex;\n const value = txParams.value as Hex;\n\n log('Request', { chainId, txParams });\n\n const is7702GasFeeTokensEnabled =\n await isEIP7702GasFeeTokensEnabled(transactionMeta);\n\n const with7702 =\n is7702GasFeeTokensEnabled && doesChainSupportEIP7702(chainId, messenger);\n\n let authorizationList:\n | SimulationRequestTransaction['authorizationList']\n | undefined = authorizationListRequest?.map((authorization) => ({\n address: authorization.address,\n from: from as Hex,\n }));\n\n if (with7702 && !delegationAddress && !authorizationList) {\n authorizationList = buildAuthorizationList({\n chainId,\n from: from as Hex,\n messenger,\n publicKeyEIP7702,\n });\n }\n\n try {\n const response = await simulateTransactions(chainId, {\n getSimulationConfig,\n transactions: [\n {\n authorizationList,\n data,\n from,\n to,\n value,\n },\n ],\n suggestFees: {\n withTransfer: true,\n withFeeTransfer: true,\n with7702,\n },\n });\n\n log('Response', response);\n\n const result = parseGasFeeTokens(response);\n\n log('Gas fee tokens', result);\n\n return result;\n } catch (error) {\n log('Failed to gas fee tokens', error);\n return { gasFeeTokens: [], isGasFeeSponsored: false };\n }\n}\n\n/**\n * Check and update gas fee token selection before publishing a transaction.\n *\n * @param request - Request object.\n * @param request.ethQuery - EthQuery instance.\n * @param request.fetchGasFeeTokens - Function to fetch gas fee tokens.\n * @param request.transaction - Transaction metadata.\n * @param request.updateTransaction - Function to update the transaction.\n */\nexport async function checkGasFeeTokenBeforePublish({\n ethQuery,\n fetchGasFeeTokens,\n transaction,\n updateTransaction,\n}: {\n ethQuery: EthQuery;\n fetchGasFeeTokens: (transaction: TransactionMeta) => Promise<GasFeeToken[]>;\n transaction: TransactionMeta;\n updateTransaction: (\n transactionId: string,\n fn: (tx: TransactionMeta) => void,\n ) => void;\n}) {\n const { isGasFeeTokenIgnoredIfBalance, selectedGasFeeToken } = transaction;\n\n if (!selectedGasFeeToken || !isGasFeeTokenIgnoredIfBalance) {\n return;\n }\n\n log('Checking gas fee token before publish', { selectedGasFeeToken });\n\n const hasNativeBalance = await isNativeBalanceSufficientForGas(\n transaction,\n ethQuery,\n );\n\n if (hasNativeBalance) {\n log(\n 'Ignoring gas fee token before publish due to sufficient native balance',\n );\n\n updateTransaction(transaction.id, (tx) => {\n tx.isExternalSign = false;\n tx.selectedGasFeeToken = undefined;\n });\n\n return;\n }\n\n const gasFeeTokens = await fetchGasFeeTokens({\n ...transaction,\n isExternalSign: true,\n });\n\n updateTransaction(transaction.id, (tx) => {\n tx.gasFeeTokens = gasFeeTokens;\n tx.isExternalSign = true;\n tx.txParams.nonce = undefined;\n });\n\n log('Updated gas fee tokens before publish', gasFeeTokens);\n\n if (\n !gasFeeTokens?.some(\n (t) => t.tokenAddress.toLowerCase() === selectedGasFeeToken.toLowerCase(),\n )\n ) {\n throw new Error('Gas fee token not found and insufficient native balance');\n }\n\n log('Publishing with selected gas fee token', { selectedGasFeeToken });\n}\n\n/**\n * Extract gas fee tokens from a simulation response.\n *\n * @param response - The simulation response.\n * @returns gasFeeTokens: An array of gas fee tokens. isGasFeeSponsored: Whether the transaction is sponsored\n */\nfunction parseGasFeeTokens(response: SimulationResponse): {\n gasFeeTokens: GasFeeToken[];\n isGasFeeSponsored: boolean;\n} {\n const feeLevel = response.transactions?.[0]\n ?.fees?.[0] as Required<SimulationResponseTransaction>['fees'][0];\n\n const isGasFeeSponsored = response.sponsorship?.isSponsored ?? false;\n\n const tokenFees = feeLevel?.tokenFees ?? [];\n\n return {\n gasFeeTokens: tokenFees.map((tokenFee) => ({\n amount: tokenFee.balanceNeededToken,\n balance: tokenFee.currentBalanceToken,\n decimals: tokenFee.token.decimals,\n fee: tokenFee.serviceFee,\n gas: feeLevel.gas,\n gasTransfer: tokenFee.transferEstimate,\n maxFeePerGas: feeLevel.maxFeePerGas,\n maxPriorityFeePerGas: feeLevel.maxPriorityFeePerGas,\n rateWei: tokenFee.rateWei,\n recipient: tokenFee.feeRecipient,\n symbol: tokenFee.token.symbol,\n tokenAddress: tokenFee.token.address,\n })),\n isGasFeeSponsored,\n };\n}\n\n/**\n * Generate the authorization list for the request.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID.\n * @param request.from - The sender's address.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - The public key for EIP-7702.\n * @returns The authorization list.\n */\nfunction buildAuthorizationList({\n chainId,\n from,\n messenger,\n publicKeyEIP7702,\n}: {\n chainId: Hex;\n from: Hex;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n}): SimulationRequestTransaction['authorizationList'] | undefined {\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal(ERROR_MESSGE_PUBLIC_KEY);\n }\n\n const upgradeAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeAddress) {\n throw rpcErrors.internal(ERROR_MESSAGE_NO_UPGRADE_CONTRACT);\n }\n\n return [\n {\n address: upgradeAddress,\n from: from as Hex,\n },\n ];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"gas-fee-tokens.d.cts","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAO3C,OAAO,KAAK,EACV,WAAW,EACX,8BAA8B,EAC9B,eAAe,EAChB,qBAAW;AAQZ,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAiB;AAIpD,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,4BAA4B,EAAE,CAC5B,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,EACpC,OAAO,EACP,4BAA4B,EAC5B,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,EAAE,sBAAsB;;;GA8DxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CAAC,EAClD,QAAQ,EACR,iBAAiB,EACjB,WAAW,EACX,iBAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5E,WAAW,EAAE,eAAe,CAAC;IAC7B,iBAAiB,EAAE,CACjB,aAAa,EAAE,MAAM,EACrB,EAAE,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,IAAI,KAC9B,IAAI,CAAC;CACX,iBA8CA"}
1
+ {"version":3,"file":"gas-fee-tokens.d.cts","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAO3C,OAAO,KAAK,EACV,WAAW,EACX,8BAA8B,EAC9B,eAAe,EAChB,qBAAW;AAQZ,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAiB;AAIpD,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,4BAA4B,EAAE,CAC5B,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,EACpC,OAAO,EACP,4BAA4B,EAC5B,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,EAAE,sBAAsB;;;GA8DxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CAAC,EAClD,QAAQ,EACR,iBAAiB,EACjB,WAAW,EACX,iBAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5E,WAAW,EAAE,eAAe,CAAC;IAC7B,iBAAiB,EAAE,CACjB,aAAa,EAAE,MAAM,EACrB,EAAE,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,IAAI,KAC9B,IAAI,CAAC;CACX,iBAiDA"}
@@ -1 +1 @@
1
- {"version":3,"file":"gas-fee-tokens.d.mts","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAO3C,OAAO,KAAK,EACV,WAAW,EACX,8BAA8B,EAC9B,eAAe,EAChB,qBAAW;AAQZ,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAiB;AAIpD,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,4BAA4B,EAAE,CAC5B,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,EACpC,OAAO,EACP,4BAA4B,EAC5B,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,EAAE,sBAAsB;;;GA8DxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CAAC,EAClD,QAAQ,EACR,iBAAiB,EACjB,WAAW,EACX,iBAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5E,WAAW,EAAE,eAAe,CAAC;IAC7B,iBAAiB,EAAE,CACjB,aAAa,EAAE,MAAM,EACrB,EAAE,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,IAAI,KAC9B,IAAI,CAAC;CACX,iBA8CA"}
1
+ {"version":3,"file":"gas-fee-tokens.d.mts","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,4BAA4B;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAO3C,OAAO,KAAK,EACV,WAAW,EACX,8BAA8B,EAC9B,eAAe,EAChB,qBAAW;AAQZ,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAiB;AAIpD,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,GAAG,CAAC;IACb,4BAA4B,EAAE,CAC5B,eAAe,EAAE,eAAe,KAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,8BAA8B,CAAC;IAC1C,gBAAgB,CAAC,EAAE,GAAG,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,EACpC,OAAO,EACP,4BAA4B,EAC5B,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,EAAE,sBAAsB;;;GA8DxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,6BAA6B,CAAC,EAClD,QAAQ,EACR,iBAAiB,EACjB,WAAW,EACX,iBAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5E,WAAW,EAAE,eAAe,CAAC;IAC7B,iBAAiB,EAAE,CACjB,aAAa,EAAE,MAAM,EACrB,EAAE,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,IAAI,KAC9B,IAAI,CAAC;CACX,iBAiDA"}
@@ -93,7 +93,10 @@ export async function checkGasFeeTokenBeforePublish({ ethQuery, fetchGasFeeToken
93
93
  });
94
94
  return;
95
95
  }
96
- const gasFeeTokens = await fetchGasFeeTokens(transaction);
96
+ const gasFeeTokens = await fetchGasFeeTokens({
97
+ ...transaction,
98
+ isExternalSign: true,
99
+ });
97
100
  updateTransaction(transaction.id, (tx) => {
98
101
  tx.gasFeeTokens = gasFeeTokens;
99
102
  tx.isExternalSign = true;
@@ -1 +1 @@
1
- {"version":3,"file":"gas-fee-tokens.mjs","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { isNativeBalanceSufficientForGas } from './balance';\nimport { ERROR_MESSAGE_NO_UPGRADE_CONTRACT } from './batch';\nimport { ERROR_MESSGE_PUBLIC_KEY, doesChainSupportEIP7702 } from './eip7702';\nimport { getEIP7702UpgradeContractAddress } from './feature-flags';\nimport type {\n GasFeeToken,\n TransactionControllerMessenger,\n TransactionMeta,\n} from '..';\nimport type { SimulationRequestTransaction } from '../api/simulation-api';\nimport {\n simulateTransactions,\n type SimulationResponse,\n type SimulationResponseTransaction,\n} from '../api/simulation-api';\nimport { projectLogger } from '../logger';\nimport type { GetSimulationConfig } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'gas-fee-tokens');\n\nexport type GetGasFeeTokensRequest = {\n chainId: Hex;\n isEIP7702GasFeeTokensEnabled: (\n transactionMeta: TransactionMeta,\n ) => Promise<boolean>;\n getSimulationConfig: GetSimulationConfig;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n transactionMeta: TransactionMeta;\n};\n\n/**\n * Get gas fee tokens for a transaction.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID of the transaction.\n * @param request.isEIP7702GasFeeTokensEnabled - Callback to check if EIP-7702 gas fee tokens are enabled.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - Public key to validate EIP-7702 contract signatures.\n * @param request.transactionMeta - The transaction metadata.\n * @param request.getSimulationConfig - Optional transaction simulation parameters.\n * @returns An array of gas fee tokens.\n */\nexport async function getGasFeeTokens({\n chainId,\n isEIP7702GasFeeTokensEnabled,\n messenger,\n publicKeyEIP7702,\n transactionMeta,\n getSimulationConfig,\n}: GetGasFeeTokensRequest) {\n const { delegationAddress, txParams } = transactionMeta;\n const { authorizationList: authorizationListRequest } = txParams;\n const data = txParams.data as Hex;\n const from = txParams.from as Hex;\n const to = txParams.to as Hex;\n const value = txParams.value as Hex;\n\n log('Request', { chainId, txParams });\n\n const is7702GasFeeTokensEnabled =\n await isEIP7702GasFeeTokensEnabled(transactionMeta);\n\n const with7702 =\n is7702GasFeeTokensEnabled && doesChainSupportEIP7702(chainId, messenger);\n\n let authorizationList:\n | SimulationRequestTransaction['authorizationList']\n | undefined = authorizationListRequest?.map((authorization) => ({\n address: authorization.address,\n from: from as Hex,\n }));\n\n if (with7702 && !delegationAddress && !authorizationList) {\n authorizationList = buildAuthorizationList({\n chainId,\n from: from as Hex,\n messenger,\n publicKeyEIP7702,\n });\n }\n\n try {\n const response = await simulateTransactions(chainId, {\n getSimulationConfig,\n transactions: [\n {\n authorizationList,\n data,\n from,\n to,\n value,\n },\n ],\n suggestFees: {\n withTransfer: true,\n withFeeTransfer: true,\n with7702,\n },\n });\n\n log('Response', response);\n\n const result = parseGasFeeTokens(response);\n\n log('Gas fee tokens', result);\n\n return result;\n } catch (error) {\n log('Failed to gas fee tokens', error);\n return { gasFeeTokens: [], isGasFeeSponsored: false };\n }\n}\n\n/**\n * Check and update gas fee token selection before publishing a transaction.\n *\n * @param request - Request object.\n * @param request.ethQuery - EthQuery instance.\n * @param request.fetchGasFeeTokens - Function to fetch gas fee tokens.\n * @param request.transaction - Transaction metadata.\n * @param request.updateTransaction - Function to update the transaction.\n */\nexport async function checkGasFeeTokenBeforePublish({\n ethQuery,\n fetchGasFeeTokens,\n transaction,\n updateTransaction,\n}: {\n ethQuery: EthQuery;\n fetchGasFeeTokens: (transaction: TransactionMeta) => Promise<GasFeeToken[]>;\n transaction: TransactionMeta;\n updateTransaction: (\n transactionId: string,\n fn: (tx: TransactionMeta) => void,\n ) => void;\n}) {\n const { isGasFeeTokenIgnoredIfBalance, selectedGasFeeToken } = transaction;\n\n if (!selectedGasFeeToken || !isGasFeeTokenIgnoredIfBalance) {\n return;\n }\n\n log('Checking gas fee token before publish', { selectedGasFeeToken });\n\n const hasNativeBalance = await isNativeBalanceSufficientForGas(\n transaction,\n ethQuery,\n );\n\n if (hasNativeBalance) {\n log(\n 'Ignoring gas fee token before publish due to sufficient native balance',\n );\n\n updateTransaction(transaction.id, (tx) => {\n tx.isExternalSign = false;\n tx.selectedGasFeeToken = undefined;\n });\n\n return;\n }\n\n const gasFeeTokens = await fetchGasFeeTokens(transaction);\n\n updateTransaction(transaction.id, (tx) => {\n tx.gasFeeTokens = gasFeeTokens;\n tx.isExternalSign = true;\n tx.txParams.nonce = undefined;\n });\n\n log('Updated gas fee tokens before publish', gasFeeTokens);\n\n if (\n !gasFeeTokens?.some(\n (t) => t.tokenAddress.toLowerCase() === selectedGasFeeToken.toLowerCase(),\n )\n ) {\n throw new Error('Gas fee token not found and insufficient native balance');\n }\n\n log('Publishing with selected gas fee token', { selectedGasFeeToken });\n}\n\n/**\n * Extract gas fee tokens from a simulation response.\n *\n * @param response - The simulation response.\n * @returns gasFeeTokens: An array of gas fee tokens. isGasFeeSponsored: Whether the transaction is sponsored\n */\nfunction parseGasFeeTokens(response: SimulationResponse): {\n gasFeeTokens: GasFeeToken[];\n isGasFeeSponsored: boolean;\n} {\n const feeLevel = response.transactions?.[0]\n ?.fees?.[0] as Required<SimulationResponseTransaction>['fees'][0];\n\n const isGasFeeSponsored = response.sponsorship?.isSponsored ?? false;\n\n const tokenFees = feeLevel?.tokenFees ?? [];\n\n return {\n gasFeeTokens: tokenFees.map((tokenFee) => ({\n amount: tokenFee.balanceNeededToken,\n balance: tokenFee.currentBalanceToken,\n decimals: tokenFee.token.decimals,\n fee: tokenFee.serviceFee,\n gas: feeLevel.gas,\n gasTransfer: tokenFee.transferEstimate,\n maxFeePerGas: feeLevel.maxFeePerGas,\n maxPriorityFeePerGas: feeLevel.maxPriorityFeePerGas,\n rateWei: tokenFee.rateWei,\n recipient: tokenFee.feeRecipient,\n symbol: tokenFee.token.symbol,\n tokenAddress: tokenFee.token.address,\n })),\n isGasFeeSponsored,\n };\n}\n\n/**\n * Generate the authorization list for the request.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID.\n * @param request.from - The sender's address.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - The public key for EIP-7702.\n * @returns The authorization list.\n */\nfunction buildAuthorizationList({\n chainId,\n from,\n messenger,\n publicKeyEIP7702,\n}: {\n chainId: Hex;\n from: Hex;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n}): SimulationRequestTransaction['authorizationList'] | undefined {\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal(ERROR_MESSGE_PUBLIC_KEY);\n }\n\n const upgradeAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeAddress) {\n throw rpcErrors.internal(ERROR_MESSAGE_NO_UPGRADE_CONTRACT);\n }\n\n return [\n {\n address: upgradeAddress,\n from: from as Hex,\n },\n ];\n}\n"]}
1
+ {"version":3,"file":"gas-fee-tokens.mjs","sourceRoot":"","sources":["../../src/utils/gas-fee-tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import type EthQuery from '@metamask/eth-query';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\n\nimport { isNativeBalanceSufficientForGas } from './balance';\nimport { ERROR_MESSAGE_NO_UPGRADE_CONTRACT } from './batch';\nimport { ERROR_MESSGE_PUBLIC_KEY, doesChainSupportEIP7702 } from './eip7702';\nimport { getEIP7702UpgradeContractAddress } from './feature-flags';\nimport type {\n GasFeeToken,\n TransactionControllerMessenger,\n TransactionMeta,\n} from '..';\nimport type { SimulationRequestTransaction } from '../api/simulation-api';\nimport {\n simulateTransactions,\n type SimulationResponse,\n type SimulationResponseTransaction,\n} from '../api/simulation-api';\nimport { projectLogger } from '../logger';\nimport type { GetSimulationConfig } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'gas-fee-tokens');\n\nexport type GetGasFeeTokensRequest = {\n chainId: Hex;\n isEIP7702GasFeeTokensEnabled: (\n transactionMeta: TransactionMeta,\n ) => Promise<boolean>;\n getSimulationConfig: GetSimulationConfig;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n transactionMeta: TransactionMeta;\n};\n\n/**\n * Get gas fee tokens for a transaction.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID of the transaction.\n * @param request.isEIP7702GasFeeTokensEnabled - Callback to check if EIP-7702 gas fee tokens are enabled.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - Public key to validate EIP-7702 contract signatures.\n * @param request.transactionMeta - The transaction metadata.\n * @param request.getSimulationConfig - Optional transaction simulation parameters.\n * @returns An array of gas fee tokens.\n */\nexport async function getGasFeeTokens({\n chainId,\n isEIP7702GasFeeTokensEnabled,\n messenger,\n publicKeyEIP7702,\n transactionMeta,\n getSimulationConfig,\n}: GetGasFeeTokensRequest) {\n const { delegationAddress, txParams } = transactionMeta;\n const { authorizationList: authorizationListRequest } = txParams;\n const data = txParams.data as Hex;\n const from = txParams.from as Hex;\n const to = txParams.to as Hex;\n const value = txParams.value as Hex;\n\n log('Request', { chainId, txParams });\n\n const is7702GasFeeTokensEnabled =\n await isEIP7702GasFeeTokensEnabled(transactionMeta);\n\n const with7702 =\n is7702GasFeeTokensEnabled && doesChainSupportEIP7702(chainId, messenger);\n\n let authorizationList:\n | SimulationRequestTransaction['authorizationList']\n | undefined = authorizationListRequest?.map((authorization) => ({\n address: authorization.address,\n from: from as Hex,\n }));\n\n if (with7702 && !delegationAddress && !authorizationList) {\n authorizationList = buildAuthorizationList({\n chainId,\n from: from as Hex,\n messenger,\n publicKeyEIP7702,\n });\n }\n\n try {\n const response = await simulateTransactions(chainId, {\n getSimulationConfig,\n transactions: [\n {\n authorizationList,\n data,\n from,\n to,\n value,\n },\n ],\n suggestFees: {\n withTransfer: true,\n withFeeTransfer: true,\n with7702,\n },\n });\n\n log('Response', response);\n\n const result = parseGasFeeTokens(response);\n\n log('Gas fee tokens', result);\n\n return result;\n } catch (error) {\n log('Failed to gas fee tokens', error);\n return { gasFeeTokens: [], isGasFeeSponsored: false };\n }\n}\n\n/**\n * Check and update gas fee token selection before publishing a transaction.\n *\n * @param request - Request object.\n * @param request.ethQuery - EthQuery instance.\n * @param request.fetchGasFeeTokens - Function to fetch gas fee tokens.\n * @param request.transaction - Transaction metadata.\n * @param request.updateTransaction - Function to update the transaction.\n */\nexport async function checkGasFeeTokenBeforePublish({\n ethQuery,\n fetchGasFeeTokens,\n transaction,\n updateTransaction,\n}: {\n ethQuery: EthQuery;\n fetchGasFeeTokens: (transaction: TransactionMeta) => Promise<GasFeeToken[]>;\n transaction: TransactionMeta;\n updateTransaction: (\n transactionId: string,\n fn: (tx: TransactionMeta) => void,\n ) => void;\n}) {\n const { isGasFeeTokenIgnoredIfBalance, selectedGasFeeToken } = transaction;\n\n if (!selectedGasFeeToken || !isGasFeeTokenIgnoredIfBalance) {\n return;\n }\n\n log('Checking gas fee token before publish', { selectedGasFeeToken });\n\n const hasNativeBalance = await isNativeBalanceSufficientForGas(\n transaction,\n ethQuery,\n );\n\n if (hasNativeBalance) {\n log(\n 'Ignoring gas fee token before publish due to sufficient native balance',\n );\n\n updateTransaction(transaction.id, (tx) => {\n tx.isExternalSign = false;\n tx.selectedGasFeeToken = undefined;\n });\n\n return;\n }\n\n const gasFeeTokens = await fetchGasFeeTokens({\n ...transaction,\n isExternalSign: true,\n });\n\n updateTransaction(transaction.id, (tx) => {\n tx.gasFeeTokens = gasFeeTokens;\n tx.isExternalSign = true;\n tx.txParams.nonce = undefined;\n });\n\n log('Updated gas fee tokens before publish', gasFeeTokens);\n\n if (\n !gasFeeTokens?.some(\n (t) => t.tokenAddress.toLowerCase() === selectedGasFeeToken.toLowerCase(),\n )\n ) {\n throw new Error('Gas fee token not found and insufficient native balance');\n }\n\n log('Publishing with selected gas fee token', { selectedGasFeeToken });\n}\n\n/**\n * Extract gas fee tokens from a simulation response.\n *\n * @param response - The simulation response.\n * @returns gasFeeTokens: An array of gas fee tokens. isGasFeeSponsored: Whether the transaction is sponsored\n */\nfunction parseGasFeeTokens(response: SimulationResponse): {\n gasFeeTokens: GasFeeToken[];\n isGasFeeSponsored: boolean;\n} {\n const feeLevel = response.transactions?.[0]\n ?.fees?.[0] as Required<SimulationResponseTransaction>['fees'][0];\n\n const isGasFeeSponsored = response.sponsorship?.isSponsored ?? false;\n\n const tokenFees = feeLevel?.tokenFees ?? [];\n\n return {\n gasFeeTokens: tokenFees.map((tokenFee) => ({\n amount: tokenFee.balanceNeededToken,\n balance: tokenFee.currentBalanceToken,\n decimals: tokenFee.token.decimals,\n fee: tokenFee.serviceFee,\n gas: feeLevel.gas,\n gasTransfer: tokenFee.transferEstimate,\n maxFeePerGas: feeLevel.maxFeePerGas,\n maxPriorityFeePerGas: feeLevel.maxPriorityFeePerGas,\n rateWei: tokenFee.rateWei,\n recipient: tokenFee.feeRecipient,\n symbol: tokenFee.token.symbol,\n tokenAddress: tokenFee.token.address,\n })),\n isGasFeeSponsored,\n };\n}\n\n/**\n * Generate the authorization list for the request.\n *\n * @param request - The request object.\n * @param request.chainId - The chain ID.\n * @param request.from - The sender's address.\n * @param request.messenger - The messenger instance.\n * @param request.publicKeyEIP7702 - The public key for EIP-7702.\n * @returns The authorization list.\n */\nfunction buildAuthorizationList({\n chainId,\n from,\n messenger,\n publicKeyEIP7702,\n}: {\n chainId: Hex;\n from: Hex;\n messenger: TransactionControllerMessenger;\n publicKeyEIP7702?: Hex;\n}): SimulationRequestTransaction['authorizationList'] | undefined {\n if (!publicKeyEIP7702) {\n throw rpcErrors.internal(ERROR_MESSGE_PUBLIC_KEY);\n }\n\n const upgradeAddress = getEIP7702UpgradeContractAddress(\n chainId,\n messenger,\n publicKeyEIP7702,\n );\n\n if (!upgradeAddress) {\n throw rpcErrors.internal(ERROR_MESSAGE_NO_UPGRADE_CONTRACT);\n }\n\n return [\n {\n address: upgradeAddress,\n from: from as Hex,\n },\n ];\n}\n"]}
@@ -14,6 +14,7 @@ const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, 'nonce');
14
14
  async function getNextNonce(txMeta, getNonceLock) {
15
15
  const { customNonceValue, isExternalSign, txParams: { from, nonce: existingNonce }, } = txMeta;
16
16
  if (isExternalSign) {
17
+ log('Skipping nonce as signed externally');
17
18
  return [undefined, undefined];
18
19
  }
19
20
  const customNonce = customNonceValue ? (0, controller_utils_1.toHex)(customNonceValue) : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"nonce.cjs","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":";;;AAAA,iEAAmD;AAMnD,0CAA8D;AAG9D,MAAM,GAAG,GAAG,IAAA,2BAAkB,EAAC,sBAAa,EAAE,OAAO,CAAC,CAAC;AAEvD;;;;;;GAMG;AACI,KAAK,UAAU,YAAY,CAChC,MAAuB,EACvB,YAAqD;IAErD,MAAM,EACJ,gBAAgB,EAChB,cAAc,EACd,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GACzC,GAAG,MAAM,CAAC;IAEX,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC,IAAA,wBAAK,EAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3E,IAAI,WAAW,EAAE,CAAC;QAChB,GAAG,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QACvC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,GAAG,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QAC3C,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAA,wBAAK,EAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1D,GAAG,CAAC,gCAAgC,EAAE,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IAErE,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC9B,CAAC;AAjCD,oCAiCC;AAED;;;;;;;;GAQG;AACH,SAAgB,uCAAuC,CACrD,cAAsB,EACtB,WAAmB,EACnB,mBAAwC,EACxC,YAA+B;IAE/B,OAAO,YAAY;SAChB,MAAM,CACL,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CACvE,CAAC,UAAU;QACX,CAAC,eAAe;QAChB,OAAO,KAAK,cAAc;QAC1B,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE,CACnD;SACA,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QACzD,4CAA4C;QAC5C,6DAA6D;QAC7D,kDAAkD;QAClD,0BAA0B;QAC1B,OAAO;YACL,MAAM;YACN,OAAO,EAAE,CAAC,EAAE,CAAC;YACb,QAAQ,EAAE;gBACR,IAAI,EAAE,IAAI,IAAI,EAAE;gBAChB,GAAG,EAAE,GAAG,IAAI,EAAE;gBACd,KAAK,EAAE,KAAK,IAAI,EAAE;gBAClB,KAAK,EAAE,KAAK,IAAI,EAAE;aACnB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC;AA/BD,0FA+BC","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type {\n NonceLock,\n Transaction as NonceTrackerTransaction,\n} from '@metamask/nonce-tracker';\n\nimport { createModuleLogger, projectLogger } from '../logger';\nimport type { TransactionMeta, TransactionStatus } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'nonce');\n\n/**\n * Determine the next nonce to be used for a transaction.\n *\n * @param txMeta - The transaction metadata.\n * @param getNonceLock - An anonymous function that acquires the nonce lock for an address\n * @returns The next hexadecimal nonce to be used for the given transaction, and optionally a function to release the nonce lock.\n */\nexport async function getNextNonce(\n txMeta: TransactionMeta,\n getNonceLock: (address: string) => Promise<NonceLock>,\n): Promise<[string | undefined, (() => void) | undefined]> {\n const {\n customNonceValue,\n isExternalSign,\n txParams: { from, nonce: existingNonce },\n } = txMeta;\n\n if (isExternalSign) {\n return [undefined, undefined];\n }\n\n const customNonce = customNonceValue ? toHex(customNonceValue) : undefined;\n\n if (customNonce) {\n log('Using custom nonce', customNonce);\n return [customNonce, undefined];\n }\n\n if (existingNonce) {\n log('Using existing nonce', existingNonce);\n return [existingNonce, undefined];\n }\n\n const nonceLock = await getNonceLock(from);\n const nonce = toHex(nonceLock.nextNonce);\n const releaseLock = nonceLock.releaseLock.bind(nonceLock);\n\n log('Using nonce from nonce tracker', nonce, nonceLock.nonceDetails);\n\n return [nonce, releaseLock];\n}\n\n/**\n * Filter and format transactions for the nonce tracker.\n *\n * @param currentChainId - Chain ID of the current network.\n * @param fromAddress - Address of the account from which the transactions to filter from are sent.\n * @param transactionStatuses - Status of the transactions for which to filter.\n * @param transactions - Array of transactionMeta objects that have been prefiltered.\n * @returns Array of transactions formatted for the nonce tracker.\n */\nexport function getAndFormatTransactionsForNonceTracker(\n currentChainId: string,\n fromAddress: string,\n transactionStatuses: TransactionStatus[],\n transactions: TransactionMeta[],\n): NonceTrackerTransaction[] {\n return transactions\n .filter(\n ({ chainId, isTransfer, isUserOperation, status, txParams: { from } }) =>\n !isTransfer &&\n !isUserOperation &&\n chainId === currentChainId &&\n transactionStatuses.includes(status) &&\n from.toLowerCase() === fromAddress.toLowerCase(),\n )\n .map(({ status, txParams: { from, gas, value, nonce } }) => {\n // the only value we care about is the nonce\n // but we need to return the other values to satisfy the type\n // TODO: refactor nonceTracker to not require this\n /* istanbul ignore next */\n return {\n status,\n history: [{}],\n txParams: {\n from: from ?? '',\n gas: gas ?? '',\n value: value ?? '',\n nonce: nonce ?? '',\n },\n };\n });\n}\n"]}
1
+ {"version":3,"file":"nonce.cjs","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":";;;AAAA,iEAAmD;AAMnD,0CAA8D;AAG9D,MAAM,GAAG,GAAG,IAAA,2BAAkB,EAAC,sBAAa,EAAE,OAAO,CAAC,CAAC;AAEvD;;;;;;GAMG;AACI,KAAK,UAAU,YAAY,CAChC,MAAuB,EACvB,YAAqD;IAErD,MAAM,EACJ,gBAAgB,EAChB,cAAc,EACd,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GACzC,GAAG,MAAM,CAAC;IAEX,IAAI,cAAc,EAAE,CAAC;QACnB,GAAG,CAAC,qCAAqC,CAAC,CAAC;QAC3C,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC,IAAA,wBAAK,EAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3E,IAAI,WAAW,EAAE,CAAC;QAChB,GAAG,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QACvC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,GAAG,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QAC3C,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAA,wBAAK,EAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1D,GAAG,CAAC,gCAAgC,EAAE,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IAErE,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC9B,CAAC;AAlCD,oCAkCC;AAED;;;;;;;;GAQG;AACH,SAAgB,uCAAuC,CACrD,cAAsB,EACtB,WAAmB,EACnB,mBAAwC,EACxC,YAA+B;IAE/B,OAAO,YAAY;SAChB,MAAM,CACL,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CACvE,CAAC,UAAU;QACX,CAAC,eAAe;QAChB,OAAO,KAAK,cAAc;QAC1B,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE,CACnD;SACA,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QACzD,4CAA4C;QAC5C,6DAA6D;QAC7D,kDAAkD;QAClD,0BAA0B;QAC1B,OAAO;YACL,MAAM;YACN,OAAO,EAAE,CAAC,EAAE,CAAC;YACb,QAAQ,EAAE;gBACR,IAAI,EAAE,IAAI,IAAI,EAAE;gBAChB,GAAG,EAAE,GAAG,IAAI,EAAE;gBACd,KAAK,EAAE,KAAK,IAAI,EAAE;gBAClB,KAAK,EAAE,KAAK,IAAI,EAAE;aACnB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC;AA/BD,0FA+BC","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type {\n NonceLock,\n Transaction as NonceTrackerTransaction,\n} from '@metamask/nonce-tracker';\n\nimport { createModuleLogger, projectLogger } from '../logger';\nimport type { TransactionMeta, TransactionStatus } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'nonce');\n\n/**\n * Determine the next nonce to be used for a transaction.\n *\n * @param txMeta - The transaction metadata.\n * @param getNonceLock - An anonymous function that acquires the nonce lock for an address\n * @returns The next hexadecimal nonce to be used for the given transaction, and optionally a function to release the nonce lock.\n */\nexport async function getNextNonce(\n txMeta: TransactionMeta,\n getNonceLock: (address: string) => Promise<NonceLock>,\n): Promise<[string | undefined, (() => void) | undefined]> {\n const {\n customNonceValue,\n isExternalSign,\n txParams: { from, nonce: existingNonce },\n } = txMeta;\n\n if (isExternalSign) {\n log('Skipping nonce as signed externally');\n return [undefined, undefined];\n }\n\n const customNonce = customNonceValue ? toHex(customNonceValue) : undefined;\n\n if (customNonce) {\n log('Using custom nonce', customNonce);\n return [customNonce, undefined];\n }\n\n if (existingNonce) {\n log('Using existing nonce', existingNonce);\n return [existingNonce, undefined];\n }\n\n const nonceLock = await getNonceLock(from);\n const nonce = toHex(nonceLock.nextNonce);\n const releaseLock = nonceLock.releaseLock.bind(nonceLock);\n\n log('Using nonce from nonce tracker', nonce, nonceLock.nonceDetails);\n\n return [nonce, releaseLock];\n}\n\n/**\n * Filter and format transactions for the nonce tracker.\n *\n * @param currentChainId - Chain ID of the current network.\n * @param fromAddress - Address of the account from which the transactions to filter from are sent.\n * @param transactionStatuses - Status of the transactions for which to filter.\n * @param transactions - Array of transactionMeta objects that have been prefiltered.\n * @returns Array of transactions formatted for the nonce tracker.\n */\nexport function getAndFormatTransactionsForNonceTracker(\n currentChainId: string,\n fromAddress: string,\n transactionStatuses: TransactionStatus[],\n transactions: TransactionMeta[],\n): NonceTrackerTransaction[] {\n return transactions\n .filter(\n ({ chainId, isTransfer, isUserOperation, status, txParams: { from } }) =>\n !isTransfer &&\n !isUserOperation &&\n chainId === currentChainId &&\n transactionStatuses.includes(status) &&\n from.toLowerCase() === fromAddress.toLowerCase(),\n )\n .map(({ status, txParams: { from, gas, value, nonce } }) => {\n // the only value we care about is the nonce\n // but we need to return the other values to satisfy the type\n // TODO: refactor nonceTracker to not require this\n /* istanbul ignore next */\n return {\n status,\n history: [{}],\n txParams: {\n from: from ?? '',\n gas: gas ?? '',\n value: value ?? '',\n nonce: nonce ?? '',\n },\n };\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"nonce.d.cts","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,IAAI,uBAAuB,EACvC,gCAAgC;AAGjC,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAiB;AAInE;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,GACpD,OAAO,CAAC,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CA8BzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,iBAAiB,EAAE,EACxC,YAAY,EAAE,eAAe,EAAE,GAC9B,uBAAuB,EAAE,CA0B3B"}
1
+ {"version":3,"file":"nonce.d.cts","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,IAAI,uBAAuB,EACvC,gCAAgC;AAGjC,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAiB;AAInE;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,GACpD,OAAO,CAAC,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CA+BzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,iBAAiB,EAAE,EACxC,YAAY,EAAE,eAAe,EAAE,GAC9B,uBAAuB,EAAE,CA0B3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"nonce.d.mts","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,IAAI,uBAAuB,EACvC,gCAAgC;AAGjC,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAiB;AAInE;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,GACpD,OAAO,CAAC,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CA8BzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,iBAAiB,EAAE,EACxC,YAAY,EAAE,eAAe,EAAE,GAC9B,uBAAuB,EAAE,CA0B3B"}
1
+ {"version":3,"file":"nonce.d.mts","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,IAAI,uBAAuB,EACvC,gCAAgC;AAGjC,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAiB;AAInE;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,GACpD,OAAO,CAAC,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CA+BzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,uCAAuC,CACrD,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,iBAAiB,EAAE,EACxC,YAAY,EAAE,eAAe,EAAE,GAC9B,uBAAuB,EAAE,CA0B3B"}
@@ -11,6 +11,7 @@ const log = createModuleLogger(projectLogger, 'nonce');
11
11
  export async function getNextNonce(txMeta, getNonceLock) {
12
12
  const { customNonceValue, isExternalSign, txParams: { from, nonce: existingNonce }, } = txMeta;
13
13
  if (isExternalSign) {
14
+ log('Skipping nonce as signed externally');
14
15
  return [undefined, undefined];
15
16
  }
16
17
  const customNonce = customNonceValue ? toHex(customNonceValue) : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"nonce.mjs","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,mCAAmC;AAMnD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,sBAAkB;AAG9D,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAuB,EACvB,YAAqD;IAErD,MAAM,EACJ,gBAAgB,EAChB,cAAc,EACd,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GACzC,GAAG,MAAM,CAAC;IAEX,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3E,IAAI,WAAW,EAAE,CAAC;QAChB,GAAG,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QACvC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,GAAG,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QAC3C,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1D,GAAG,CAAC,gCAAgC,EAAE,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IAErE,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uCAAuC,CACrD,cAAsB,EACtB,WAAmB,EACnB,mBAAwC,EACxC,YAA+B;IAE/B,OAAO,YAAY;SAChB,MAAM,CACL,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CACvE,CAAC,UAAU;QACX,CAAC,eAAe;QAChB,OAAO,KAAK,cAAc;QAC1B,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE,CACnD;SACA,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QACzD,4CAA4C;QAC5C,6DAA6D;QAC7D,kDAAkD;QAClD,0BAA0B;QAC1B,OAAO;YACL,MAAM;YACN,OAAO,EAAE,CAAC,EAAE,CAAC;YACb,QAAQ,EAAE;gBACR,IAAI,EAAE,IAAI,IAAI,EAAE;gBAChB,GAAG,EAAE,GAAG,IAAI,EAAE;gBACd,KAAK,EAAE,KAAK,IAAI,EAAE;gBAClB,KAAK,EAAE,KAAK,IAAI,EAAE;aACnB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type {\n NonceLock,\n Transaction as NonceTrackerTransaction,\n} from '@metamask/nonce-tracker';\n\nimport { createModuleLogger, projectLogger } from '../logger';\nimport type { TransactionMeta, TransactionStatus } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'nonce');\n\n/**\n * Determine the next nonce to be used for a transaction.\n *\n * @param txMeta - The transaction metadata.\n * @param getNonceLock - An anonymous function that acquires the nonce lock for an address\n * @returns The next hexadecimal nonce to be used for the given transaction, and optionally a function to release the nonce lock.\n */\nexport async function getNextNonce(\n txMeta: TransactionMeta,\n getNonceLock: (address: string) => Promise<NonceLock>,\n): Promise<[string | undefined, (() => void) | undefined]> {\n const {\n customNonceValue,\n isExternalSign,\n txParams: { from, nonce: existingNonce },\n } = txMeta;\n\n if (isExternalSign) {\n return [undefined, undefined];\n }\n\n const customNonce = customNonceValue ? toHex(customNonceValue) : undefined;\n\n if (customNonce) {\n log('Using custom nonce', customNonce);\n return [customNonce, undefined];\n }\n\n if (existingNonce) {\n log('Using existing nonce', existingNonce);\n return [existingNonce, undefined];\n }\n\n const nonceLock = await getNonceLock(from);\n const nonce = toHex(nonceLock.nextNonce);\n const releaseLock = nonceLock.releaseLock.bind(nonceLock);\n\n log('Using nonce from nonce tracker', nonce, nonceLock.nonceDetails);\n\n return [nonce, releaseLock];\n}\n\n/**\n * Filter and format transactions for the nonce tracker.\n *\n * @param currentChainId - Chain ID of the current network.\n * @param fromAddress - Address of the account from which the transactions to filter from are sent.\n * @param transactionStatuses - Status of the transactions for which to filter.\n * @param transactions - Array of transactionMeta objects that have been prefiltered.\n * @returns Array of transactions formatted for the nonce tracker.\n */\nexport function getAndFormatTransactionsForNonceTracker(\n currentChainId: string,\n fromAddress: string,\n transactionStatuses: TransactionStatus[],\n transactions: TransactionMeta[],\n): NonceTrackerTransaction[] {\n return transactions\n .filter(\n ({ chainId, isTransfer, isUserOperation, status, txParams: { from } }) =>\n !isTransfer &&\n !isUserOperation &&\n chainId === currentChainId &&\n transactionStatuses.includes(status) &&\n from.toLowerCase() === fromAddress.toLowerCase(),\n )\n .map(({ status, txParams: { from, gas, value, nonce } }) => {\n // the only value we care about is the nonce\n // but we need to return the other values to satisfy the type\n // TODO: refactor nonceTracker to not require this\n /* istanbul ignore next */\n return {\n status,\n history: [{}],\n txParams: {\n from: from ?? '',\n gas: gas ?? '',\n value: value ?? '',\n nonce: nonce ?? '',\n },\n };\n });\n}\n"]}
1
+ {"version":3,"file":"nonce.mjs","sourceRoot":"","sources":["../../src/utils/nonce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,mCAAmC;AAMnD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,sBAAkB;AAG9D,MAAM,GAAG,GAAG,kBAAkB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAuB,EACvB,YAAqD;IAErD,MAAM,EACJ,gBAAgB,EAChB,cAAc,EACd,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GACzC,GAAG,MAAM,CAAC;IAEX,IAAI,cAAc,EAAE,CAAC;QACnB,GAAG,CAAC,qCAAqC,CAAC,CAAC;QAC3C,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3E,IAAI,WAAW,EAAE,CAAC;QAChB,GAAG,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QACvC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,GAAG,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QAC3C,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1D,GAAG,CAAC,gCAAgC,EAAE,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IAErE,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uCAAuC,CACrD,cAAsB,EACtB,WAAmB,EACnB,mBAAwC,EACxC,YAA+B;IAE/B,OAAO,YAAY;SAChB,MAAM,CACL,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CACvE,CAAC,UAAU;QACX,CAAC,eAAe;QAChB,OAAO,KAAK,cAAc;QAC1B,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE,CACnD;SACA,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QACzD,4CAA4C;QAC5C,6DAA6D;QAC7D,kDAAkD;QAClD,0BAA0B;QAC1B,OAAO;YACL,MAAM;YACN,OAAO,EAAE,CAAC,EAAE,CAAC;YACb,QAAQ,EAAE;gBACR,IAAI,EAAE,IAAI,IAAI,EAAE;gBAChB,GAAG,EAAE,GAAG,IAAI,EAAE;gBACd,KAAK,EAAE,KAAK,IAAI,EAAE;gBAClB,KAAK,EAAE,KAAK,IAAI,EAAE;aACnB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type {\n NonceLock,\n Transaction as NonceTrackerTransaction,\n} from '@metamask/nonce-tracker';\n\nimport { createModuleLogger, projectLogger } from '../logger';\nimport type { TransactionMeta, TransactionStatus } from '../types';\n\nconst log = createModuleLogger(projectLogger, 'nonce');\n\n/**\n * Determine the next nonce to be used for a transaction.\n *\n * @param txMeta - The transaction metadata.\n * @param getNonceLock - An anonymous function that acquires the nonce lock for an address\n * @returns The next hexadecimal nonce to be used for the given transaction, and optionally a function to release the nonce lock.\n */\nexport async function getNextNonce(\n txMeta: TransactionMeta,\n getNonceLock: (address: string) => Promise<NonceLock>,\n): Promise<[string | undefined, (() => void) | undefined]> {\n const {\n customNonceValue,\n isExternalSign,\n txParams: { from, nonce: existingNonce },\n } = txMeta;\n\n if (isExternalSign) {\n log('Skipping nonce as signed externally');\n return [undefined, undefined];\n }\n\n const customNonce = customNonceValue ? toHex(customNonceValue) : undefined;\n\n if (customNonce) {\n log('Using custom nonce', customNonce);\n return [customNonce, undefined];\n }\n\n if (existingNonce) {\n log('Using existing nonce', existingNonce);\n return [existingNonce, undefined];\n }\n\n const nonceLock = await getNonceLock(from);\n const nonce = toHex(nonceLock.nextNonce);\n const releaseLock = nonceLock.releaseLock.bind(nonceLock);\n\n log('Using nonce from nonce tracker', nonce, nonceLock.nonceDetails);\n\n return [nonce, releaseLock];\n}\n\n/**\n * Filter and format transactions for the nonce tracker.\n *\n * @param currentChainId - Chain ID of the current network.\n * @param fromAddress - Address of the account from which the transactions to filter from are sent.\n * @param transactionStatuses - Status of the transactions for which to filter.\n * @param transactions - Array of transactionMeta objects that have been prefiltered.\n * @returns Array of transactions formatted for the nonce tracker.\n */\nexport function getAndFormatTransactionsForNonceTracker(\n currentChainId: string,\n fromAddress: string,\n transactionStatuses: TransactionStatus[],\n transactions: TransactionMeta[],\n): NonceTrackerTransaction[] {\n return transactions\n .filter(\n ({ chainId, isTransfer, isUserOperation, status, txParams: { from } }) =>\n !isTransfer &&\n !isUserOperation &&\n chainId === currentChainId &&\n transactionStatuses.includes(status) &&\n from.toLowerCase() === fromAddress.toLowerCase(),\n )\n .map(({ status, txParams: { from, gas, value, nonce } }) => {\n // the only value we care about is the nonce\n // but we need to return the other values to satisfy the type\n // TODO: refactor nonceTracker to not require this\n /* istanbul ignore next */\n return {\n status,\n history: [{}],\n txParams: {\n from: from ?? '',\n gas: gas ?? '',\n value: value ?? '',\n nonce: nonce ?? '',\n },\n };\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/transaction-controller",
3
- "version": "62.2.0",
3
+ "version": "62.3.1",
4
4
  "description": "Stores transactions alongside their periodically updated statuses and manages interactions such as approval and cancellation",
5
5
  "keywords": [
6
6
  "MetaMask",