@metamask-previews/transaction-controller 38.2.0-preview-db2c53b → 38.2.0-preview-651fe366
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.
|
@@ -5,8 +5,9 @@ const abi_1 = require("@ethersproject/abi");
|
|
|
5
5
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
6
6
|
const metamask_eth_abis_1 = require("@metamask/metamask-eth-abis");
|
|
7
7
|
const rpc_errors_1 = require("@metamask/rpc-errors");
|
|
8
|
+
const utils_1 = require("@metamask/utils");
|
|
8
9
|
const types_1 = require("../types.cjs");
|
|
9
|
-
const
|
|
10
|
+
const utils_2 = require("./utils.cjs");
|
|
10
11
|
/**
|
|
11
12
|
* Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.
|
|
12
13
|
*
|
|
@@ -75,7 +76,7 @@ function validateEnvelopeType(type) {
|
|
|
75
76
|
* @throws Throws invalid params if the transaction specifies EIP-1559 but the network does not support it.
|
|
76
77
|
*/
|
|
77
78
|
function validateEIP1559Compatibility(txParams, isEIP1559Compatible) {
|
|
78
|
-
if ((0,
|
|
79
|
+
if ((0, utils_2.isEIP1559Transaction)(txParams) && !isEIP1559Compatible) {
|
|
79
80
|
throw rpc_errors_1.rpcErrors.invalidParams('Invalid transaction params: params specify an EIP-1559 transaction but the current network does not support EIP-1559');
|
|
80
81
|
}
|
|
81
82
|
}
|
|
@@ -193,17 +194,17 @@ function validateGasFeeParams(txParams) {
|
|
|
193
194
|
ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');
|
|
194
195
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'gasPrice', 'maxFeePerGas');
|
|
195
196
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'gasPrice', 'maxPriorityFeePerGas');
|
|
196
|
-
|
|
197
|
+
ensureFieldIsValidHex(txParams, 'gasPrice');
|
|
197
198
|
}
|
|
198
199
|
if (txParams.maxFeePerGas) {
|
|
199
200
|
ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');
|
|
200
201
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'maxFeePerGas', 'gasPrice');
|
|
201
|
-
|
|
202
|
+
ensureFieldIsValidHex(txParams, 'maxFeePerGas');
|
|
202
203
|
}
|
|
203
204
|
if (txParams.maxPriorityFeePerGas) {
|
|
204
205
|
ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxPriorityFeePerGas');
|
|
205
206
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'maxPriorityFeePerGas', 'gasPrice');
|
|
206
|
-
|
|
207
|
+
ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
210
|
/**
|
|
@@ -249,19 +250,17 @@ function ensureMutuallyExclusiveFieldsNotProvided(txParams, fieldBeingValidated,
|
|
|
249
250
|
}
|
|
250
251
|
}
|
|
251
252
|
/**
|
|
252
|
-
* Ensures that the provided value for field is a
|
|
253
|
-
* invalidParams error if field is not a
|
|
253
|
+
* Ensures that the provided value for field is a valid hexadecimal.
|
|
254
|
+
* Throws an invalidParams error if field is not a valid hexadecimal.
|
|
254
255
|
*
|
|
255
256
|
* @param txParams - The transaction parameters object
|
|
256
257
|
* @param field - The current field being validated
|
|
257
|
-
* @throws {rpcErrors.invalidParams} Throws if field is not a
|
|
258
|
+
* @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal
|
|
258
259
|
*/
|
|
259
|
-
function
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
264
|
-
`Invalid transaction params: ${field} is not a string. got: (${txParams[field]})`);
|
|
260
|
+
function ensureFieldIsValidHex(txParams, field) {
|
|
261
|
+
const value = txParams[field];
|
|
262
|
+
if (typeof value !== 'string' || !(0, utils_1.isStrictHexString)(value)) {
|
|
263
|
+
throw rpc_errors_1.rpcErrors.invalidParams(`Invalid transaction params: ${field} is not a valid hexadecimal. got: (${String(value)})`);
|
|
265
264
|
}
|
|
266
265
|
}
|
|
267
266
|
//# sourceMappingURL=validation.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.cjs","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":";;;AAAA,4CAA+C;AAC/C,iEAAgF;AAChF,mEAAuD;AACvD,qDAAiE;AAEjE,wCAA2E;AAC3E,uCAA+C;AAI/C;;;;;;;;GAQG;AACI,KAAK,UAAU,yBAAyB,CAC7C,kBAA4B,EAC5B,eAAuB,EACvB,IAAY,EACZ,MAAc;IAEd,IAAI,MAAM,KAAK,kCAAe,EAAE;QAC9B,mEAAmE;QACnE,IAAI,IAAI,KAAK,eAAe,EAAE;YAC5B,MAAM,sBAAS,CAAC,QAAQ,CAAC;gBACvB,OAAO,EAAE,4DAA4D;gBACrE,IAAI,EAAE;oBACJ,MAAM;oBACN,WAAW,EAAE,IAAI;oBACjB,eAAe;iBAChB;aACF,CAAC,CAAC;SACJ;QACD,OAAO;KACR;IAED,0FAA0F;IAC1F,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QACtC,MAAM,2BAAc,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;KACzD;AACH,CAAC;AAzBD,8DAyBC;AAED;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAC9B,QAA2B,EAC3B,mBAAmB,GAAG,IAAI;IAE1B,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,4BAA4B,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;IAC5D,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACjC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACnC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACjC,oBAAoB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACvC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC;AAZD,4CAYC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,IAAwB;IACpD,IACE,IAAI;QACJ,CAAC,MAAM,CAAC,MAAM,CAAC,+BAAuB,CAAC,CAAC,QAAQ,CAC9C,IAA+B,CAChC,EACD;QACA,MAAM,sBAAS,CAAC,aAAa,CAC3B,uCAAuC,IAAI,sBAAsB,MAAM,CAAC,MAAM,CAC5E,+BAAuB,CACxB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACf,CAAC;KACH;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,4BAA4B,CACnC,QAA2B,EAC3B,mBAA4B;IAE5B,IAAI,IAAA,4BAAoB,EAAC,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE;QAC1D,MAAM,sBAAS,CAAC,aAAa,CAC3B,sHAAsH,CACvH,CAAC;KACH;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,KAAK,KAAK,SAAS,EAAE;QACvB,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YACvB,MAAM,sBAAS,CAAC,aAAa,CAC3B,8BAA8B,KAAK,2BAA2B,CAC/D,CAAC;SACH;QAED,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YACvB,MAAM,sBAAS,CAAC,aAAa,CAC3B,8BAA8B,KAAK,2BAA2B,CAC/D,CAAC;SACH;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,OAAO,GACX,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACzB,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YACvB,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrB,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,sBAAS,CAAC,aAAa,CAC3B,6BAA6B,KAAK,kCAAkC,CACrE,CAAC;SACH;KACF;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,sBAAsB,CAAC,QAA2B;IACzD,IAAI,QAAQ,CAAC,EAAE,KAAK,IAAI,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE;QACrD,IAAI,QAAQ,CAAC,IAAI,EAAE;YACjB,OAAO,QAAQ,CAAC,EAAE,CAAC;SACpB;aAAM;YACL,MAAM,sBAAS,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC;SACxD;KACF;SAAM,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,IAAA,oCAAiB,EAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;QACvE,MAAM,sBAAS,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC;KACxD;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QACrC,MAAM,sBAAS,CAAC,aAAa,CAC3B,0BAA0B,IAAI,iBAAiB,CAChD,CAAC;KACH;IACD,IAAI,CAAC,IAAA,oCAAiB,EAAC,IAAI,CAAC,EAAE;QAC5B,MAAM,sBAAS,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;KAC1D;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,KAAK,EAAE;QACT,MAAM,cAAc,GAAG,IAAI,eAAS,CAAC,4BAAQ,CAAC,CAAC;QAC/C,IAAI;YACF,cAAc,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,gCAAgC;YAChC,8DAA8D;SAC/D;QAAC,OAAO,KAAU,EAAE;YACnB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE;gBAC1C,MAAM,sBAAS,CAAC,aAAa,CAC3B,iEAAiE,CAClE,CAAC;aACH;SACF;KACF;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,OAAoC;IAChE,IACE,OAAO,KAAK,SAAS;QACrB,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,OAAO,KAAK,QAAQ,EAC3B;QACA,MAAM,sBAAS,CAAC,aAAa;QAC3B,gFAAgF;QAChF,4EAA4E;QAC5E,4EAA4E,OAAO,GAAG,CACvF,CAAC;KACH;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,QAA2B;IACvD,IAAI,QAAQ,CAAC,QAAQ,EAAE;QACrB,2CAA2C,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAClE,wCAAwC,CACtC,QAAQ,EACR,UAAU,EACV,cAAc,CACf,CAAC;QACF,wCAAwC,CACtC,QAAQ,EACR,UAAU,EACV,sBAAsB,CACvB,CAAC;QACF,mBAAmB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;KAC3C;IAED,IAAI,QAAQ,CAAC,YAAY,EAAE;QACzB,2CAA2C,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QACtE,wCAAwC,CACtC,QAAQ,EACR,cAAc,EACd,UAAU,CACX,CAAC;QACF,mBAAmB,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;KAC/C;IAED,IAAI,QAAQ,CAAC,oBAAoB,EAAE;QACjC,2CAA2C,CACzC,QAAQ,EACR,sBAAsB,CACvB,CAAC;QACF,wCAAwC,CACtC,QAAQ,EACR,sBAAsB,EACtB,UAAU,CACX,CAAC;QACF,mBAAmB,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;KACvD;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,2CAA2C,CAClD,QAA2B,EAC3B,KAA0B;IAE1B,QAAQ,KAAK,EAAE;QACb,KAAK,cAAc,CAAC;QACpB,KAAK,sBAAsB;YACzB,IACE,QAAQ,CAAC,IAAI;gBACb,QAAQ,CAAC,IAAI,KAAK,+BAAuB,CAAC,SAAS,EACnD;gBACA,MAAM,sBAAS,CAAC,aAAa,CAC3B,sDAAsD,QAAQ,CAAC,IAAI,yEAAyE,+BAAuB,CAAC,SAAS,GAAG,CACjL,CAAC;aACH;YACD,MAAM;QACR,KAAK,UAAU,CAAC;QAChB;YACE,IACE,QAAQ,CAAC,IAAI;gBACb,QAAQ,CAAC,IAAI,KAAK,+BAAuB,CAAC,SAAS,EACnD;gBACA,MAAM,sBAAS,CAAC,aAAa,CAC3B,sDAAsD,QAAQ,CAAC,IAAI,4EAA4E,CAChJ,CAAC;aACH;KACJ;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,wCAAwC,CAC/C,QAA2B,EAC3B,mBAAwC,EACxC,sBAA2C;IAE3C,IAAI,OAAO,QAAQ,CAAC,sBAAsB,CAAC,KAAK,WAAW,EAAE;QAC3D,MAAM,sBAAS,CAAC,aAAa,CAC3B,yCAAyC,mBAAmB,sBAAsB,sBAAsB,yBAAyB,CAClI,CAAC;KACH;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAC1B,QAA2B,EAC3B,KAA0B;IAE1B,IAAI,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE;QACvC,MAAM,sBAAS,CAAC,aAAa;QAC3B,gFAAgF;QAChF,4EAA4E;QAC5E,+BAA+B,KAAK,2BAA2B,QAAQ,CAAC,KAAK,CAAC,GAAG,CAClF,CAAC;KACH;AACH,CAAC","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { ORIGIN_METAMASK, isValidHexAddress } from '@metamask/controller-utils';\nimport { abiERC20 } from '@metamask/metamask-eth-abis';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\n\nimport { TransactionEnvelopeType, type TransactionParams } from '../types';\nimport { isEIP1559Transaction } from './utils';\n\ntype GasFieldsToValidate = 'gasPrice' | 'maxFeePerGas' | 'maxPriorityFeePerGas';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param permittedAddresses - The permitted accounts for the given origin.\n * @param selectedAddress - The currently selected Ethereum address in the wallet.\n * @param from - The address from which the transaction is initiated.\n * @param origin - The origin or source of the transaction.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin(\n permittedAddresses: string[],\n selectedAddress: string,\n from: string,\n origin: string,\n) {\n if (origin === ORIGIN_METAMASK) {\n // Ensure the 'from' address matches the currently selected address\n if (from !== selectedAddress) {\n throw rpcErrors.internal({\n message: `Internally initiated transaction is using invalid account.`,\n data: {\n origin,\n fromAddress: from,\n selectedAddress,\n },\n });\n }\n return;\n }\n\n // Check if the origin has permissions to initiate transactions from the specified address\n if (!permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\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 */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n) {\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);\n validateGasFeeParams(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) {\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) {\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) {\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) {\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) {\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 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) {\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 chainId - The chainId to validate.\n */\nfunction validateParamChainId(chainId: number | string | undefined) {\n if (\n chainId !== undefined &&\n typeof chainId !== 'number' &&\n typeof chainId !== 'string'\n ) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Invalid transaction params: chainId is not a Number or hex string. got: (${chainId})`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams) {\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 ensureFieldIsString(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsString(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 ensureFieldIsString(txParams, 'maxPriorityFeePerGas');\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: GasFieldsToValidate,\n) {\n switch (field) {\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (\n txParams.type &&\n txParams.type !== TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TransactionEnvelopeType.feeMarket}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (\n txParams.type &&\n txParams.type === TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.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) {\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 string, throws an\n * invalidParams error if field is not a string.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a string\n */\nfunction ensureFieldIsString(\n txParams: TransactionParams,\n field: GasFieldsToValidate,\n) {\n if (typeof txParams[field] !== 'string') {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Invalid transaction params: ${field} is not a string. got: (${txParams[field]})`,\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 { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport { isStrictHexString } from '@metamask/utils';\n\nimport { TransactionEnvelopeType, type TransactionParams } from '../types';\nimport { isEIP1559Transaction } from './utils';\n\ntype GasFieldsToValidate = 'gasPrice' | 'maxFeePerGas' | 'maxPriorityFeePerGas';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param permittedAddresses - The permitted accounts for the given origin.\n * @param selectedAddress - The currently selected Ethereum address in the wallet.\n * @param from - The address from which the transaction is initiated.\n * @param origin - The origin or source of the transaction.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin(\n permittedAddresses: string[],\n selectedAddress: string,\n from: string,\n origin: string,\n) {\n if (origin === ORIGIN_METAMASK) {\n // Ensure the 'from' address matches the currently selected address\n if (from !== selectedAddress) {\n throw rpcErrors.internal({\n message: `Internally initiated transaction is using invalid account.`,\n data: {\n origin,\n fromAddress: from,\n selectedAddress,\n },\n });\n }\n return;\n }\n\n // Check if the origin has permissions to initiate transactions from the specified address\n if (!permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\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 */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n) {\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);\n validateGasFeeParams(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) {\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) {\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) {\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) {\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) {\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 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) {\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 chainId - The chainId to validate.\n */\nfunction validateParamChainId(chainId: number | string | undefined) {\n if (\n chainId !== undefined &&\n typeof chainId !== 'number' &&\n typeof chainId !== 'string'\n ) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Invalid transaction params: chainId is not a Number or hex string. got: (${chainId})`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams) {\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\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: GasFieldsToValidate,\n) {\n switch (field) {\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (\n txParams.type &&\n txParams.type !== TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TransactionEnvelopeType.feeMarket}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (\n txParams.type &&\n txParams.type === TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.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) {\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 txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex(\n txParams: TransactionParams,\n field: GasFieldsToValidate,\n) {\n const value = txParams[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${field} is not a valid hexadecimal. got: (${String(\n value,\n )})`,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.cts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validation.d.cts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,iBAAiB,EAAE,qBAAiB;AAK3E;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,kBAAkB,EAAE,MAAM,EAAE,EAC5B,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,iBAqBf;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAC3B,mBAAmB,UAAO,QAU3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.mts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validation.d.mts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,iBAAiB,EAAE,qBAAiB;AAK3E;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,kBAAkB,EAAE,MAAM,EAAE,EAC5B,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,iBAqBf;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAC3B,mBAAmB,UAAO,QAU3B"}
|
|
@@ -2,6 +2,7 @@ import { Interface } from "@ethersproject/abi";
|
|
|
2
2
|
import { ORIGIN_METAMASK, isValidHexAddress } from "@metamask/controller-utils";
|
|
3
3
|
import { abiERC20 } from "@metamask/metamask-eth-abis";
|
|
4
4
|
import { providerErrors, rpcErrors } from "@metamask/rpc-errors";
|
|
5
|
+
import { isStrictHexString } from "@metamask/utils";
|
|
5
6
|
import { TransactionEnvelopeType } from "../types.mjs";
|
|
6
7
|
import { isEIP1559Transaction } from "./utils.mjs";
|
|
7
8
|
/**
|
|
@@ -188,17 +189,17 @@ function validateGasFeeParams(txParams) {
|
|
|
188
189
|
ensureProperTransactionEnvelopeTypeProvided(txParams, 'gasPrice');
|
|
189
190
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'gasPrice', 'maxFeePerGas');
|
|
190
191
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'gasPrice', 'maxPriorityFeePerGas');
|
|
191
|
-
|
|
192
|
+
ensureFieldIsValidHex(txParams, 'gasPrice');
|
|
192
193
|
}
|
|
193
194
|
if (txParams.maxFeePerGas) {
|
|
194
195
|
ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');
|
|
195
196
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'maxFeePerGas', 'gasPrice');
|
|
196
|
-
|
|
197
|
+
ensureFieldIsValidHex(txParams, 'maxFeePerGas');
|
|
197
198
|
}
|
|
198
199
|
if (txParams.maxPriorityFeePerGas) {
|
|
199
200
|
ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxPriorityFeePerGas');
|
|
200
201
|
ensureMutuallyExclusiveFieldsNotProvided(txParams, 'maxPriorityFeePerGas', 'gasPrice');
|
|
201
|
-
|
|
202
|
+
ensureFieldIsValidHex(txParams, 'maxPriorityFeePerGas');
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
/**
|
|
@@ -244,19 +245,17 @@ function ensureMutuallyExclusiveFieldsNotProvided(txParams, fieldBeingValidated,
|
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
/**
|
|
247
|
-
* Ensures that the provided value for field is a
|
|
248
|
-
* invalidParams error if field is not a
|
|
248
|
+
* Ensures that the provided value for field is a valid hexadecimal.
|
|
249
|
+
* Throws an invalidParams error if field is not a valid hexadecimal.
|
|
249
250
|
*
|
|
250
251
|
* @param txParams - The transaction parameters object
|
|
251
252
|
* @param field - The current field being validated
|
|
252
|
-
* @throws {rpcErrors.invalidParams} Throws if field is not a
|
|
253
|
+
* @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal
|
|
253
254
|
*/
|
|
254
|
-
function
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
259
|
-
`Invalid transaction params: ${field} is not a string. got: (${txParams[field]})`);
|
|
255
|
+
function ensureFieldIsValidHex(txParams, field) {
|
|
256
|
+
const value = txParams[field];
|
|
257
|
+
if (typeof value !== 'string' || !isStrictHexString(value)) {
|
|
258
|
+
throw rpcErrors.invalidParams(`Invalid transaction params: ${field} is not a valid hexadecimal. got: (${String(value)})`);
|
|
260
259
|
}
|
|
261
260
|
}
|
|
262
261
|
//# sourceMappingURL=validation.mjs.map
|
|
@@ -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 { providerErrors, rpcErrors } from '@metamask/rpc-errors';\n\nimport { TransactionEnvelopeType, type TransactionParams } from '../types';\nimport { isEIP1559Transaction } from './utils';\n\ntype GasFieldsToValidate = 'gasPrice' | 'maxFeePerGas' | 'maxPriorityFeePerGas';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param permittedAddresses - The permitted accounts for the given origin.\n * @param selectedAddress - The currently selected Ethereum address in the wallet.\n * @param from - The address from which the transaction is initiated.\n * @param origin - The origin or source of the transaction.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin(\n permittedAddresses: string[],\n selectedAddress: string,\n from: string,\n origin: string,\n) {\n if (origin === ORIGIN_METAMASK) {\n // Ensure the 'from' address matches the currently selected address\n if (from !== selectedAddress) {\n throw rpcErrors.internal({\n message: `Internally initiated transaction is using invalid account.`,\n data: {\n origin,\n fromAddress: from,\n selectedAddress,\n },\n });\n }\n return;\n }\n\n // Check if the origin has permissions to initiate transactions from the specified address\n if (!permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\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 */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n) {\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);\n validateGasFeeParams(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) {\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) {\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) {\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) {\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) {\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 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) {\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 chainId - The chainId to validate.\n */\nfunction validateParamChainId(chainId: number | string | undefined) {\n if (\n chainId !== undefined &&\n typeof chainId !== 'number' &&\n typeof chainId !== 'string'\n ) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Invalid transaction params: chainId is not a Number or hex string. got: (${chainId})`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams) {\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 ensureFieldIsString(txParams, 'gasPrice');\n }\n\n if (txParams.maxFeePerGas) {\n ensureProperTransactionEnvelopeTypeProvided(txParams, 'maxFeePerGas');\n ensureMutuallyExclusiveFieldsNotProvided(\n txParams,\n 'maxFeePerGas',\n 'gasPrice',\n );\n ensureFieldIsString(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 ensureFieldIsString(txParams, 'maxPriorityFeePerGas');\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: GasFieldsToValidate,\n) {\n switch (field) {\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (\n txParams.type &&\n txParams.type !== TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TransactionEnvelopeType.feeMarket}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (\n txParams.type &&\n txParams.type === TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.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) {\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 string, throws an\n * invalidParams error if field is not a string.\n *\n * @param txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a string\n */\nfunction ensureFieldIsString(\n txParams: TransactionParams,\n field: GasFieldsToValidate,\n) {\n if (typeof txParams[field] !== 'string') {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Invalid transaction params: ${field} is not a string. got: (${txParams[field]})`,\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 { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport { isStrictHexString } from '@metamask/utils';\n\nimport { TransactionEnvelopeType, type TransactionParams } from '../types';\nimport { isEIP1559Transaction } from './utils';\n\ntype GasFieldsToValidate = 'gasPrice' | 'maxFeePerGas' | 'maxPriorityFeePerGas';\n\n/**\n * Validates whether a transaction initiated by a specific 'from' address is permitted by the origin.\n *\n * @param permittedAddresses - The permitted accounts for the given origin.\n * @param selectedAddress - The currently selected Ethereum address in the wallet.\n * @param from - The address from which the transaction is initiated.\n * @param origin - The origin or source of the transaction.\n * @throws Throws an error if the transaction is not permitted.\n */\nexport async function validateTransactionOrigin(\n permittedAddresses: string[],\n selectedAddress: string,\n from: string,\n origin: string,\n) {\n if (origin === ORIGIN_METAMASK) {\n // Ensure the 'from' address matches the currently selected address\n if (from !== selectedAddress) {\n throw rpcErrors.internal({\n message: `Internally initiated transaction is using invalid account.`,\n data: {\n origin,\n fromAddress: from,\n selectedAddress,\n },\n });\n }\n return;\n }\n\n // Check if the origin has permissions to initiate transactions from the specified address\n if (!permittedAddresses.includes(from)) {\n throw providerErrors.unauthorized({ data: { origin } });\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 */\nexport function validateTxParams(\n txParams: TransactionParams,\n isEIP1559Compatible = true,\n) {\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);\n validateGasFeeParams(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) {\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) {\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) {\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) {\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) {\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 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) {\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 chainId - The chainId to validate.\n */\nfunction validateParamChainId(chainId: number | string | undefined) {\n if (\n chainId !== undefined &&\n typeof chainId !== 'number' &&\n typeof chainId !== 'string'\n ) {\n throw rpcErrors.invalidParams(\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Invalid transaction params: chainId is not a Number or hex string. got: (${chainId})`,\n );\n }\n}\n\n/**\n * Validates gas values.\n *\n * @param txParams - The transaction parameters to validate.\n */\nfunction validateGasFeeParams(txParams: TransactionParams) {\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\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: GasFieldsToValidate,\n) {\n switch (field) {\n case 'maxFeePerGas':\n case 'maxPriorityFeePerGas':\n if (\n txParams.type &&\n txParams.type !== TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.type}\" but including maxFeePerGas and maxPriorityFeePerGas requires type: \"${TransactionEnvelopeType.feeMarket}\"`,\n );\n }\n break;\n case 'gasPrice':\n default:\n if (\n txParams.type &&\n txParams.type === TransactionEnvelopeType.feeMarket\n ) {\n throw rpcErrors.invalidParams(\n `Invalid transaction envelope type: specified type \"${txParams.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) {\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 txParams - The transaction parameters object\n * @param field - The current field being validated\n * @throws {rpcErrors.invalidParams} Throws if field is not a valid hexadecimal\n */\nfunction ensureFieldIsValidHex(\n txParams: TransactionParams,\n field: GasFieldsToValidate,\n) {\n const value = txParams[field];\n if (typeof value !== 'string' || !isStrictHexString(value)) {\n throw rpcErrors.invalidParams(\n `Invalid transaction params: ${field} is not a valid hexadecimal. got: (${String(\n value,\n )})`,\n );\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/transaction-controller",
|
|
3
|
-
"version": "38.2.0-preview-
|
|
3
|
+
"version": "38.2.0-preview-651fe366",
|
|
4
4
|
"description": "Stores transactions alongside their periodically updated statuses and manages interactions such as approval and cancellation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MetaMask",
|