Socket
Socket
Sign inDemoInstall

@metamask/eth-sig-util

Package Overview
Dependencies
Maintainers
10
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@metamask/eth-sig-util - npm Package Compare versions

Comparing version 6.0.0 to 6.0.1

6

dist/sign-typed-data.d.ts

@@ -21,3 +21,4 @@ /// <reference types="node" />

*
* V1 is based upon [an early version of EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* V1 is based upon [an early version of
* EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* that lacked some later security improvements, and should generally be neglected in favor of

@@ -205,3 +206,4 @@ * later versions.

*
* V1 is based upon [an early version of EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* V1 is based upon [an early version of
* EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* that lacked some later security improvements, and should generally be neglected in favor of

@@ -208,0 +210,0 @@ * later versions.

@@ -5,10 +5,13 @@ "use strict";

const util_1 = require("@ethereumjs/util");
const abi_utils_1 = require("@metamask/abi-utils");
const parsers_1 = require("@metamask/abi-utils/dist/parsers");
const utils_1 = require("@metamask/abi-utils/dist/utils");
const utils_2 = require("@metamask/utils");
const keccak_1 = require("ethereum-cryptography/keccak");
const ethjs_util_1 = require("ethjs-util");
const ethereumjs_abi_utils_1 = require("./ethereumjs-abi-utils");
const utils_1 = require("./utils");
const utils_3 = require("./utils");
/**
* Represents the version of `signTypedData` being used.
*
* V1 is based upon [an early version of EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* V1 is based upon [an early version of
* EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* that lacked some later security improvements, and should generally be neglected in favor of

@@ -66,2 +69,56 @@ * later versions.

/**
* Parse a string, number, or bigint value into a `Uint8Array`.
*
* @param type - The type of the value.
* @param value - The value to parse.
* @returns The parsed value.
*/
function parseNumber(type, value) {
(0, utils_2.assert)(value !== null, `Unable to encode value: Invalid number. Expected a valid number value, but received "${value}".`);
const bigIntValue = BigInt(value);
const length = (0, parsers_1.getLength)(type);
const maxValue = BigInt(2) ** BigInt(length) - BigInt(1);
// Note that this is not accurate, since the actual maximum value for unsigned
// integers is `2 ^ (length - 1) - 1`, but this is required for backwards
// compatibility with the old implementation.
(0, utils_2.assert)(bigIntValue >= -maxValue && bigIntValue <= maxValue, `Unable to encode value: Number "${value}" is out of range for type "${type}".`);
return bigIntValue;
}
/**
* Parse an address string to a `Uint8Array`. The behaviour of this is quite
* strange, in that it does not parse the address as hexadecimal string, nor as
* UTF-8. It does some weird stuff with the string and char codes, and then
* returns the result as a `Uint8Array`.
*
* This is based on the old `ethereumjs-abi` implementation, which essentially
* calls `new BN(address, 10)` on the address string, the equivalent of calling
* `parseInt(address, 10)` in JavaScript. This is not a valid way to parse an
* address and would result in `NaN` in plain JavaScript, but it is the
* behaviour of the old implementation, and so we must preserve it for backwards
* compatibility.
*
* @param address - The address to parse.
* @returns The parsed address.
*/
function reallyStrangeAddressToBytes(address) {
let addressValue = BigInt(0);
for (let i = 0; i < address.length; i++) {
const character = BigInt(address.charCodeAt(i) - 48);
addressValue *= BigInt(10);
// 'a'
if (character >= 49) {
addressValue += character - BigInt(49) + BigInt(0xa);
// 'A'
}
else if (character >= 17) {
addressValue += character - BigInt(17) + BigInt(0xa);
// '0' - '9'
}
else {
addressValue += character;
}
}
return (0, utils_1.padStart)((0, utils_2.bigIntToBytes)(addressValue), 20);
}
/**
* Encode a single field.

@@ -89,24 +146,61 @@ *

}
// `function` is supported in `@metamask/abi-utils`, but not allowed by
// EIP-712, so we throw an error here.
if (type === 'function') {
throw new Error('Unsupported or invalid type: "function"');
}
if (value === undefined) {
throw new Error(`missing value for field ${name} of type ${type}`);
}
if (type === 'address') {
if (typeof value === 'number') {
return ['address', (0, utils_1.padStart)((0, utils_2.numberToBytes)(value), 20)];
}
else if ((0, utils_2.isStrictHexString)(value)) {
return ['address', (0, utils_2.add0x)(value)];
}
else if (typeof value === 'string') {
return ['address', reallyStrangeAddressToBytes(value).subarray(0, 20)];
}
}
if (type === 'bool') {
return ['bool', Boolean(value)];
}
if (type === 'bytes') {
if (typeof value === 'number') {
value = (0, utils_1.numberToBuffer)(value);
value = (0, utils_2.numberToBytes)(value);
}
else if ((0, ethjs_util_1.isHexString)(value)) {
const prepend = value.length % 2 ? '0' : '';
value = Buffer.from(prepend + value.slice(2), 'hex');
else if ((0, utils_2.isStrictHexString)(value)) {
value = (0, utils_2.hexToBytes)(value);
}
else {
value = Buffer.from(value, 'utf8');
else if (typeof value === 'string') {
value = (0, utils_2.stringToBytes)(value);
}
return ['bytes32', (0, util_1.arrToBufArr)((0, keccak_1.keccak256)(value))];
}
if (type.startsWith('bytes') && type !== 'bytes' && !type.includes('[')) {
if (typeof value === 'number') {
if (value < 0) {
return ['bytes32', new Uint8Array(32)];
}
return ['bytes32', (0, utils_2.bigIntToBytes)(BigInt(value))];
}
else if ((0, utils_2.isStrictHexString)(value)) {
return ['bytes32', (0, utils_2.hexToBytes)(value)];
}
return ['bytes32', value];
}
if (type.startsWith('int') && !type.includes('[')) {
const bigIntValue = parseNumber(type, value);
if (bigIntValue >= BigInt(0)) {
return ['uint256', bigIntValue];
}
return ['int256', bigIntValue];
}
if (type === 'string') {
if (typeof value === 'number') {
value = (0, utils_1.numberToBuffer)(value);
value = (0, utils_2.numberToBytes)(value);
}
else {
value = Buffer.from(value !== null && value !== void 0 ? value : '', 'utf8');
value = (0, utils_2.stringToBytes)(value !== null && value !== void 0 ? value : '');
}

@@ -123,3 +217,3 @@ return ['bytes32', (0, util_1.arrToBufArr)((0, keccak_1.keccak256)(value))];

'bytes32',
(0, util_1.arrToBufArr)((0, keccak_1.keccak256)((0, ethereumjs_abi_utils_1.rawEncode)(typeValuePairs.map(([t]) => t), typeValuePairs.map(([, v]) => v)))),
(0, util_1.arrToBufArr)((0, keccak_1.keccak256)((0, abi_utils_1.encode)(typeValuePairs.map(([t]) => t), typeValuePairs.map(([, v]) => v)))),
];

@@ -141,3 +235,5 @@ }

const encodedTypes = ['bytes32'];
const encodedValues = [hashType(primaryType, types)];
const encodedValues = [
hashType(primaryType, types),
];
for (const field of types[primaryType]) {

@@ -151,3 +247,3 @@ if (version === SignTypedDataVersion.V3 && data[field.name] === undefined) {

}
return (0, ethereumjs_abi_utils_1.rawEncode)(encodedTypes, encodedValues);
return (0, util_1.arrToBufArr)((0, abi_utils_1.encode)(encodedTypes, encodedValues));
}

@@ -224,3 +320,3 @@ /**

function hashType(primaryType, types) {
const encodedHashType = Buffer.from(encodeType(primaryType, types), 'utf-8');
const encodedHashType = (0, utils_2.stringToBytes)(encodeType(primaryType, types));
return (0, util_1.arrToBufArr)((0, keccak_1.keccak256)(encodedHashType));

@@ -277,3 +373,3 @@ }

const sanitizedData = sanitizeData(typedData);
const parts = [Buffer.from('1901', 'hex')];
const parts = [(0, utils_2.hexToBytes)('1901')];
parts.push(eip712DomainHash(typedData, version));

@@ -285,3 +381,3 @@ if (sanitizedData.primaryType !== 'EIP712Domain') {

}
return (0, util_1.arrToBufArr)((0, keccak_1.keccak256)(Buffer.concat(parts)));
return (0, util_1.arrToBufArr)((0, keccak_1.keccak256)((0, utils_2.concatBytes)(parts)));
}

@@ -312,6 +408,107 @@ /**

const hashBuffer = _typedSignatureHash(typedData);
return (0, util_1.bufferToHex)(hashBuffer);
return (0, utils_2.bytesToHex)(hashBuffer);
}
exports.typedSignatureHash = typedSignatureHash;
/**
* Normalize a value, so that `@metamask/abi-utils` can handle it. This
* matches the behaviour of the `ethereumjs-abi` library.
*
* @param type - The type of the value to normalize.
* @param value - The value to normalize.
* @returns The normalized value.
*/
function normalizeValue(type, value) {
if ((0, parsers_1.isArrayType)(type) && Array.isArray(value)) {
const [innerType] = (0, parsers_1.getArrayType)(type);
return value.map((item) => normalizeValue(innerType, item));
}
if (type === 'address') {
if (typeof value === 'number') {
return (0, utils_1.padStart)((0, utils_2.numberToBytes)(value), 20);
}
if ((0, utils_2.isStrictHexString)(value)) {
return (0, utils_1.padStart)((0, utils_2.hexToBytes)(value).subarray(0, 20), 20);
}
if (value instanceof Uint8Array) {
return (0, utils_1.padStart)(value.subarray(0, 20), 20);
}
}
if (type === 'bool') {
return Boolean(value);
}
if (type.startsWith('bytes') && type !== 'bytes') {
const length = (0, parsers_1.getByteLength)(type);
if (typeof value === 'number') {
if (value < 0) {
// `solidityPack(['bytesN'], [-1])` returns `0x00..00`.
return new Uint8Array();
}
return (0, utils_2.numberToBytes)(value).subarray(0, length);
}
if ((0, utils_2.isStrictHexString)(value)) {
return (0, utils_2.hexToBytes)(value).subarray(0, length);
}
if (value instanceof Uint8Array) {
return value.subarray(0, length);
}
}
if (type.startsWith('uint')) {
if (typeof value === 'number') {
return Math.abs(value);
}
}
if (type.startsWith('int')) {
if (typeof value === 'number') {
const length = (0, parsers_1.getLength)(type);
return BigInt.asIntN(length, BigInt(value));
}
}
return value;
}
/**
* For some reason `ethereumjs-abi` treats `address` and `address[]` differently
* so we need to normalize `address[]` differently.
*
* @param values - The values to normalize.
* @returns The normalized values.
*/
function normalizeAddresses(values) {
return values.map((value) => {
if (typeof value === 'number') {
return (0, utils_1.padStart)((0, utils_2.numberToBytes)(value), 32);
}
if ((0, utils_2.isStrictHexString)(value)) {
return (0, utils_1.padStart)((0, utils_2.hexToBytes)(value).subarray(0, 32), 32);
}
if (value instanceof Uint8Array) {
return (0, utils_1.padStart)(value.subarray(0, 32), 32);
}
return value;
});
}
/**
* For some reason `ethereumjs-abi` treats `intN` and `intN[]` differently
* so we need to normalize `intN[]` differently.
*
* @param type - The type of the value to normalize.
* @param values - The values to normalize.
* @returns The normalized values.
*/
function normalizeIntegers(type, values) {
return values.map((value) => {
if (typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'bigint') {
const bigIntValue = parseNumber(type, value);
if (bigIntValue >= BigInt(0)) {
return (0, utils_1.padStart)((0, utils_2.bigIntToBytes)(bigIntValue), 32);
}
const length = (0, parsers_1.getLength)(type);
const asIntN = BigInt.asIntN(length, bigIntValue);
return (0, utils_2.signedBigIntToBytes)(asIntN, 32);
}
return value;
});
}
/**
* Generate the "V1" hash for the provided typed message.

@@ -332,12 +529,39 @@ *

}
const data = typedData.map(function (e) {
const normalizedData = typedData.map(({ name, type, value }) => {
// Handle an edge case with `address[]` types.
if (type === 'address[]') {
return {
name,
type: 'bytes32[]',
value: normalizeAddresses(value),
};
}
// Handle an edge case with `intN[]` types.
if (type.startsWith('int') && (0, parsers_1.isArrayType)(type)) {
const [innerType, length] = (0, parsers_1.getArrayType)(type);
return {
name,
type: `bytes32[${length !== null && length !== void 0 ? length : ''}]`,
value: normalizeIntegers(innerType, value),
};
}
return {
name,
type,
value: normalizeValue(type, value),
};
});
const data = normalizedData.map((e) => {
if (e.type !== 'bytes') {
return e.value;
}
return (0, utils_1.legacyToBuffer)(e.value);
return (0, utils_3.legacyToBuffer)(e.value);
});
const types = typedData.map(function (e) {
const types = normalizedData.map((e) => {
if (e.type === 'function') {
throw new Error('Unsupported or invalid type: "function"');
}
return e.type;
});
const schema = typedData.map(function (e) {
const schema = typedData.map((e) => {
if (!e.name) {

@@ -348,5 +572,5 @@ throw error;

});
return (0, util_1.arrToBufArr)((0, keccak_1.keccak256)((0, ethereumjs_abi_utils_1.solidityPack)(['bytes32', 'bytes32'], [
(0, keccak_1.keccak256)((0, ethereumjs_abi_utils_1.solidityPack)(new Array(typedData.length).fill('string'), schema)),
(0, keccak_1.keccak256)((0, ethereumjs_abi_utils_1.solidityPack)(types, data)),
return (0, util_1.arrToBufArr)((0, keccak_1.keccak256)((0, abi_utils_1.encodePacked)(['bytes32', 'bytes32'], [
(0, keccak_1.keccak256)((0, abi_utils_1.encodePacked)(['string[]'], [schema], true)),
(0, keccak_1.keccak256)((0, abi_utils_1.encodePacked)(types, data, true)),
])));

@@ -357,3 +581,4 @@ }

*
* V1 is based upon [an early version of EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* V1 is based upon [an early version of
* EIP-712](https://github.com/ethereum/EIPs/pull/712/commits/21abe254fe0452d8583d5b132b1d7be87c0439ca)
* that lacked some later security improvements, and should generally be neglected in favor of

@@ -376,6 +601,6 @@ * later versions.

validateVersion(version);
if ((0, utils_1.isNullish)(data)) {
if ((0, utils_3.isNullish)(data)) {
throw new Error('Missing data parameter');
}
else if ((0, utils_1.isNullish)(privateKey)) {
else if ((0, utils_3.isNullish)(privateKey)) {
throw new Error('Missing private key parameter');

@@ -387,3 +612,3 @@ }

const sig = (0, util_1.ecsign)(messageHash, privateKey);
return (0, utils_1.concatSig)((0, util_1.toBuffer)(sig.v), sig.r, sig.s);
return (0, utils_3.concatSig)((0, util_1.arrToBufArr)((0, utils_2.bigIntToBytes)(sig.v)), sig.r, sig.s);
}

@@ -404,6 +629,6 @@ exports.signTypedData = signTypedData;

validateVersion(version);
if ((0, utils_1.isNullish)(data)) {
if ((0, utils_3.isNullish)(data)) {
throw new Error('Missing data parameter');
}
else if ((0, utils_1.isNullish)(signature)) {
else if ((0, utils_3.isNullish)(signature)) {
throw new Error('Missing signature parameter');

@@ -414,7 +639,7 @@ }

: exports.TypedDataUtils.eip712Hash(data, version);
const publicKey = (0, utils_1.recoverPublicKey)(messageHash, signature);
const publicKey = (0, utils_3.recoverPublicKey)(messageHash, signature);
const sender = (0, util_1.publicToAddress)(publicKey);
return (0, util_1.bufferToHex)(sender);
return (0, utils_2.bytesToHex)(sender);
}
exports.recoverTypedSignature = recoverTypedSignature;
//# sourceMappingURL=sign-typed-data.js.map

@@ -56,9 +56,1 @@ /// <reference types="node" />

export declare function normalize(input: number | string): string | undefined;
/**
* Node's Buffer.from() method does not seem to buffer numbers correctly out of the box.
* This helper method formats the number correct for Buffer.from to return correct buffer.
*
* @param num - The number to convert to buffer.
* @returns The number in buffer form.
*/
export declare function numberToBuffer(num: number): Buffer;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.numberToBuffer = exports.normalize = exports.recoverPublicKey = exports.concatSig = exports.legacyToBuffer = exports.isNullish = exports.padWithZeroes = void 0;
exports.normalize = exports.recoverPublicKey = exports.concatSig = exports.legacyToBuffer = exports.isNullish = exports.padWithZeroes = void 0;
const util_1 = require("@ethereumjs/util");
const utils_1 = require("@metamask/utils");
const ethjs_util_1 = require("ethjs-util");

@@ -67,3 +68,3 @@ /**

const vStr = (0, ethjs_util_1.stripHexPrefix)((0, ethjs_util_1.intToHex)(vSig));
return (0, util_1.addHexPrefix)(rStr.concat(sStr, vStr));
return (0, utils_1.add0x)(rStr.concat(sStr, vStr));
}

@@ -97,4 +98,4 @@ exports.concatSig = concatSig;

}
const buffer = (0, util_1.toBuffer)(input);
input = (0, util_1.bufferToHex)(buffer);
const buffer = (0, utils_1.numberToBytes)(input);
input = (0, utils_1.bytesToHex)(buffer);
}

@@ -106,18 +107,5 @@ if (typeof input !== 'string') {

}
return (0, util_1.addHexPrefix)(input.toLowerCase());
return (0, utils_1.add0x)(input.toLowerCase());
}
exports.normalize = normalize;
/**
* Node's Buffer.from() method does not seem to buffer numbers correctly out of the box.
* This helper method formats the number correct for Buffer.from to return correct buffer.
*
* @param num - The number to convert to buffer.
* @returns The number in buffer form.
*/
function numberToBuffer(num) {
const hexVal = num.toString(16);
const prepend = hexVal.length % 2 ? '0' : '';
return Buffer.from(prepend + hexVal, 'hex');
}
exports.numberToBuffer = numberToBuffer;
//# sourceMappingURL=utils.js.map
{
"name": "@metamask/eth-sig-util",
"version": "6.0.0",
"version": "6.0.1",
"description": "A few useful functions for signing ethereum data",

@@ -47,5 +47,6 @@ "keywords": [

"dependencies": {
"@ethereumjs/util": "^8.0.6",
"bn.js": "^4.12.0",
"ethereum-cryptography": "^2.0.0",
"@ethereumjs/util": "^8.1.0",
"@metamask/abi-utils": "^1.2.0",
"@metamask/utils": "^5.0.2",
"ethereum-cryptography": "^2.1.2",
"ethjs-util": "^0.1.6",

@@ -62,3 +63,2 @@ "tweetnacl": "^1.0.3",

"@metamask/eslint-config-typescript": "^11.1.0",
"@types/bn.js": "^4.11.6",
"@types/jest": "^27.0.6",

@@ -65,0 +65,0 @@ "@types/node": "^14.14.25",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc