@metamask-previews/transaction-controller 65.2.0-preview-ef7075b96 → 65.2.0-preview-5e603a6c0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/utils/first-time-interaction.cjs +5 -2
- package/dist/utils/first-time-interaction.cjs.map +1 -1
- package/dist/utils/first-time-interaction.d.cts.map +1 -1
- package/dist/utils/first-time-interaction.d.mts.map +1 -1
- package/dist/utils/first-time-interaction.mjs +5 -2
- package/dist/utils/first-time-interaction.mjs.map +1 -1
- package/dist/utils/transaction-type.cjs +2 -1
- package/dist/utils/transaction-type.cjs.map +1 -1
- package/dist/utils/transaction-type.d.cts.map +1 -1
- package/dist/utils/transaction-type.d.mts.map +1 -1
- package/dist/utils/transaction-type.mjs +2 -1
- package/dist/utils/transaction-type.mjs.map +1 -1
- package/dist/utils/validation.cjs +14 -6
- package/dist/utils/validation.cjs.map +1 -1
- package/dist/utils/validation.d.cts.map +1 -1
- package/dist/utils/validation.d.mts.map +1 -1
- package/dist/utils/validation.mjs +14 -6
- package/dist/utils/validation.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Trigger the first-time-interaction warning correctly for `safeTransferFrom` token transfers by including `TransactionType.tokenMethodSafeTransferFrom` in the effective-recipient decoding logic ([#8723](https://github.com/MetaMask/core/pull/8723))
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Reject transactions with a missing `to` and empty `data` to prevent accidental empty contract deployments ([#8744](https://github.com/MetaMask/core/pull/8744))
|
|
17
|
+
|
|
10
18
|
## [65.2.0]
|
|
11
19
|
|
|
12
20
|
### Added
|
|
@@ -10,10 +10,12 @@ const validation_1 = require("./validation.cjs");
|
|
|
10
10
|
const TOKEN_TRANSFER_TYPES = [
|
|
11
11
|
types_1.TransactionType.tokenMethodTransfer,
|
|
12
12
|
types_1.TransactionType.tokenMethodTransferFrom,
|
|
13
|
+
types_1.TransactionType.tokenMethodSafeTransferFrom,
|
|
13
14
|
];
|
|
14
15
|
/**
|
|
15
16
|
* Returns the effective recipient for first-time-interaction checks (decoded from data for token transfers).
|
|
16
|
-
* Used when comparing existing transactions so we match by actual recipient, not txParams.to (
|
|
17
|
+
* Used when comparing existing transactions so we match by actual recipient, not txParams.to (the token
|
|
18
|
+
* contract for ERC20/ERC721/ERC1155 transfer methods).
|
|
17
19
|
*
|
|
18
20
|
* @param tx - Transaction meta with txParams and type
|
|
19
21
|
* @returns Effective recipient address, or undefined
|
|
@@ -57,7 +59,8 @@ async function updateFirstTimeInteraction({ existingTransactions, getTransaction
|
|
|
57
59
|
tx.txParams?.from?.toLowerCase() === from?.toLowerCase() &&
|
|
58
60
|
getEffectiveRecipient(tx)?.toLowerCase() === recipientLower);
|
|
59
61
|
// Skip API call only if we already have a tx with same from and same effective recipient (e.g. duplicate or pending).
|
|
60
|
-
// For ERC20, effective recipient is decoded from data; using txParams.to
|
|
62
|
+
// For token transfers (ERC20/ERC721/ERC1155), effective recipient is decoded from data; using txParams.to
|
|
63
|
+
// would wrongly match any send of the same token contract.
|
|
61
64
|
if (existingTransaction) {
|
|
62
65
|
return;
|
|
63
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"first-time-interaction.cjs","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":";;;AAEA,2CAA8C;AAE9C,0DAAoE;AAEpE,0CAAiD;AACjD,wCAA2C;AAE3C,6DAA2D;AAC3D,iDAA+C;AAE/C,MAAM,oBAAoB,GAAG;IAC3B,uBAAe,CAAC,mBAAmB;IACnC,uBAAe,CAAC,uBAAuB;
|
|
1
|
+
{"version":3,"file":"first-time-interaction.cjs","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TransactionDescription } from '@ethersproject/abi';\nimport type { TraceContext, TraceCallback } from '@metamask/controller-utils';\nimport { hexToNumber } from '@metamask/utils';\n\nimport { getAccountAddressRelationship } from '../api/accounts-api';\nimport type { GetAccountAddressRelationshipRequest } from '../api/accounts-api';\nimport { projectLogger as log } from '../logger';\nimport { TransactionType } from '../types';\nimport type { TransactionMeta } from '../types';\nimport { decodeTransactionData } from './transaction-type';\nimport { validateParamTo } from './validation';\n\nconst TOKEN_TRANSFER_TYPES = [\n TransactionType.tokenMethodTransfer,\n TransactionType.tokenMethodTransferFrom,\n TransactionType.tokenMethodSafeTransferFrom,\n];\n\n/**\n * Returns the effective recipient for first-time-interaction checks (decoded from data for token transfers).\n * Used when comparing existing transactions so we match by actual recipient, not txParams.to (the token\n * contract for ERC20/ERC721/ERC1155 transfer methods).\n *\n * @param tx - Transaction meta with txParams and type\n * @returns Effective recipient address, or undefined\n */\nfunction getEffectiveRecipient(tx: TransactionMeta): string | undefined {\n const { data, to } = tx?.txParams ?? {};\n if (data && TOKEN_TRANSFER_TYPES.includes(tx?.type as TransactionType)) {\n const parsed = decodeTransactionData(data) as TransactionDescription;\n return (parsed?.args?._to ?? parsed?.args?.to ?? to) as string | undefined;\n }\n return to;\n}\n\ntype UpdateFirstTimeInteractionRequest = {\n existingTransactions: TransactionMeta[];\n getTransaction: (transactionId: string) => TransactionMeta | undefined;\n isFirstTimeInteractionEnabled: () => boolean;\n trace: TraceCallback;\n traceContext?: TraceContext;\n transactionMeta: TransactionMeta;\n updateTransaction: (\n updateParams: {\n transactionId: string;\n note: string;\n },\n updater: (txMeta: TransactionMeta) => void,\n ) => void;\n};\n\n/**\n * Updates the first-time interaction status for a transaction.\n *\n * @param params - The parameters for updating first time interaction.\n * @param params.existingTransactions - The existing transactions.\n * @param params.getTransaction - Function to get a transaction by ID.\n * @param params.isFirstTimeInteractionEnabled - The function to check if first time interaction is enabled.\n * @param params.trace - The trace callback.\n * @param params.traceContext - The trace context.\n * @param params.transactionMeta - The transaction meta object.\n * @param params.updateTransaction - Function to update transaction internal state.\n * @returns Promise that resolves when the update is complete.\n */\nexport async function updateFirstTimeInteraction({\n existingTransactions,\n getTransaction,\n isFirstTimeInteractionEnabled,\n trace,\n traceContext,\n transactionMeta,\n updateTransaction,\n}: UpdateFirstTimeInteractionRequest): Promise<void> {\n if (!isFirstTimeInteractionEnabled()) {\n return;\n }\n\n const {\n chainId,\n id: transactionId,\n txParams: { from },\n } = transactionMeta;\n\n const recipient = getEffectiveRecipient(transactionMeta);\n\n const request: GetAccountAddressRelationshipRequest = {\n chainId: hexToNumber(chainId),\n to: recipient as string,\n from,\n };\n\n validateParamTo(recipient);\n\n const recipientLower = recipient?.toLowerCase();\n const existingTransaction = existingTransactions.find(\n (tx) =>\n tx.id !== transactionId &&\n tx.chainId === chainId &&\n tx.txParams?.from?.toLowerCase() === from?.toLowerCase() &&\n getEffectiveRecipient(tx)?.toLowerCase() === recipientLower,\n );\n\n // Skip API call only if we already have a tx with same from and same effective recipient (e.g. duplicate or pending).\n // For token transfers (ERC20/ERC721/ERC1155), effective recipient is decoded from data; using txParams.to\n // would wrongly match any send of the same token contract.\n if (existingTransaction) {\n return;\n }\n\n try {\n const { count } = await trace(\n { name: 'Account Address Relationship', parentContext: traceContext },\n () => getAccountAddressRelationship(request),\n );\n\n const isFirstTimeInteraction =\n count === undefined ? undefined : count === 0;\n\n const finalTransactionMeta = getTransaction(transactionId);\n\n /* istanbul ignore if */\n if (!finalTransactionMeta) {\n log(\n 'Cannot update first time interaction as transaction not found',\n transactionId,\n );\n return;\n }\n\n updateTransaction(\n {\n transactionId,\n note: 'TransactionController#updateFirstInteraction - Update first time interaction',\n },\n (txMeta) => {\n txMeta.isFirstTimeInteraction = isFirstTimeInteraction;\n },\n );\n\n log('Updated first time interaction', transactionId, {\n isFirstTimeInteraction,\n });\n } catch (error) {\n log(\n 'Error fetching account address relationship, skipping first time interaction update',\n error,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"first-time-interaction.d.cts","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,mCAAmC;AAO9E,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAiB;
|
|
1
|
+
{"version":3,"file":"first-time-interaction.d.cts","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,mCAAmC;AAO9E,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAiB;AA2BhD,KAAK,iCAAiC,GAAG;IACvC,oBAAoB,EAAE,eAAe,EAAE,CAAC;IACxC,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;IACvE,6BAA6B,EAAE,MAAM,OAAO,CAAC;IAC7C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,EAAE,eAAe,CAAC;IACjC,iBAAiB,EAAE,CACjB,YAAY,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC;KACd,EACD,OAAO,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,KACvC,IAAI,CAAC;CACX,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAsB,0BAA0B,CAAC,EAC/C,oBAAoB,EACpB,cAAc,EACd,6BAA6B,EAC7B,KAAK,EACL,YAAY,EACZ,eAAe,EACf,iBAAiB,GAClB,EAAE,iCAAiC,GAAG,OAAO,CAAC,IAAI,CAAC,CA4EnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"first-time-interaction.d.mts","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,mCAAmC;AAO9E,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAiB;
|
|
1
|
+
{"version":3,"file":"first-time-interaction.d.mts","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,mCAAmC;AAO9E,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAiB;AA2BhD,KAAK,iCAAiC,GAAG;IACvC,oBAAoB,EAAE,eAAe,EAAE,CAAC;IACxC,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,eAAe,GAAG,SAAS,CAAC;IACvE,6BAA6B,EAAE,MAAM,OAAO,CAAC;IAC7C,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,EAAE,eAAe,CAAC;IACjC,iBAAiB,EAAE,CACjB,YAAY,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC;KACd,EACD,OAAO,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,KACvC,IAAI,CAAC;CACX,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAsB,0BAA0B,CAAC,EAC/C,oBAAoB,EACpB,cAAc,EACd,6BAA6B,EAC7B,KAAK,EACL,YAAY,EACZ,eAAe,EACf,iBAAiB,GAClB,EAAE,iCAAiC,GAAG,OAAO,CAAC,IAAI,CAAC,CA4EnD"}
|
|
@@ -7,10 +7,12 @@ import { validateParamTo } from "./validation.mjs";
|
|
|
7
7
|
const TOKEN_TRANSFER_TYPES = [
|
|
8
8
|
TransactionType.tokenMethodTransfer,
|
|
9
9
|
TransactionType.tokenMethodTransferFrom,
|
|
10
|
+
TransactionType.tokenMethodSafeTransferFrom,
|
|
10
11
|
];
|
|
11
12
|
/**
|
|
12
13
|
* Returns the effective recipient for first-time-interaction checks (decoded from data for token transfers).
|
|
13
|
-
* Used when comparing existing transactions so we match by actual recipient, not txParams.to (
|
|
14
|
+
* Used when comparing existing transactions so we match by actual recipient, not txParams.to (the token
|
|
15
|
+
* contract for ERC20/ERC721/ERC1155 transfer methods).
|
|
14
16
|
*
|
|
15
17
|
* @param tx - Transaction meta with txParams and type
|
|
16
18
|
* @returns Effective recipient address, or undefined
|
|
@@ -54,7 +56,8 @@ export async function updateFirstTimeInteraction({ existingTransactions, getTran
|
|
|
54
56
|
tx.txParams?.from?.toLowerCase() === from?.toLowerCase() &&
|
|
55
57
|
getEffectiveRecipient(tx)?.toLowerCase() === recipientLower);
|
|
56
58
|
// Skip API call only if we already have a tx with same from and same effective recipient (e.g. duplicate or pending).
|
|
57
|
-
// For ERC20, effective recipient is decoded from data; using txParams.to
|
|
59
|
+
// For token transfers (ERC20/ERC721/ERC1155), effective recipient is decoded from data; using txParams.to
|
|
60
|
+
// would wrongly match any send of the same token contract.
|
|
58
61
|
if (existingTransaction) {
|
|
59
62
|
return;
|
|
60
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"first-time-interaction.mjs","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,wBAAwB;AAE9C,OAAO,EAAE,6BAA6B,EAAE,gCAA4B;AAEpE,OAAO,EAAE,aAAa,IAAI,GAAG,EAAE,sBAAkB;AACjD,OAAO,EAAE,eAAe,EAAE,qBAAiB;AAE3C,OAAO,EAAE,qBAAqB,EAAE,+BAA2B;AAC3D,OAAO,EAAE,eAAe,EAAE,yBAAqB;AAE/C,MAAM,oBAAoB,GAAG;IAC3B,eAAe,CAAC,mBAAmB;IACnC,eAAe,CAAC,uBAAuB;
|
|
1
|
+
{"version":3,"file":"first-time-interaction.mjs","sourceRoot":"","sources":["../../src/utils/first-time-interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TransactionDescription } from '@ethersproject/abi';\nimport type { TraceContext, TraceCallback } from '@metamask/controller-utils';\nimport { hexToNumber } from '@metamask/utils';\n\nimport { getAccountAddressRelationship } from '../api/accounts-api';\nimport type { GetAccountAddressRelationshipRequest } from '../api/accounts-api';\nimport { projectLogger as log } from '../logger';\nimport { TransactionType } from '../types';\nimport type { TransactionMeta } from '../types';\nimport { decodeTransactionData } from './transaction-type';\nimport { validateParamTo } from './validation';\n\nconst TOKEN_TRANSFER_TYPES = [\n TransactionType.tokenMethodTransfer,\n TransactionType.tokenMethodTransferFrom,\n TransactionType.tokenMethodSafeTransferFrom,\n];\n\n/**\n * Returns the effective recipient for first-time-interaction checks (decoded from data for token transfers).\n * Used when comparing existing transactions so we match by actual recipient, not txParams.to (the token\n * contract for ERC20/ERC721/ERC1155 transfer methods).\n *\n * @param tx - Transaction meta with txParams and type\n * @returns Effective recipient address, or undefined\n */\nfunction getEffectiveRecipient(tx: TransactionMeta): string | undefined {\n const { data, to } = tx?.txParams ?? {};\n if (data && TOKEN_TRANSFER_TYPES.includes(tx?.type as TransactionType)) {\n const parsed = decodeTransactionData(data) as TransactionDescription;\n return (parsed?.args?._to ?? parsed?.args?.to ?? to) as string | undefined;\n }\n return to;\n}\n\ntype UpdateFirstTimeInteractionRequest = {\n existingTransactions: TransactionMeta[];\n getTransaction: (transactionId: string) => TransactionMeta | undefined;\n isFirstTimeInteractionEnabled: () => boolean;\n trace: TraceCallback;\n traceContext?: TraceContext;\n transactionMeta: TransactionMeta;\n updateTransaction: (\n updateParams: {\n transactionId: string;\n note: string;\n },\n updater: (txMeta: TransactionMeta) => void,\n ) => void;\n};\n\n/**\n * Updates the first-time interaction status for a transaction.\n *\n * @param params - The parameters for updating first time interaction.\n * @param params.existingTransactions - The existing transactions.\n * @param params.getTransaction - Function to get a transaction by ID.\n * @param params.isFirstTimeInteractionEnabled - The function to check if first time interaction is enabled.\n * @param params.trace - The trace callback.\n * @param params.traceContext - The trace context.\n * @param params.transactionMeta - The transaction meta object.\n * @param params.updateTransaction - Function to update transaction internal state.\n * @returns Promise that resolves when the update is complete.\n */\nexport async function updateFirstTimeInteraction({\n existingTransactions,\n getTransaction,\n isFirstTimeInteractionEnabled,\n trace,\n traceContext,\n transactionMeta,\n updateTransaction,\n}: UpdateFirstTimeInteractionRequest): Promise<void> {\n if (!isFirstTimeInteractionEnabled()) {\n return;\n }\n\n const {\n chainId,\n id: transactionId,\n txParams: { from },\n } = transactionMeta;\n\n const recipient = getEffectiveRecipient(transactionMeta);\n\n const request: GetAccountAddressRelationshipRequest = {\n chainId: hexToNumber(chainId),\n to: recipient as string,\n from,\n };\n\n validateParamTo(recipient);\n\n const recipientLower = recipient?.toLowerCase();\n const existingTransaction = existingTransactions.find(\n (tx) =>\n tx.id !== transactionId &&\n tx.chainId === chainId &&\n tx.txParams?.from?.toLowerCase() === from?.toLowerCase() &&\n getEffectiveRecipient(tx)?.toLowerCase() === recipientLower,\n );\n\n // Skip API call only if we already have a tx with same from and same effective recipient (e.g. duplicate or pending).\n // For token transfers (ERC20/ERC721/ERC1155), effective recipient is decoded from data; using txParams.to\n // would wrongly match any send of the same token contract.\n if (existingTransaction) {\n return;\n }\n\n try {\n const { count } = await trace(\n { name: 'Account Address Relationship', parentContext: traceContext },\n () => getAccountAddressRelationship(request),\n );\n\n const isFirstTimeInteraction =\n count === undefined ? undefined : count === 0;\n\n const finalTransactionMeta = getTransaction(transactionId);\n\n /* istanbul ignore if */\n if (!finalTransactionMeta) {\n log(\n 'Cannot update first time interaction as transaction not found',\n transactionId,\n );\n return;\n }\n\n updateTransaction(\n {\n transactionId,\n note: 'TransactionController#updateFirstInteraction - Update first time interaction',\n },\n (txMeta) => {\n txMeta.isFirstTimeInteraction = isFirstTimeInteraction;\n },\n );\n\n log('Updated first time interaction', transactionId, {\n isFirstTimeInteraction,\n });\n } catch (error) {\n log(\n 'Error fetching account address relationship, skipping first time interaction update',\n error,\n );\n }\n}\n"]}
|
|
@@ -24,7 +24,8 @@ const USDCInterface = new abi_1.Interface(metamask_eth_abis_1.abiFiatTokenV2);
|
|
|
24
24
|
*/
|
|
25
25
|
async function determineTransactionType(txParams, options) {
|
|
26
26
|
const { data, to } = txParams;
|
|
27
|
-
|
|
27
|
+
const hasRealBytecode = Boolean(data && data !== '0x' && data.length > 2);
|
|
28
|
+
if (hasRealBytecode && !to) {
|
|
28
29
|
return { type: types_1.TransactionType.deployContract, getCodeResponse: undefined };
|
|
29
30
|
}
|
|
30
31
|
let getCodeResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-type.cjs","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":";;;AAAA,4CAA+C;AAE/C,mEAKqC;AAKrC,wCAA2C;AAC3C,2CAA8C;AAC9C,6CAAwC;AAE3B,QAAA,kBAAkB,GAAG,kCAAkC,CAAC;AAErE,MAAM,cAAc,GAAG,IAAI,eAAS,CAAC,4BAAQ,CAAC,CAAC;AAC/C,MAAM,eAAe,GAAG,IAAI,eAAS,CAAC,6BAAS,CAAC,CAAC;AACjD,MAAM,gBAAgB,GAAG,IAAI,eAAS,CAAC,8BAAU,CAAC,CAAC;AACnD,MAAM,aAAa,GAAG,IAAI,eAAS,CAAC,kCAAc,CAAC,CAAC;AAEpD;;;;;;;;;;GAUG;AACI,KAAK,UAAU,wBAAwB,CAC5C,QAA2B,EAC3B,OAGC;IAED,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC;IAE9B,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction-type.cjs","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport type { TransactionDescription } from '@ethersproject/abi';\nimport {\n abiERC721,\n abiERC20,\n abiERC1155,\n abiFiatTokenV2,\n} from '@metamask/metamask-eth-abis';\nimport type { NetworkClientId } from '@metamask/network-controller';\n\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type { InferTransactionTypeResult, TransactionParams } from '../types';\nimport { TransactionType } from '../types';\nimport { DELEGATION_PREFIX } from './eip7702';\nimport { rpcRequest } from './provider';\n\nexport const ESTIMATE_GAS_ERROR = 'eth_estimateGas rpc method error';\n\nconst ERC20Interface = new Interface(abiERC20);\nconst ERC721Interface = new Interface(abiERC721);\nconst ERC1155Interface = new Interface(abiERC1155);\nconst USDCInterface = new Interface(abiFiatTokenV2);\n\n/**\n * Determines the type of the transaction by analyzing the txParams.\n * It will never return TRANSACTION_TYPE_CANCEL or TRANSACTION_TYPE_RETRY as these\n * represent specific events that we specify manually at transaction creation.\n *\n * @param txParams - Parameters for the transaction.\n * @param options - Optional messenger and network client ID to query the network.\n * @param options.messenger - The TransactionController messenger.\n * @param options.networkClientId - The network client ID to use.\n * @returns A object with the transaction type and the contract code response in Hex.\n */\nexport async function determineTransactionType(\n txParams: TransactionParams,\n options?: {\n messenger: TransactionControllerMessenger;\n networkClientId: NetworkClientId;\n },\n): Promise<InferTransactionTypeResult> {\n const { data, to } = txParams;\n\n const hasRealBytecode = Boolean(data && data !== '0x' && data.length > 2);\n\n if (hasRealBytecode && !to) {\n return { type: TransactionType.deployContract, getCodeResponse: undefined };\n }\n\n let getCodeResponse;\n let isContractAddress = Boolean(data?.length);\n\n if (options) {\n const { messenger, networkClientId } = options;\n const response = await readAddressAsContract(\n messenger,\n networkClientId,\n to,\n );\n\n getCodeResponse = response.contractCode;\n isContractAddress = response.isContractAddress;\n }\n\n if (!isContractAddress) {\n return { type: TransactionType.simpleSend, getCodeResponse };\n }\n\n const hasValue = Number(txParams.value ?? '0') !== 0;\n\n const contractInteractionResult = {\n type: TransactionType.contractInteraction,\n getCodeResponse,\n };\n\n if (!data || hasValue) {\n return contractInteractionResult;\n }\n\n const name = getMethodName(data);\n\n if (!name) {\n return contractInteractionResult;\n }\n\n const tokenMethodName = [\n TransactionType.tokenMethodApprove,\n TransactionType.tokenMethodSetApprovalForAll,\n TransactionType.tokenMethodTransfer,\n TransactionType.tokenMethodTransferFrom,\n TransactionType.tokenMethodSafeTransferFrom,\n TransactionType.tokenMethodIncreaseAllowance,\n ].find((methodName) => methodName.toLowerCase() === name.toLowerCase());\n\n if (tokenMethodName) {\n return { type: tokenMethodName, getCodeResponse };\n }\n\n return contractInteractionResult;\n}\n\n/**\n * Parses transaction data using ABIs for three different token standards: ERC20, ERC721, ERC1155 and USDC.\n * The data will decode correctly if the transaction is an interaction with a contract that matches one of these\n * contract standards\n *\n * @param data - Encoded transaction data.\n * @param options - Options bag.\n * @param options.getMethodName - Whether to get the method name.\n * @returns A representation of an ethereum contract call.\n */\nexport function decodeTransactionData(\n data: string,\n options?: {\n getMethodName?: boolean;\n },\n): undefined | TransactionDescription | string {\n if (!data || data.length < 10) {\n return undefined;\n }\n\n const fourByte = data.substring(0, 10).toLowerCase();\n\n for (const iface of [\n ERC20Interface,\n ERC721Interface,\n ERC1155Interface,\n USDCInterface,\n ]) {\n try {\n if (options?.getMethodName) {\n return iface.getFunction(fourByte)?.name;\n }\n return iface.parseTransaction({ data });\n } catch {\n // Intentionally empty\n }\n }\n\n return undefined;\n}\n\n/**\n * Attempts to get the method name from the given transaction data.\n *\n * @param data - Encoded transaction data.\n * @returns The method name.\n */\nfunction getMethodName(data?: string): string | undefined {\n return decodeTransactionData(data as string, {\n getMethodName: true,\n }) as string | undefined;\n}\n\n/**\n * Reads an Ethereum address and determines if it is a contract address.\n *\n * @param messenger - The TransactionController messenger.\n * @param networkClientId - The network client ID to use.\n * @param address - The Ethereum address.\n * @returns An object containing the contract code and a boolean indicating if it is a contract address.\n */\nasync function readAddressAsContract(\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n address?: string,\n): Promise<{\n contractCode: string | null;\n isContractAddress: boolean;\n}> {\n let contractCode;\n try {\n contractCode = (await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_getCode',\n params: [address as string, 'latest'],\n })) as string;\n // Not used\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (error) {\n contractCode = null;\n }\n\n const isContractAddress = contractCode\n ? contractCode !== '0x' &&\n contractCode !== '0x0' &&\n !contractCode.startsWith(DELEGATION_PREFIX)\n : false;\n return { contractCode, isContractAddress };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-type.d.cts","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,2BAA2B;AAOjE,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,qBAAiB;AAK9E,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAOrE;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,CAAC,EAAE;IACR,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GACA,OAAO,CAAC,0BAA0B,CAAC,
|
|
1
|
+
{"version":3,"file":"transaction-type.d.cts","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,2BAA2B;AAOjE,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,qBAAiB;AAK9E,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAOrE;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,CAAC,EAAE;IACR,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GACA,OAAO,CAAC,0BAA0B,CAAC,CA2DrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACR,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GACA,SAAS,GAAG,sBAAsB,GAAG,MAAM,CAwB7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-type.d.mts","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,2BAA2B;AAOjE,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,qBAAiB;AAK9E,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAOrE;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,CAAC,EAAE;IACR,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GACA,OAAO,CAAC,0BAA0B,CAAC,
|
|
1
|
+
{"version":3,"file":"transaction-type.d.mts","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,2BAA2B;AAOjE,OAAO,KAAK,EAAE,eAAe,EAAE,qCAAqC;AAEpE,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,qBAAiB;AAK9E,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAOrE;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,CAAC,EAAE;IACR,SAAS,EAAE,8BAA8B,CAAC;IAC1C,eAAe,EAAE,eAAe,CAAC;CAClC,GACA,OAAO,CAAC,0BAA0B,CAAC,CA2DrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACR,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GACA,SAAS,GAAG,sBAAsB,GAAG,MAAM,CAwB7C"}
|
|
@@ -21,7 +21,8 @@ const USDCInterface = new Interface(abiFiatTokenV2);
|
|
|
21
21
|
*/
|
|
22
22
|
export async function determineTransactionType(txParams, options) {
|
|
23
23
|
const { data, to } = txParams;
|
|
24
|
-
|
|
24
|
+
const hasRealBytecode = Boolean(data && data !== '0x' && data.length > 2);
|
|
25
|
+
if (hasRealBytecode && !to) {
|
|
25
26
|
return { type: TransactionType.deployContract, getCodeResponse: undefined };
|
|
26
27
|
}
|
|
27
28
|
let getCodeResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-type.mjs","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,2BAA2B;AAE/C,OAAO,EACL,SAAS,EACT,QAAQ,EACR,UAAU,EACV,cAAc,EACf,oCAAoC;AAKrC,OAAO,EAAE,eAAe,EAAE,qBAAiB;AAC3C,OAAO,EAAE,iBAAiB,EAAE,sBAAkB;AAC9C,OAAO,EAAE,UAAU,EAAE,uBAAmB;AAExC,MAAM,CAAC,MAAM,kBAAkB,GAAG,kCAAkC,CAAC;AAErE,MAAM,cAAc,GAAG,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;AAC/C,MAAM,eAAe,GAAG,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AACjD,MAAM,gBAAgB,GAAG,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC;AACnD,MAAM,aAAa,GAAG,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,QAA2B,EAC3B,OAGC;IAED,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC;IAE9B,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction-type.mjs","sourceRoot":"","sources":["../../src/utils/transaction-type.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport type { TransactionDescription } from '@ethersproject/abi';\nimport {\n abiERC721,\n abiERC20,\n abiERC1155,\n abiFiatTokenV2,\n} from '@metamask/metamask-eth-abis';\nimport type { NetworkClientId } from '@metamask/network-controller';\n\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type { InferTransactionTypeResult, TransactionParams } from '../types';\nimport { TransactionType } from '../types';\nimport { DELEGATION_PREFIX } from './eip7702';\nimport { rpcRequest } from './provider';\n\nexport const ESTIMATE_GAS_ERROR = 'eth_estimateGas rpc method error';\n\nconst ERC20Interface = new Interface(abiERC20);\nconst ERC721Interface = new Interface(abiERC721);\nconst ERC1155Interface = new Interface(abiERC1155);\nconst USDCInterface = new Interface(abiFiatTokenV2);\n\n/**\n * Determines the type of the transaction by analyzing the txParams.\n * It will never return TRANSACTION_TYPE_CANCEL or TRANSACTION_TYPE_RETRY as these\n * represent specific events that we specify manually at transaction creation.\n *\n * @param txParams - Parameters for the transaction.\n * @param options - Optional messenger and network client ID to query the network.\n * @param options.messenger - The TransactionController messenger.\n * @param options.networkClientId - The network client ID to use.\n * @returns A object with the transaction type and the contract code response in Hex.\n */\nexport async function determineTransactionType(\n txParams: TransactionParams,\n options?: {\n messenger: TransactionControllerMessenger;\n networkClientId: NetworkClientId;\n },\n): Promise<InferTransactionTypeResult> {\n const { data, to } = txParams;\n\n const hasRealBytecode = Boolean(data && data !== '0x' && data.length > 2);\n\n if (hasRealBytecode && !to) {\n return { type: TransactionType.deployContract, getCodeResponse: undefined };\n }\n\n let getCodeResponse;\n let isContractAddress = Boolean(data?.length);\n\n if (options) {\n const { messenger, networkClientId } = options;\n const response = await readAddressAsContract(\n messenger,\n networkClientId,\n to,\n );\n\n getCodeResponse = response.contractCode;\n isContractAddress = response.isContractAddress;\n }\n\n if (!isContractAddress) {\n return { type: TransactionType.simpleSend, getCodeResponse };\n }\n\n const hasValue = Number(txParams.value ?? '0') !== 0;\n\n const contractInteractionResult = {\n type: TransactionType.contractInteraction,\n getCodeResponse,\n };\n\n if (!data || hasValue) {\n return contractInteractionResult;\n }\n\n const name = getMethodName(data);\n\n if (!name) {\n return contractInteractionResult;\n }\n\n const tokenMethodName = [\n TransactionType.tokenMethodApprove,\n TransactionType.tokenMethodSetApprovalForAll,\n TransactionType.tokenMethodTransfer,\n TransactionType.tokenMethodTransferFrom,\n TransactionType.tokenMethodSafeTransferFrom,\n TransactionType.tokenMethodIncreaseAllowance,\n ].find((methodName) => methodName.toLowerCase() === name.toLowerCase());\n\n if (tokenMethodName) {\n return { type: tokenMethodName, getCodeResponse };\n }\n\n return contractInteractionResult;\n}\n\n/**\n * Parses transaction data using ABIs for three different token standards: ERC20, ERC721, ERC1155 and USDC.\n * The data will decode correctly if the transaction is an interaction with a contract that matches one of these\n * contract standards\n *\n * @param data - Encoded transaction data.\n * @param options - Options bag.\n * @param options.getMethodName - Whether to get the method name.\n * @returns A representation of an ethereum contract call.\n */\nexport function decodeTransactionData(\n data: string,\n options?: {\n getMethodName?: boolean;\n },\n): undefined | TransactionDescription | string {\n if (!data || data.length < 10) {\n return undefined;\n }\n\n const fourByte = data.substring(0, 10).toLowerCase();\n\n for (const iface of [\n ERC20Interface,\n ERC721Interface,\n ERC1155Interface,\n USDCInterface,\n ]) {\n try {\n if (options?.getMethodName) {\n return iface.getFunction(fourByte)?.name;\n }\n return iface.parseTransaction({ data });\n } catch {\n // Intentionally empty\n }\n }\n\n return undefined;\n}\n\n/**\n * Attempts to get the method name from the given transaction data.\n *\n * @param data - Encoded transaction data.\n * @returns The method name.\n */\nfunction getMethodName(data?: string): string | undefined {\n return decodeTransactionData(data as string, {\n getMethodName: true,\n }) as string | undefined;\n}\n\n/**\n * Reads an Ethereum address and determines if it is a contract address.\n *\n * @param messenger - The TransactionController messenger.\n * @param networkClientId - The network client ID to use.\n * @param address - The Ethereum address.\n * @returns An object containing the contract code and a boolean indicating if it is a contract address.\n */\nasync function readAddressAsContract(\n messenger: TransactionControllerMessenger,\n networkClientId: NetworkClientId,\n address?: string,\n): Promise<{\n contractCode: string | null;\n isContractAddress: boolean;\n}> {\n let contractCode;\n try {\n contractCode = (await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_getCode',\n params: [address as string, 'latest'],\n })) as string;\n // Not used\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (error) {\n contractCode = null;\n }\n\n const isContractAddress = contractCode\n ? contractCode !== '0x' &&\n contractCode !== '0x0' &&\n !contractCode.startsWith(DELEGATION_PREFIX)\n : false;\n return { contractCode, isContractAddress };\n}\n"]}
|
|
@@ -132,17 +132,25 @@ function validateParamValue(value) {
|
|
|
132
132
|
*
|
|
133
133
|
* @param txParams - The transaction parameters object to validate.
|
|
134
134
|
* @throws Throws an error if the recipient address is invalid:
|
|
135
|
-
* - If the recipient address is
|
|
136
|
-
*
|
|
137
|
-
*
|
|
135
|
+
* - If the recipient address is missing (empty string, '0x', or undefined) and the
|
|
136
|
+
* transaction does not contain real bytecode (data must be longer than `0x`),
|
|
137
|
+
* an error is thrown. This prevents accidental contract deployments with empty
|
|
138
|
+
* `to` and empty `data` from locking funds.
|
|
139
|
+
* - If the recipient address is missing and the transaction contains real
|
|
140
|
+
* bytecode (data longer than `0x`), the "to" field is removed from the
|
|
141
|
+
* transaction parameters (legitimate contract deployment).
|
|
142
|
+
* - If the recipient address is not a valid hexadecimal Ethereum address, an
|
|
143
|
+
* error is thrown.
|
|
138
144
|
*/
|
|
139
145
|
function validateParamRecipient(txParams) {
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
const isMissingRecipient = txParams.to === '0x' || txParams.to === '' || txParams.to === undefined;
|
|
147
|
+
if (isMissingRecipient) {
|
|
148
|
+
const hasRealBytecode = Boolean(txParams.data && txParams.data !== '0x' && txParams.data.length > 2);
|
|
149
|
+
if (hasRealBytecode) {
|
|
142
150
|
delete txParams.to;
|
|
143
151
|
}
|
|
144
152
|
else {
|
|
145
|
-
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid "to" address.`);
|
|
153
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid "to" address: must be specified for transactions without contract deployment bytecode.`);
|
|
146
154
|
}
|
|
147
155
|
}
|
|
148
156
|
else if (txParams.to !== undefined && !(0, controller_utils_1.isValidHexAddress)(txParams.to)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.cjs","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { ORIGIN_METAMASK, isValidHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport { JsonRpcError, providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { isStrictHexString, remove0x } from '@metamask/utils';\n\nimport { TransactionEnvelopeType, TransactionType } from '../types';\nimport type {\n Authorization,\n TransactionBatchRequest,\n TransactionParams,\n} from '../types';\nimport { isEIP1559Transaction } from './utils';\n\nexport enum ErrorCode {\n DuplicateBundleId = 5720,\n BundleTooLarge = 5740,\n RejectedUpgrade = 5750,\n}\n\nconst TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [\n TransactionEnvelopeType.feeMarket,\n TransactionEnvelopeType.setCode,\n];\n\ntype GasFieldsToValidate =\n | 'gasPrice'\n | 'maxFeePerGas'\n | 'maxPriorityFeePerGas'\n | 'gas'\n | 'gasLimit';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param options - Options bag.\n * @param options.data - The data included in the transaction.\n * @param options.from - The address from which the transaction is initiated.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.origin - The origin or source of the transaction.\n * @param options.permittedAddresses - The permitted accounts for the given origin.\n * @param options.selectedAddress - The currently selected Ethereum address in the wallet.\n * @param options.txParams - The transaction parameters.\n * @param options.type - The transaction type.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin({\n data,\n from,\n internalAccounts,\n origin,\n permittedAddresses,\n txParams,\n type,\n}: {\n data?: string;\n from: string;\n internalAccounts?: string[];\n origin?: string;\n permittedAddresses?: string[];\n selectedAddress?: string;\n txParams: TransactionParams;\n type?: TransactionType;\n}): Promise<void> {\n const isInternal = !origin || origin === ORIGIN_METAMASK;\n\n if (isInternal) {\n return;\n }\n\n const { authorizationList, to, type: envelopeType } = txParams;\n\n if (permittedAddresses && !permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\n }\n\n if (type === TransactionType.batch) {\n return;\n }\n\n if (authorizationList || envelopeType === TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n 'External EIP-7702 transactions are not supported',\n );\n }\n\n const hasData = Boolean(data && data !== '0x');\n\n if (\n hasData &&\n internalAccounts?.some(\n (account) => account.toLowerCase() === to?.toLowerCase(),\n )\n ) {\n throw rpcErrors.invalidParams(\n 'External transactions to internal accounts cannot include data',\n );\n }\n}\n\n/**\n * Validates the transaction params for required properties and throws in\n * the event of any validation error.\n *\n * @param txParams - Transaction params object to validate.\n * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions.\n * @param chainId - The chain ID of the transaction.\n */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n chainId?: Hex,\n): void {\n validateEnvelopeType(txParams.type);\n validateEIP1559Compatibility(txParams, isEIP1559Compatible);\n validateParamFrom(txParams.from);\n validateParamRecipient(txParams);\n validateParamValue(txParams.value);\n validateParamData(txParams.data);\n validateParamChainId(txParams.chainId, chainId);\n validateGasFeeParams(txParams);\n validateAuthorizationList(txParams);\n}\n\n/**\n * Validates the `type` property, ensuring that if it is specified, it is a valid transaction envelope type.\n *\n * @param type - The transaction envelope type to validate.\n * @throws Throws invalid params if the type is not a valid transaction envelope type.\n */\nfunction validateEnvelopeType(type: string | undefined): void {\n if (\n type &&\n !Object.values(TransactionEnvelopeType).includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: \"${type}\". Must be one of: ${Object.values(\n TransactionEnvelopeType,\n ).join(', ')}`,\n );\n }\n}\n\n/**\n * Validates EIP-1559 compatibility for transaction creation.\n *\n * @param txParams - The transaction parameters to validate.\n * @param isEIP1559Compatible - Indicates if the current network supports EIP-1559.\n * @throws Throws invalid params if the transaction specifies EIP-1559 but the network does not support it.\n */\nfunction validateEIP1559Compatibility(\n txParams: TransactionParams,\n isEIP1559Compatible: boolean,\n): void {\n if (isEIP1559Transaction(txParams) && !isEIP1559Compatible) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: params specify an EIP-1559 transaction but the current network does not support EIP-1559',\n );\n }\n}\n\n/**\n * Validates value property, ensuring it is a valid positive integer number\n * denominated in wei.\n *\n * @param value - The value to validate, expressed as a string.\n * @throws Throws an error if the value is not a valid positive integer\n * number denominated in wei.\n * - If the value contains a hyphen (-), it is considered invalid.\n * - If the value contains a decimal point (.), it is considered invalid.\n * - If the value is not a finite number, is NaN, or is not a safe integer, it is considered invalid.\n */\nfunction validateParamValue(value?: string): void {\n if (value !== undefined) {\n if (value.includes('-')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": not a positive number.`,\n );\n }\n\n if (value.includes('.')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": number must be in wei.`,\n );\n }\n const intValue = parseInt(value, 10);\n const isValid =\n Number.isFinite(intValue) &&\n !Number.isNaN(intValue) &&\n !isNaN(Number(value)) &&\n Number.isSafeInteger(intValue);\n if (!isValid) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value ${value}: number must be a valid number.`,\n );\n }\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param txParams - The transaction parameters object to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamRecipient(txParams: TransactionParams): void {\n if (txParams.to === '0x' || txParams.to === undefined) {\n if (txParams.data) {\n delete txParams.to;\n } else {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n } else if (txParams.to !== undefined && !isValidHexAddress(txParams.to)) {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param from - The from property to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamFrom(from: string): void {\n if (!from || typeof from !== 'string') {\n throw rpcErrors.invalidParams(\n `Invalid \"from\" address ${from}: not a string.`,\n );\n }\n if (!isValidHexAddress(from)) {\n throw rpcErrors.invalidParams('Invalid \"from\" address.');\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param to - The to property to validate.\n * @throws Throws an error if the recipient address is invalid.\n */\nexport function validateParamTo(to?: string): void {\n if (!to || typeof to !== 'string') {\n throw rpcErrors.invalidParams(`Invalid \"to\" address`);\n }\n}\n\n/**\n * Validates a transaction batch request.\n *\n * @param options - Options bag.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.request - The batch request object.\n * @param options.sizeLimit - The maximum number of calls allowed in a batch request.\n */\nexport function validateBatchRequest({\n internalAccounts,\n request,\n sizeLimit,\n}: {\n internalAccounts: string[];\n request: TransactionBatchRequest;\n sizeLimit: number;\n}): void {\n const { origin } = request;\n const isExternal = origin && origin !== ORIGIN_METAMASK;\n\n const internalAccountsNormalized = internalAccounts.map((account) =>\n account.toLowerCase(),\n );\n\n if (\n isExternal &&\n request.transactions.some((nestedTransaction) => {\n const normalizedCallTo =\n nestedTransaction.params.to?.toLowerCase() as string;\n\n const callData = nestedTransaction.params.data;\n\n const isInternalAccount =\n internalAccountsNormalized.includes(normalizedCallTo);\n\n const hasData = Boolean(callData && callData !== '0x');\n\n return isInternalAccount && hasData;\n })\n ) {\n throw rpcErrors.invalidParams(\n 'External calls to internal accounts cannot include data',\n );\n }\n\n if (isExternal && request.transactions.length > sizeLimit) {\n throw new JsonRpcError(\n ErrorCode.BundleTooLarge,\n `Batch size cannot exceed ${sizeLimit}. got: ${request.transactions.length}`,\n );\n }\n}\n\n/**\n * Validates input data for transactions.\n *\n * @param value - The input data to validate.\n * @throws Throws invalid params if the input data is invalid.\n */\nfunction validateParamData(value?: string): void {\n if (value) {\n const ERC20Interface = new Interface(abiERC20);\n try {\n ERC20Interface.parseTransaction({ data: value });\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message.match(/BUFFER_OVERRUN/u)) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: data out-of-bounds, BUFFER_OVERRUN.',\n );\n }\n }\n }\n}\n\n/**\n * Validates chainId type.\n *\n * @param chainIdParams - The chain ID to validate.\n * @param chainIdNetworkClient - The chain ID of the network client.\n */\nfunction validateParamChainId(\n chainIdParams?: Hex,\n chainIdNetworkClient?: Hex,\n): void {\n if (\n chainIdParams &&\n chainIdNetworkClient &&\n chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams): void {\n if (txParams.gasPrice) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxPriorityFeePerGas',\n );\n ensureFieldIsValidHex(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxFeePerGas');\n }\n\n if (txParams.maxPriorityFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(\n txParams,\n 'maxPriorityFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxPriorityFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');\n }\n\n if (txParams.gasLimit) {\n ensureFieldIsValidHex(txParams, 'gasLimit');\n }\n\n if (txParams.gas) {\n ensureFieldIsValidHex(txParams, 'gas');\n }\n}\n\n/**\n * Ensures that the provided txParams has the proper 'type' specified for the\n * given field, if it is provided. If types do not match throws an\n * invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {ethErrors.rpc.invalidParams} Throws if type does not match the\n * expectations for provided field.\n */\nfunction ensureProperTransactionEnvelopeTypeProvided(\n txParams: TransactionParams,\n field: keyof TransactionParams,\n): void {\n const type = txParams.type as TransactionEnvelopeType | undefined;\n\n switch (field) {\n case 'authorizationList':\n if (type && type !== TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including authorizationList requires type: \"${TransactionEnvelopeType.setCode}\"`,\n );\n }\n break;\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (type && !TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.join(', ')}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (type && TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but included a gasPrice instead of maxFeePerGas and maxPriorityFeePerGas`,\n );\n }\n }\n}\n\n/**\n * Given two fields, ensure that the second field is not included in txParams,\n * and if it is throw an invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param fieldBeingValidated - The current field being validated\n * @param mutuallyExclusiveField - The field to ensure is not provided\n * @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is\n * present in txParams.\n */\nfunction ensureMutuallyExclusiveFieldsNotProvided(\n txParams: TransactionParams,\n fieldBeingValidated: GasFieldsToValidate,\n mutuallyExclusiveField: GasFieldsToValidate,\n): void {\n if (typeof txParams[mutuallyExclusiveField] !== 'undefined') {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: specified ${fieldBeingValidated} but also included ${mutuallyExclusiveField}, these cannot be mixed`,\n );\n }\n}\n\n/**\n * Ensures that the provided value for field is a valid hexadecimal.\n * Throws an invalidParams error if field is not a valid hexadecimal.\n *\n * @param data - The object containing the field\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex<DataType>(\n data: DataType,\n field: keyof DataType,\n): void {\n const value = data[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${String(field)} is not a valid hexadecimal string. got: (${String(\n value,\n )})`,\n );\n }\n}\n\n/**\n * Validate the authorization list property in the transaction parameters.\n *\n * @param txParams - The transaction parameters containing the authorization list to validate.\n */\nfunction validateAuthorizationList(txParams: TransactionParams): void {\n const { authorizationList } = txParams;\n\n if (!authorizationList) {\n return;\n }\n\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'authorizationList');\n\n if (!Array.isArray(authorizationList)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: authorizationList must be an array`,\n );\n }\n\n for (const authorization of authorizationList) {\n validateAuthorization(authorization);\n }\n}\n\n/**\n * Validate an authorization object.\n *\n * @param authorization - The authorization object to validate.\n */\nfunction validateAuthorization(authorization: Authorization): void {\n ensureFieldIsValidHex(authorization, 'address');\n validateHexLength(authorization.address, 20, 'address');\n\n for (const field of ['chainId', 'nonce', 'r', 's'] as const) {\n if (authorization[field]) {\n ensureFieldIsValidHex(authorization, field);\n }\n }\n\n const { yParity } = authorization;\n\n if (yParity && !['0x0', '0x1'].includes(yParity)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: yParity must be '0x0' or '0x1'. got: ${yParity}`,\n );\n }\n}\n\n/**\n * Validate the number of bytes in a hex string.\n *\n * @param value - The hex string to validate.\n * @param lengthBytes - The expected length in bytes.\n * @param fieldName - The name of the field being validated.\n */\nfunction validateHexLength(\n value: string,\n lengthBytes: number,\n fieldName: string,\n): void {\n const actualLengthBytes = remove0x(value).length / 2;\n\n if (actualLengthBytes !== lengthBytes) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${fieldName} must be ${lengthBytes} bytes. got: ${actualLengthBytes} bytes`,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validation.cjs","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { ORIGIN_METAMASK, isValidHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport { JsonRpcError, providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { isStrictHexString, remove0x } from '@metamask/utils';\n\nimport { TransactionEnvelopeType, TransactionType } from '../types';\nimport type {\n Authorization,\n TransactionBatchRequest,\n TransactionParams,\n} from '../types';\nimport { isEIP1559Transaction } from './utils';\n\nexport enum ErrorCode {\n DuplicateBundleId = 5720,\n BundleTooLarge = 5740,\n RejectedUpgrade = 5750,\n}\n\nconst TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [\n TransactionEnvelopeType.feeMarket,\n TransactionEnvelopeType.setCode,\n];\n\ntype GasFieldsToValidate =\n | 'gasPrice'\n | 'maxFeePerGas'\n | 'maxPriorityFeePerGas'\n | 'gas'\n | 'gasLimit';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param options - Options bag.\n * @param options.data - The data included in the transaction.\n * @param options.from - The address from which the transaction is initiated.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.origin - The origin or source of the transaction.\n * @param options.permittedAddresses - The permitted accounts for the given origin.\n * @param options.selectedAddress - The currently selected Ethereum address in the wallet.\n * @param options.txParams - The transaction parameters.\n * @param options.type - The transaction type.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin({\n data,\n from,\n internalAccounts,\n origin,\n permittedAddresses,\n txParams,\n type,\n}: {\n data?: string;\n from: string;\n internalAccounts?: string[];\n origin?: string;\n permittedAddresses?: string[];\n selectedAddress?: string;\n txParams: TransactionParams;\n type?: TransactionType;\n}): Promise<void> {\n const isInternal = !origin || origin === ORIGIN_METAMASK;\n\n if (isInternal) {\n return;\n }\n\n const { authorizationList, to, type: envelopeType } = txParams;\n\n if (permittedAddresses && !permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\n }\n\n if (type === TransactionType.batch) {\n return;\n }\n\n if (authorizationList || envelopeType === TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n 'External EIP-7702 transactions are not supported',\n );\n }\n\n const hasData = Boolean(data && data !== '0x');\n\n if (\n hasData &&\n internalAccounts?.some(\n (account) => account.toLowerCase() === to?.toLowerCase(),\n )\n ) {\n throw rpcErrors.invalidParams(\n 'External transactions to internal accounts cannot include data',\n );\n }\n}\n\n/**\n * Validates the transaction params for required properties and throws in\n * the event of any validation error.\n *\n * @param txParams - Transaction params object to validate.\n * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions.\n * @param chainId - The chain ID of the transaction.\n */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n chainId?: Hex,\n): void {\n validateEnvelopeType(txParams.type);\n validateEIP1559Compatibility(txParams, isEIP1559Compatible);\n validateParamFrom(txParams.from);\n validateParamRecipient(txParams);\n validateParamValue(txParams.value);\n validateParamData(txParams.data);\n validateParamChainId(txParams.chainId, chainId);\n validateGasFeeParams(txParams);\n validateAuthorizationList(txParams);\n}\n\n/**\n * Validates the `type` property, ensuring that if it is specified, it is a valid transaction envelope type.\n *\n * @param type - The transaction envelope type to validate.\n * @throws Throws invalid params if the type is not a valid transaction envelope type.\n */\nfunction validateEnvelopeType(type: string | undefined): void {\n if (\n type &&\n !Object.values(TransactionEnvelopeType).includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: \"${type}\". Must be one of: ${Object.values(\n TransactionEnvelopeType,\n ).join(', ')}`,\n );\n }\n}\n\n/**\n * Validates EIP-1559 compatibility for transaction creation.\n *\n * @param txParams - The transaction parameters to validate.\n * @param isEIP1559Compatible - Indicates if the current network supports EIP-1559.\n * @throws Throws invalid params if the transaction specifies EIP-1559 but the network does not support it.\n */\nfunction validateEIP1559Compatibility(\n txParams: TransactionParams,\n isEIP1559Compatible: boolean,\n): void {\n if (isEIP1559Transaction(txParams) && !isEIP1559Compatible) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: params specify an EIP-1559 transaction but the current network does not support EIP-1559',\n );\n }\n}\n\n/**\n * Validates value property, ensuring it is a valid positive integer number\n * denominated in wei.\n *\n * @param value - The value to validate, expressed as a string.\n * @throws Throws an error if the value is not a valid positive integer\n * number denominated in wei.\n * - If the value contains a hyphen (-), it is considered invalid.\n * - If the value contains a decimal point (.), it is considered invalid.\n * - If the value is not a finite number, is NaN, or is not a safe integer, it is considered invalid.\n */\nfunction validateParamValue(value?: string): void {\n if (value !== undefined) {\n if (value.includes('-')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": not a positive number.`,\n );\n }\n\n if (value.includes('.')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": number must be in wei.`,\n );\n }\n const intValue = parseInt(value, 10);\n const isValid =\n Number.isFinite(intValue) &&\n !Number.isNaN(intValue) &&\n !isNaN(Number(value)) &&\n Number.isSafeInteger(intValue);\n if (!isValid) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value ${value}: number must be a valid number.`,\n );\n }\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param txParams - The transaction parameters object to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is missing (empty string, '0x', or undefined) and the\n * transaction does not contain real bytecode (data must be longer than `0x`),\n * an error is thrown. This prevents accidental contract deployments with empty\n * `to` and empty `data` from locking funds.\n * - If the recipient address is missing and the transaction contains real\n * bytecode (data longer than `0x`), the \"to\" field is removed from the\n * transaction parameters (legitimate contract deployment).\n * - If the recipient address is not a valid hexadecimal Ethereum address, an\n * error is thrown.\n */\nfunction validateParamRecipient(txParams: TransactionParams): void {\n const isMissingRecipient =\n txParams.to === '0x' || txParams.to === '' || txParams.to === undefined;\n\n if (isMissingRecipient) {\n const hasRealBytecode = Boolean(\n txParams.data && txParams.data !== '0x' && txParams.data.length > 2,\n );\n\n if (hasRealBytecode) {\n delete txParams.to;\n } else {\n throw rpcErrors.invalidParams(\n `Invalid \"to\" address: must be specified for transactions without contract deployment bytecode.`,\n );\n }\n } else if (txParams.to !== undefined && !isValidHexAddress(txParams.to)) {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param from - The from property to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamFrom(from: string): void {\n if (!from || typeof from !== 'string') {\n throw rpcErrors.invalidParams(\n `Invalid \"from\" address ${from}: not a string.`,\n );\n }\n if (!isValidHexAddress(from)) {\n throw rpcErrors.invalidParams('Invalid \"from\" address.');\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param to - The to property to validate.\n * @throws Throws an error if the recipient address is invalid.\n */\nexport function validateParamTo(to?: string): void {\n if (!to || typeof to !== 'string') {\n throw rpcErrors.invalidParams(`Invalid \"to\" address`);\n }\n}\n\n/**\n * Validates a transaction batch request.\n *\n * @param options - Options bag.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.request - The batch request object.\n * @param options.sizeLimit - The maximum number of calls allowed in a batch request.\n */\nexport function validateBatchRequest({\n internalAccounts,\n request,\n sizeLimit,\n}: {\n internalAccounts: string[];\n request: TransactionBatchRequest;\n sizeLimit: number;\n}): void {\n const { origin } = request;\n const isExternal = origin && origin !== ORIGIN_METAMASK;\n\n const internalAccountsNormalized = internalAccounts.map((account) =>\n account.toLowerCase(),\n );\n\n if (\n isExternal &&\n request.transactions.some((nestedTransaction) => {\n const normalizedCallTo =\n nestedTransaction.params.to?.toLowerCase() as string;\n\n const callData = nestedTransaction.params.data;\n\n const isInternalAccount =\n internalAccountsNormalized.includes(normalizedCallTo);\n\n const hasData = Boolean(callData && callData !== '0x');\n\n return isInternalAccount && hasData;\n })\n ) {\n throw rpcErrors.invalidParams(\n 'External calls to internal accounts cannot include data',\n );\n }\n\n if (isExternal && request.transactions.length > sizeLimit) {\n throw new JsonRpcError(\n ErrorCode.BundleTooLarge,\n `Batch size cannot exceed ${sizeLimit}. got: ${request.transactions.length}`,\n );\n }\n}\n\n/**\n * Validates input data for transactions.\n *\n * @param value - The input data to validate.\n * @throws Throws invalid params if the input data is invalid.\n */\nfunction validateParamData(value?: string): void {\n if (value) {\n const ERC20Interface = new Interface(abiERC20);\n try {\n ERC20Interface.parseTransaction({ data: value });\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message.match(/BUFFER_OVERRUN/u)) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: data out-of-bounds, BUFFER_OVERRUN.',\n );\n }\n }\n }\n}\n\n/**\n * Validates chainId type.\n *\n * @param chainIdParams - The chain ID to validate.\n * @param chainIdNetworkClient - The chain ID of the network client.\n */\nfunction validateParamChainId(\n chainIdParams?: Hex,\n chainIdNetworkClient?: Hex,\n): void {\n if (\n chainIdParams &&\n chainIdNetworkClient &&\n chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams): void {\n if (txParams.gasPrice) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxPriorityFeePerGas',\n );\n ensureFieldIsValidHex(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxFeePerGas');\n }\n\n if (txParams.maxPriorityFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(\n txParams,\n 'maxPriorityFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxPriorityFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');\n }\n\n if (txParams.gasLimit) {\n ensureFieldIsValidHex(txParams, 'gasLimit');\n }\n\n if (txParams.gas) {\n ensureFieldIsValidHex(txParams, 'gas');\n }\n}\n\n/**\n * Ensures that the provided txParams has the proper 'type' specified for the\n * given field, if it is provided. If types do not match throws an\n * invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {ethErrors.rpc.invalidParams} Throws if type does not match the\n * expectations for provided field.\n */\nfunction ensureProperTransactionEnvelopeTypeProvided(\n txParams: TransactionParams,\n field: keyof TransactionParams,\n): void {\n const type = txParams.type as TransactionEnvelopeType | undefined;\n\n switch (field) {\n case 'authorizationList':\n if (type && type !== TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including authorizationList requires type: \"${TransactionEnvelopeType.setCode}\"`,\n );\n }\n break;\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (type && !TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.join(', ')}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (type && TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but included a gasPrice instead of maxFeePerGas and maxPriorityFeePerGas`,\n );\n }\n }\n}\n\n/**\n * Given two fields, ensure that the second field is not included in txParams,\n * and if it is throw an invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param fieldBeingValidated - The current field being validated\n * @param mutuallyExclusiveField - The field to ensure is not provided\n * @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is\n * present in txParams.\n */\nfunction ensureMutuallyExclusiveFieldsNotProvided(\n txParams: TransactionParams,\n fieldBeingValidated: GasFieldsToValidate,\n mutuallyExclusiveField: GasFieldsToValidate,\n): void {\n if (typeof txParams[mutuallyExclusiveField] !== 'undefined') {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: specified ${fieldBeingValidated} but also included ${mutuallyExclusiveField}, these cannot be mixed`,\n );\n }\n}\n\n/**\n * Ensures that the provided value for field is a valid hexadecimal.\n * Throws an invalidParams error if field is not a valid hexadecimal.\n *\n * @param data - The object containing the field\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex<DataType>(\n data: DataType,\n field: keyof DataType,\n): void {\n const value = data[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${String(field)} is not a valid hexadecimal string. got: (${String(\n value,\n )})`,\n );\n }\n}\n\n/**\n * Validate the authorization list property in the transaction parameters.\n *\n * @param txParams - The transaction parameters containing the authorization list to validate.\n */\nfunction validateAuthorizationList(txParams: TransactionParams): void {\n const { authorizationList } = txParams;\n\n if (!authorizationList) {\n return;\n }\n\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'authorizationList');\n\n if (!Array.isArray(authorizationList)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: authorizationList must be an array`,\n );\n }\n\n for (const authorization of authorizationList) {\n validateAuthorization(authorization);\n }\n}\n\n/**\n * Validate an authorization object.\n *\n * @param authorization - The authorization object to validate.\n */\nfunction validateAuthorization(authorization: Authorization): void {\n ensureFieldIsValidHex(authorization, 'address');\n validateHexLength(authorization.address, 20, 'address');\n\n for (const field of ['chainId', 'nonce', 'r', 's'] as const) {\n if (authorization[field]) {\n ensureFieldIsValidHex(authorization, field);\n }\n }\n\n const { yParity } = authorization;\n\n if (yParity && !['0x0', '0x1'].includes(yParity)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: yParity must be '0x0' or '0x1'. got: ${yParity}`,\n );\n }\n}\n\n/**\n * Validate the number of bytes in a hex string.\n *\n * @param value - The hex string to validate.\n * @param lengthBytes - The expected length in bytes.\n * @param fieldName - The name of the field being validated.\n */\nfunction validateHexLength(\n value: string,\n lengthBytes: number,\n fieldName: string,\n): void {\n const actualLengthBytes = remove0x(value).length / 2;\n\n if (actualLengthBytes !== lengthBytes) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${fieldName} must be ${lengthBytes} bytes. got: ${actualLengthBytes} bytes`,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.cts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,EAA2B,eAAe,EAAE,qBAAiB;AACpE,OAAO,KAAK,EAEV,uBAAuB,EACvB,iBAAiB,EAClB,qBAAiB;AAGlB,oBAAY,SAAS;IACnB,iBAAiB,OAAO;IACxB,cAAc,OAAO;IACrB,eAAe,OAAO;CACvB;AAcD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,IAAI,EACJ,IAAI,EACJ,gBAAgB,EAChB,MAAM,EACN,kBAAkB,EAClB,QAAQ,EACR,IAAI,GACL,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmChB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAC3B,mBAAmB,UAAO,EAC1B,OAAO,CAAC,EAAE,GAAG,GACZ,IAAI,CAUN;
|
|
1
|
+
{"version":3,"file":"validation.d.cts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,EAA2B,eAAe,EAAE,qBAAiB;AACpE,OAAO,KAAK,EAEV,uBAAuB,EACvB,iBAAiB,EAClB,qBAAiB;AAGlB,oBAAY,SAAS;IACnB,iBAAiB,OAAO;IACxB,cAAc,OAAO;IACrB,eAAe,OAAO;CACvB;AAcD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,IAAI,EACJ,IAAI,EACJ,gBAAgB,EAChB,MAAM,EACN,kBAAkB,EAClB,QAAQ,EACR,IAAI,GACL,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmChB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAC3B,mBAAmB,UAAO,EAC1B,OAAO,CAAC,EAAE,GAAG,GACZ,IAAI,CAUN;AAuID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,gBAAgB,EAChB,OAAO,EACP,SAAS,GACV,EAAE;IACD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,uBAAuB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAmCP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.mts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,EAA2B,eAAe,EAAE,qBAAiB;AACpE,OAAO,KAAK,EAEV,uBAAuB,EACvB,iBAAiB,EAClB,qBAAiB;AAGlB,oBAAY,SAAS;IACnB,iBAAiB,OAAO;IACxB,cAAc,OAAO;IACrB,eAAe,OAAO;CACvB;AAcD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,IAAI,EACJ,IAAI,EACJ,gBAAgB,EAChB,MAAM,EACN,kBAAkB,EAClB,QAAQ,EACR,IAAI,GACL,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmChB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAC3B,mBAAmB,UAAO,EAC1B,OAAO,CAAC,EAAE,GAAG,GACZ,IAAI,CAUN;
|
|
1
|
+
{"version":3,"file":"validation.d.mts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAG3C,OAAO,EAA2B,eAAe,EAAE,qBAAiB;AACpE,OAAO,KAAK,EAEV,uBAAuB,EACvB,iBAAiB,EAClB,qBAAiB;AAGlB,oBAAY,SAAS;IACnB,iBAAiB,OAAO;IACxB,cAAc,OAAO;IACrB,eAAe,OAAO;CACvB;AAcD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,IAAI,EACJ,IAAI,EACJ,gBAAgB,EAChB,MAAM,EACN,kBAAkB,EAClB,QAAQ,EACR,IAAI,GACL,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmChB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAC3B,mBAAmB,UAAO,EAC1B,OAAO,CAAC,EAAE,GAAG,GACZ,IAAI,CAUN;AAuID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,gBAAgB,EAChB,OAAO,EACP,SAAS,GACV,EAAE;IACD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,EAAE,uBAAuB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAmCP"}
|
|
@@ -127,17 +127,25 @@ function validateParamValue(value) {
|
|
|
127
127
|
*
|
|
128
128
|
* @param txParams - The transaction parameters object to validate.
|
|
129
129
|
* @throws Throws an error if the recipient address is invalid:
|
|
130
|
-
* - If the recipient address is
|
|
131
|
-
*
|
|
132
|
-
*
|
|
130
|
+
* - If the recipient address is missing (empty string, '0x', or undefined) and the
|
|
131
|
+
* transaction does not contain real bytecode (data must be longer than `0x`),
|
|
132
|
+
* an error is thrown. This prevents accidental contract deployments with empty
|
|
133
|
+
* `to` and empty `data` from locking funds.
|
|
134
|
+
* - If the recipient address is missing and the transaction contains real
|
|
135
|
+
* bytecode (data longer than `0x`), the "to" field is removed from the
|
|
136
|
+
* transaction parameters (legitimate contract deployment).
|
|
137
|
+
* - If the recipient address is not a valid hexadecimal Ethereum address, an
|
|
138
|
+
* error is thrown.
|
|
133
139
|
*/
|
|
134
140
|
function validateParamRecipient(txParams) {
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
const isMissingRecipient = txParams.to === '0x' || txParams.to === '' || txParams.to === undefined;
|
|
142
|
+
if (isMissingRecipient) {
|
|
143
|
+
const hasRealBytecode = Boolean(txParams.data && txParams.data !== '0x' && txParams.data.length > 2);
|
|
144
|
+
if (hasRealBytecode) {
|
|
137
145
|
delete txParams.to;
|
|
138
146
|
}
|
|
139
147
|
else {
|
|
140
|
-
throw rpcErrors.invalidParams(`Invalid "to" address.`);
|
|
148
|
+
throw rpcErrors.invalidParams(`Invalid "to" address: must be specified for transactions without contract deployment bytecode.`);
|
|
141
149
|
}
|
|
142
150
|
}
|
|
143
151
|
else if (txParams.to !== undefined && !isValidHexAddress(txParams.to)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.mjs","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { ORIGIN_METAMASK, isValidHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport { JsonRpcError, providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { isStrictHexString, remove0x } from '@metamask/utils';\n\nimport { TransactionEnvelopeType, TransactionType } from '../types';\nimport type {\n Authorization,\n TransactionBatchRequest,\n TransactionParams,\n} from '../types';\nimport { isEIP1559Transaction } from './utils';\n\nexport enum ErrorCode {\n DuplicateBundleId = 5720,\n BundleTooLarge = 5740,\n RejectedUpgrade = 5750,\n}\n\nconst TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [\n TransactionEnvelopeType.feeMarket,\n TransactionEnvelopeType.setCode,\n];\n\ntype GasFieldsToValidate =\n | 'gasPrice'\n | 'maxFeePerGas'\n | 'maxPriorityFeePerGas'\n | 'gas'\n | 'gasLimit';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param options - Options bag.\n * @param options.data - The data included in the transaction.\n * @param options.from - The address from which the transaction is initiated.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.origin - The origin or source of the transaction.\n * @param options.permittedAddresses - The permitted accounts for the given origin.\n * @param options.selectedAddress - The currently selected Ethereum address in the wallet.\n * @param options.txParams - The transaction parameters.\n * @param options.type - The transaction type.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin({\n data,\n from,\n internalAccounts,\n origin,\n permittedAddresses,\n txParams,\n type,\n}: {\n data?: string;\n from: string;\n internalAccounts?: string[];\n origin?: string;\n permittedAddresses?: string[];\n selectedAddress?: string;\n txParams: TransactionParams;\n type?: TransactionType;\n}): Promise<void> {\n const isInternal = !origin || origin === ORIGIN_METAMASK;\n\n if (isInternal) {\n return;\n }\n\n const { authorizationList, to, type: envelopeType } = txParams;\n\n if (permittedAddresses && !permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\n }\n\n if (type === TransactionType.batch) {\n return;\n }\n\n if (authorizationList || envelopeType === TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n 'External EIP-7702 transactions are not supported',\n );\n }\n\n const hasData = Boolean(data && data !== '0x');\n\n if (\n hasData &&\n internalAccounts?.some(\n (account) => account.toLowerCase() === to?.toLowerCase(),\n )\n ) {\n throw rpcErrors.invalidParams(\n 'External transactions to internal accounts cannot include data',\n );\n }\n}\n\n/**\n * Validates the transaction params for required properties and throws in\n * the event of any validation error.\n *\n * @param txParams - Transaction params object to validate.\n * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions.\n * @param chainId - The chain ID of the transaction.\n */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n chainId?: Hex,\n): void {\n validateEnvelopeType(txParams.type);\n validateEIP1559Compatibility(txParams, isEIP1559Compatible);\n validateParamFrom(txParams.from);\n validateParamRecipient(txParams);\n validateParamValue(txParams.value);\n validateParamData(txParams.data);\n validateParamChainId(txParams.chainId, chainId);\n validateGasFeeParams(txParams);\n validateAuthorizationList(txParams);\n}\n\n/**\n * Validates the `type` property, ensuring that if it is specified, it is a valid transaction envelope type.\n *\n * @param type - The transaction envelope type to validate.\n * @throws Throws invalid params if the type is not a valid transaction envelope type.\n */\nfunction validateEnvelopeType(type: string | undefined): void {\n if (\n type &&\n !Object.values(TransactionEnvelopeType).includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: \"${type}\". Must be one of: ${Object.values(\n TransactionEnvelopeType,\n ).join(', ')}`,\n );\n }\n}\n\n/**\n * Validates EIP-1559 compatibility for transaction creation.\n *\n * @param txParams - The transaction parameters to validate.\n * @param isEIP1559Compatible - Indicates if the current network supports EIP-1559.\n * @throws Throws invalid params if the transaction specifies EIP-1559 but the network does not support it.\n */\nfunction validateEIP1559Compatibility(\n txParams: TransactionParams,\n isEIP1559Compatible: boolean,\n): void {\n if (isEIP1559Transaction(txParams) && !isEIP1559Compatible) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: params specify an EIP-1559 transaction but the current network does not support EIP-1559',\n );\n }\n}\n\n/**\n * Validates value property, ensuring it is a valid positive integer number\n * denominated in wei.\n *\n * @param value - The value to validate, expressed as a string.\n * @throws Throws an error if the value is not a valid positive integer\n * number denominated in wei.\n * - If the value contains a hyphen (-), it is considered invalid.\n * - If the value contains a decimal point (.), it is considered invalid.\n * - If the value is not a finite number, is NaN, or is not a safe integer, it is considered invalid.\n */\nfunction validateParamValue(value?: string): void {\n if (value !== undefined) {\n if (value.includes('-')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": not a positive number.`,\n );\n }\n\n if (value.includes('.')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": number must be in wei.`,\n );\n }\n const intValue = parseInt(value, 10);\n const isValid =\n Number.isFinite(intValue) &&\n !Number.isNaN(intValue) &&\n !isNaN(Number(value)) &&\n Number.isSafeInteger(intValue);\n if (!isValid) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value ${value}: number must be a valid number.`,\n );\n }\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param txParams - The transaction parameters object to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamRecipient(txParams: TransactionParams): void {\n if (txParams.to === '0x' || txParams.to === undefined) {\n if (txParams.data) {\n delete txParams.to;\n } else {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n } else if (txParams.to !== undefined && !isValidHexAddress(txParams.to)) {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param from - The from property to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamFrom(from: string): void {\n if (!from || typeof from !== 'string') {\n throw rpcErrors.invalidParams(\n `Invalid \"from\" address ${from}: not a string.`,\n );\n }\n if (!isValidHexAddress(from)) {\n throw rpcErrors.invalidParams('Invalid \"from\" address.');\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param to - The to property to validate.\n * @throws Throws an error if the recipient address is invalid.\n */\nexport function validateParamTo(to?: string): void {\n if (!to || typeof to !== 'string') {\n throw rpcErrors.invalidParams(`Invalid \"to\" address`);\n }\n}\n\n/**\n * Validates a transaction batch request.\n *\n * @param options - Options bag.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.request - The batch request object.\n * @param options.sizeLimit - The maximum number of calls allowed in a batch request.\n */\nexport function validateBatchRequest({\n internalAccounts,\n request,\n sizeLimit,\n}: {\n internalAccounts: string[];\n request: TransactionBatchRequest;\n sizeLimit: number;\n}): void {\n const { origin } = request;\n const isExternal = origin && origin !== ORIGIN_METAMASK;\n\n const internalAccountsNormalized = internalAccounts.map((account) =>\n account.toLowerCase(),\n );\n\n if (\n isExternal &&\n request.transactions.some((nestedTransaction) => {\n const normalizedCallTo =\n nestedTransaction.params.to?.toLowerCase() as string;\n\n const callData = nestedTransaction.params.data;\n\n const isInternalAccount =\n internalAccountsNormalized.includes(normalizedCallTo);\n\n const hasData = Boolean(callData && callData !== '0x');\n\n return isInternalAccount && hasData;\n })\n ) {\n throw rpcErrors.invalidParams(\n 'External calls to internal accounts cannot include data',\n );\n }\n\n if (isExternal && request.transactions.length > sizeLimit) {\n throw new JsonRpcError(\n ErrorCode.BundleTooLarge,\n `Batch size cannot exceed ${sizeLimit}. got: ${request.transactions.length}`,\n );\n }\n}\n\n/**\n * Validates input data for transactions.\n *\n * @param value - The input data to validate.\n * @throws Throws invalid params if the input data is invalid.\n */\nfunction validateParamData(value?: string): void {\n if (value) {\n const ERC20Interface = new Interface(abiERC20);\n try {\n ERC20Interface.parseTransaction({ data: value });\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message.match(/BUFFER_OVERRUN/u)) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: data out-of-bounds, BUFFER_OVERRUN.',\n );\n }\n }\n }\n}\n\n/**\n * Validates chainId type.\n *\n * @param chainIdParams - The chain ID to validate.\n * @param chainIdNetworkClient - The chain ID of the network client.\n */\nfunction validateParamChainId(\n chainIdParams?: Hex,\n chainIdNetworkClient?: Hex,\n): void {\n if (\n chainIdParams &&\n chainIdNetworkClient &&\n chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams): void {\n if (txParams.gasPrice) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxPriorityFeePerGas',\n );\n ensureFieldIsValidHex(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxFeePerGas');\n }\n\n if (txParams.maxPriorityFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(\n txParams,\n 'maxPriorityFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxPriorityFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');\n }\n\n if (txParams.gasLimit) {\n ensureFieldIsValidHex(txParams, 'gasLimit');\n }\n\n if (txParams.gas) {\n ensureFieldIsValidHex(txParams, 'gas');\n }\n}\n\n/**\n * Ensures that the provided txParams has the proper 'type' specified for the\n * given field, if it is provided. If types do not match throws an\n * invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {ethErrors.rpc.invalidParams} Throws if type does not match the\n * expectations for provided field.\n */\nfunction ensureProperTransactionEnvelopeTypeProvided(\n txParams: TransactionParams,\n field: keyof TransactionParams,\n): void {\n const type = txParams.type as TransactionEnvelopeType | undefined;\n\n switch (field) {\n case 'authorizationList':\n if (type && type !== TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including authorizationList requires type: \"${TransactionEnvelopeType.setCode}\"`,\n );\n }\n break;\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (type && !TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.join(', ')}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (type && TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but included a gasPrice instead of maxFeePerGas and maxPriorityFeePerGas`,\n );\n }\n }\n}\n\n/**\n * Given two fields, ensure that the second field is not included in txParams,\n * and if it is throw an invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param fieldBeingValidated - The current field being validated\n * @param mutuallyExclusiveField - The field to ensure is not provided\n * @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is\n * present in txParams.\n */\nfunction ensureMutuallyExclusiveFieldsNotProvided(\n txParams: TransactionParams,\n fieldBeingValidated: GasFieldsToValidate,\n mutuallyExclusiveField: GasFieldsToValidate,\n): void {\n if (typeof txParams[mutuallyExclusiveField] !== 'undefined') {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: specified ${fieldBeingValidated} but also included ${mutuallyExclusiveField}, these cannot be mixed`,\n );\n }\n}\n\n/**\n * Ensures that the provided value for field is a valid hexadecimal.\n * Throws an invalidParams error if field is not a valid hexadecimal.\n *\n * @param data - The object containing the field\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex<DataType>(\n data: DataType,\n field: keyof DataType,\n): void {\n const value = data[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${String(field)} is not a valid hexadecimal string. got: (${String(\n value,\n )})`,\n );\n }\n}\n\n/**\n * Validate the authorization list property in the transaction parameters.\n *\n * @param txParams - The transaction parameters containing the authorization list to validate.\n */\nfunction validateAuthorizationList(txParams: TransactionParams): void {\n const { authorizationList } = txParams;\n\n if (!authorizationList) {\n return;\n }\n\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'authorizationList');\n\n if (!Array.isArray(authorizationList)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: authorizationList must be an array`,\n );\n }\n\n for (const authorization of authorizationList) {\n validateAuthorization(authorization);\n }\n}\n\n/**\n * Validate an authorization object.\n *\n * @param authorization - The authorization object to validate.\n */\nfunction validateAuthorization(authorization: Authorization): void {\n ensureFieldIsValidHex(authorization, 'address');\n validateHexLength(authorization.address, 20, 'address');\n\n for (const field of ['chainId', 'nonce', 'r', 's'] as const) {\n if (authorization[field]) {\n ensureFieldIsValidHex(authorization, field);\n }\n }\n\n const { yParity } = authorization;\n\n if (yParity && !['0x0', '0x1'].includes(yParity)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: yParity must be '0x0' or '0x1'. got: ${yParity}`,\n );\n }\n}\n\n/**\n * Validate the number of bytes in a hex string.\n *\n * @param value - The hex string to validate.\n * @param lengthBytes - The expected length in bytes.\n * @param fieldName - The name of the field being validated.\n */\nfunction validateHexLength(\n value: string,\n lengthBytes: number,\n fieldName: string,\n): void {\n const actualLengthBytes = remove0x(value).length / 2;\n\n if (actualLengthBytes !== lengthBytes) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${fieldName} must be ${lengthBytes} bytes. got: ${actualLengthBytes} bytes`,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validation.mjs","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { ORIGIN_METAMASK, isValidHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport { JsonRpcError, providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type { Hex } from '@metamask/utils';\nimport { isStrictHexString, remove0x } from '@metamask/utils';\n\nimport { TransactionEnvelopeType, TransactionType } from '../types';\nimport type {\n Authorization,\n TransactionBatchRequest,\n TransactionParams,\n} from '../types';\nimport { isEIP1559Transaction } from './utils';\n\nexport enum ErrorCode {\n DuplicateBundleId = 5720,\n BundleTooLarge = 5740,\n RejectedUpgrade = 5750,\n}\n\nconst TRANSACTION_ENVELOPE_TYPES_FEE_MARKET = [\n TransactionEnvelopeType.feeMarket,\n TransactionEnvelopeType.setCode,\n];\n\ntype GasFieldsToValidate =\n | 'gasPrice'\n | 'maxFeePerGas'\n | 'maxPriorityFeePerGas'\n | 'gas'\n | 'gasLimit';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param options - Options bag.\n * @param options.data - The data included in the transaction.\n * @param options.from - The address from which the transaction is initiated.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.origin - The origin or source of the transaction.\n * @param options.permittedAddresses - The permitted accounts for the given origin.\n * @param options.selectedAddress - The currently selected Ethereum address in the wallet.\n * @param options.txParams - The transaction parameters.\n * @param options.type - The transaction type.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin({\n data,\n from,\n internalAccounts,\n origin,\n permittedAddresses,\n txParams,\n type,\n}: {\n data?: string;\n from: string;\n internalAccounts?: string[];\n origin?: string;\n permittedAddresses?: string[];\n selectedAddress?: string;\n txParams: TransactionParams;\n type?: TransactionType;\n}): Promise<void> {\n const isInternal = !origin || origin === ORIGIN_METAMASK;\n\n if (isInternal) {\n return;\n }\n\n const { authorizationList, to, type: envelopeType } = txParams;\n\n if (permittedAddresses && !permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\n }\n\n if (type === TransactionType.batch) {\n return;\n }\n\n if (authorizationList || envelopeType === TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n 'External EIP-7702 transactions are not supported',\n );\n }\n\n const hasData = Boolean(data && data !== '0x');\n\n if (\n hasData &&\n internalAccounts?.some(\n (account) => account.toLowerCase() === to?.toLowerCase(),\n )\n ) {\n throw rpcErrors.invalidParams(\n 'External transactions to internal accounts cannot include data',\n );\n }\n}\n\n/**\n * Validates the transaction params for required properties and throws in\n * the event of any validation error.\n *\n * @param txParams - Transaction params object to validate.\n * @param isEIP1559Compatible - whether or not the current network supports EIP-1559 transactions.\n * @param chainId - The chain ID of the transaction.\n */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n chainId?: Hex,\n): void {\n validateEnvelopeType(txParams.type);\n validateEIP1559Compatibility(txParams, isEIP1559Compatible);\n validateParamFrom(txParams.from);\n validateParamRecipient(txParams);\n validateParamValue(txParams.value);\n validateParamData(txParams.data);\n validateParamChainId(txParams.chainId, chainId);\n validateGasFeeParams(txParams);\n validateAuthorizationList(txParams);\n}\n\n/**\n * Validates the `type` property, ensuring that if it is specified, it is a valid transaction envelope type.\n *\n * @param type - The transaction envelope type to validate.\n * @throws Throws invalid params if the type is not a valid transaction envelope type.\n */\nfunction validateEnvelopeType(type: string | undefined): void {\n if (\n type &&\n !Object.values(TransactionEnvelopeType).includes(\n type as TransactionEnvelopeType,\n )\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: \"${type}\". Must be one of: ${Object.values(\n TransactionEnvelopeType,\n ).join(', ')}`,\n );\n }\n}\n\n/**\n * Validates EIP-1559 compatibility for transaction creation.\n *\n * @param txParams - The transaction parameters to validate.\n * @param isEIP1559Compatible - Indicates if the current network supports EIP-1559.\n * @throws Throws invalid params if the transaction specifies EIP-1559 but the network does not support it.\n */\nfunction validateEIP1559Compatibility(\n txParams: TransactionParams,\n isEIP1559Compatible: boolean,\n): void {\n if (isEIP1559Transaction(txParams) && !isEIP1559Compatible) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: params specify an EIP-1559 transaction but the current network does not support EIP-1559',\n );\n }\n}\n\n/**\n * Validates value property, ensuring it is a valid positive integer number\n * denominated in wei.\n *\n * @param value - The value to validate, expressed as a string.\n * @throws Throws an error if the value is not a valid positive integer\n * number denominated in wei.\n * - If the value contains a hyphen (-), it is considered invalid.\n * - If the value contains a decimal point (.), it is considered invalid.\n * - If the value is not a finite number, is NaN, or is not a safe integer, it is considered invalid.\n */\nfunction validateParamValue(value?: string): void {\n if (value !== undefined) {\n if (value.includes('-')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": not a positive number.`,\n );\n }\n\n if (value.includes('.')) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value \"${value}\": number must be in wei.`,\n );\n }\n const intValue = parseInt(value, 10);\n const isValid =\n Number.isFinite(intValue) &&\n !Number.isNaN(intValue) &&\n !isNaN(Number(value)) &&\n Number.isSafeInteger(intValue);\n if (!isValid) {\n throw rpcErrors.invalidParams(\n `Invalid transaction value ${value}: number must be a valid number.`,\n );\n }\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param txParams - The transaction parameters object to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is missing (empty string, '0x', or undefined) and the\n * transaction does not contain real bytecode (data must be longer than `0x`),\n * an error is thrown. This prevents accidental contract deployments with empty\n * `to` and empty `data` from locking funds.\n * - If the recipient address is missing and the transaction contains real\n * bytecode (data longer than `0x`), the \"to\" field is removed from the\n * transaction parameters (legitimate contract deployment).\n * - If the recipient address is not a valid hexadecimal Ethereum address, an\n * error is thrown.\n */\nfunction validateParamRecipient(txParams: TransactionParams): void {\n const isMissingRecipient =\n txParams.to === '0x' || txParams.to === '' || txParams.to === undefined;\n\n if (isMissingRecipient) {\n const hasRealBytecode = Boolean(\n txParams.data && txParams.data !== '0x' && txParams.data.length > 2,\n );\n\n if (hasRealBytecode) {\n delete txParams.to;\n } else {\n throw rpcErrors.invalidParams(\n `Invalid \"to\" address: must be specified for transactions without contract deployment bytecode.`,\n );\n }\n } else if (txParams.to !== undefined && !isValidHexAddress(txParams.to)) {\n throw rpcErrors.invalidParams(`Invalid \"to\" address.`);\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param from - The from property to validate.\n * @throws Throws an error if the recipient address is invalid:\n * - If the recipient address is an empty string ('0x') or undefined and the transaction contains data,\n * the \"to\" field is removed from the transaction parameters.\n * - If the recipient address is not a valid hexadecimal Ethereum address, an error is thrown.\n */\nfunction validateParamFrom(from: string): void {\n if (!from || typeof from !== 'string') {\n throw rpcErrors.invalidParams(\n `Invalid \"from\" address ${from}: not a string.`,\n );\n }\n if (!isValidHexAddress(from)) {\n throw rpcErrors.invalidParams('Invalid \"from\" address.');\n }\n}\n\n/**\n * Validates the recipient address in a transaction's parameters.\n *\n * @param to - The to property to validate.\n * @throws Throws an error if the recipient address is invalid.\n */\nexport function validateParamTo(to?: string): void {\n if (!to || typeof to !== 'string') {\n throw rpcErrors.invalidParams(`Invalid \"to\" address`);\n }\n}\n\n/**\n * Validates a transaction batch request.\n *\n * @param options - Options bag.\n * @param options.internalAccounts - The internal accounts added to the wallet.\n * @param options.request - The batch request object.\n * @param options.sizeLimit - The maximum number of calls allowed in a batch request.\n */\nexport function validateBatchRequest({\n internalAccounts,\n request,\n sizeLimit,\n}: {\n internalAccounts: string[];\n request: TransactionBatchRequest;\n sizeLimit: number;\n}): void {\n const { origin } = request;\n const isExternal = origin && origin !== ORIGIN_METAMASK;\n\n const internalAccountsNormalized = internalAccounts.map((account) =>\n account.toLowerCase(),\n );\n\n if (\n isExternal &&\n request.transactions.some((nestedTransaction) => {\n const normalizedCallTo =\n nestedTransaction.params.to?.toLowerCase() as string;\n\n const callData = nestedTransaction.params.data;\n\n const isInternalAccount =\n internalAccountsNormalized.includes(normalizedCallTo);\n\n const hasData = Boolean(callData && callData !== '0x');\n\n return isInternalAccount && hasData;\n })\n ) {\n throw rpcErrors.invalidParams(\n 'External calls to internal accounts cannot include data',\n );\n }\n\n if (isExternal && request.transactions.length > sizeLimit) {\n throw new JsonRpcError(\n ErrorCode.BundleTooLarge,\n `Batch size cannot exceed ${sizeLimit}. got: ${request.transactions.length}`,\n );\n }\n}\n\n/**\n * Validates input data for transactions.\n *\n * @param value - The input data to validate.\n * @throws Throws invalid params if the input data is invalid.\n */\nfunction validateParamData(value?: string): void {\n if (value) {\n const ERC20Interface = new Interface(abiERC20);\n try {\n ERC20Interface.parseTransaction({ data: value });\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n if (error.message.match(/BUFFER_OVERRUN/u)) {\n throw rpcErrors.invalidParams(\n 'Invalid transaction params: data out-of-bounds, BUFFER_OVERRUN.',\n );\n }\n }\n }\n}\n\n/**\n * Validates chainId type.\n *\n * @param chainIdParams - The chain ID to validate.\n * @param chainIdNetworkClient - The chain ID of the network client.\n */\nfunction validateParamChainId(\n chainIdParams?: Hex,\n chainIdNetworkClient?: Hex,\n): void {\n if (\n chainIdParams &&\n chainIdNetworkClient &&\n chainIdParams.toLowerCase?.() !== chainIdNetworkClient.toLowerCase()\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: chainId must match the network client, got: ${chainIdParams}, expected: ${chainIdNetworkClient}`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams): void {\n if (txParams.gasPrice) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'gasPrice',\n 'maxPriorityFeePerGas',\n );\n ensureFieldIsValidHex(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxFeePerGas');\n }\n\n if (txParams.maxPriorityFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(\n txParams,\n 'maxPriorityFeePerGas',\n );\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxPriorityFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');\n }\n\n if (txParams.gasLimit) {\n ensureFieldIsValidHex(txParams, 'gasLimit');\n }\n\n if (txParams.gas) {\n ensureFieldIsValidHex(txParams, 'gas');\n }\n}\n\n/**\n * Ensures that the provided txParams has the proper 'type' specified for the\n * given field, if it is provided. If types do not match throws an\n * invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {ethErrors.rpc.invalidParams} Throws if type does not match the\n * expectations for provided field.\n */\nfunction ensureProperTransactionEnvelopeTypeProvided(\n txParams: TransactionParams,\n field: keyof TransactionParams,\n): void {\n const type = txParams.type as TransactionEnvelopeType | undefined;\n\n switch (field) {\n case 'authorizationList':\n if (type && type !== TransactionEnvelopeType.setCode) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including authorizationList requires type: \"${TransactionEnvelopeType.setCode}\"`,\n );\n }\n break;\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (type && !TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.join(', ')}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (type && TRANSACTION_ENVELOPE_TYPES_FEE_MARKET.includes(type)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${type}\" but included a gasPrice instead of maxFeePerGas and maxPriorityFeePerGas`,\n );\n }\n }\n}\n\n/**\n * Given two fields, ensure that the second field is not included in txParams,\n * and if it is throw an invalidParams error.\n *\n * @param txParams - The transaction parameters object\n * @param fieldBeingValidated - The current field being validated\n * @param mutuallyExclusiveField - The field to ensure is not provided\n * @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is\n * present in txParams.\n */\nfunction ensureMutuallyExclusiveFieldsNotProvided(\n txParams: TransactionParams,\n fieldBeingValidated: GasFieldsToValidate,\n mutuallyExclusiveField: GasFieldsToValidate,\n): void {\n if (typeof txParams[mutuallyExclusiveField] !== 'undefined') {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: specified ${fieldBeingValidated} but also included ${mutuallyExclusiveField}, these cannot be mixed`,\n );\n }\n}\n\n/**\n * Ensures that the provided value for field is a valid hexadecimal.\n * Throws an invalidParams error if field is not a valid hexadecimal.\n *\n * @param data - The object containing the field\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex<DataType>(\n data: DataType,\n field: keyof DataType,\n): void {\n const value = data[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${String(field)} is not a valid hexadecimal string. got: (${String(\n value,\n )})`,\n );\n }\n}\n\n/**\n * Validate the authorization list property in the transaction parameters.\n *\n * @param txParams - The transaction parameters containing the authorization list to validate.\n */\nfunction validateAuthorizationList(txParams: TransactionParams): void {\n const { authorizationList } = txParams;\n\n if (!authorizationList) {\n return;\n }\n\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'authorizationList');\n\n if (!Array.isArray(authorizationList)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: authorizationList must be an array`,\n );\n }\n\n for (const authorization of authorizationList) {\n validateAuthorization(authorization);\n }\n}\n\n/**\n * Validate an authorization object.\n *\n * @param authorization - The authorization object to validate.\n */\nfunction validateAuthorization(authorization: Authorization): void {\n ensureFieldIsValidHex(authorization, 'address');\n validateHexLength(authorization.address, 20, 'address');\n\n for (const field of ['chainId', 'nonce', 'r', 's'] as const) {\n if (authorization[field]) {\n ensureFieldIsValidHex(authorization, field);\n }\n }\n\n const { yParity } = authorization;\n\n if (yParity && !['0x0', '0x1'].includes(yParity)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: yParity must be '0x0' or '0x1'. got: ${yParity}`,\n );\n }\n}\n\n/**\n * Validate the number of bytes in a hex string.\n *\n * @param value - The hex string to validate.\n * @param lengthBytes - The expected length in bytes.\n * @param fieldName - The name of the field being validated.\n */\nfunction validateHexLength(\n value: string,\n lengthBytes: number,\n fieldName: string,\n): void {\n const actualLengthBytes = remove0x(value).length / 2;\n\n if (actualLengthBytes !== lengthBytes) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${fieldName} must be ${lengthBytes} bytes. got: ${actualLengthBytes} bytes`,\n );\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/transaction-controller",
|
|
3
|
-
"version": "65.2.0-preview-
|
|
3
|
+
"version": "65.2.0-preview-5e603a6c0",
|
|
4
4
|
"description": "Stores transactions alongside their periodically updated statuses and manages interactions such as approval and cancellation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|