diff --git a/packages/web3-eth-accounts/test/unit/account_dom.test.ts b/packages/web3-eth-accounts/test/unit/account_dom.test.ts
new file mode 100644
index 00000000000..587996a721c
--- /dev/null
+++ b/packages/web3-eth-accounts/test/unit/account_dom.test.ts
@@ -0,0 +1,248 @@
+/**
+ * @jest-environment jsdom
+ */
+
+/*
+This file is part of web3.js.
+
+web3.js is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web3.js is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with web3.js. If not, see .
+*/
+
+// this file contains the unit test for the event emitter in the DOM environment
+// it is executed in the jsdom environment (see "@jest-environment jsdom" in the top comment of this file)
+
+// ignore the following rule to allow keeping `@jest-environment jsdom` on top:
+// eslint-disable-next-line header/header
+import { TextEncoder } from 'util';
+import crypto from 'crypto';
+// polyfill for jsdom
+global.TextEncoder = TextEncoder;
+// @ts-expect-error "Cannot assign to 'subtle' because it is a read-only property."
+global.crypto.subtle = crypto.webcrypto.subtle;
+
+/* eslint-disable import/first */
+import { Address } from 'web3-types';
+import { Web3ValidatorError, isHexStrict } from 'web3-validator';
+import {
+ create,
+ decrypt,
+ encrypt,
+ hashMessage,
+ privateKeyToAccount,
+ privateKeyToAddress,
+ recover,
+ recoverTransaction,
+ sign,
+ signTransaction,
+ privateKeyToPublicKey,
+} from '../../src/account';
+import {
+ invalidDecryptData,
+ invalidEncryptData,
+ invalidKeyStore,
+ invalidPrivateKeytoAccountData,
+ invalidPrivateKeyToAddressData,
+ signatureRecoverData,
+ transactionsTestData,
+ validDecryptData,
+ validEncryptData,
+ validHashMessageData,
+ validPrivateKeytoAccountData,
+ validPrivateKeyToAddressData,
+ validPrivateKeyToPublicKeyData,
+ validRecover,
+} from '../fixtures/account';
+import { TransactionFactory } from '../../src/tx/transactionFactory';
+import { TxData } from '../../src/tx/types';
+
+describe('accounts', () => {
+ describe('create', () => {
+ describe('valid cases', () => {
+ it('%s', () => {
+ const account = create();
+ expect(typeof account.privateKey).toBe('string');
+ expect(typeof account.address).toBe('string');
+ expect(isHexStrict(account.address)).toBe(true);
+ expect(typeof account.encrypt).toBe('function');
+ expect(typeof account.sign).toBe('function');
+ expect(typeof account.signTransaction).toBe('function');
+ });
+ });
+ });
+
+ describe('privateKeyToAddress', () => {
+ describe('valid cases', () => {
+ it.each(validPrivateKeyToAddressData)('%s', (input, output) => {
+ expect(privateKeyToAddress(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(invalidPrivateKeyToAddressData)('%s', (input, output) => {
+ expect(() => privateKeyToAddress(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('privateKeyToAccount', () => {
+ describe('valid cases', () => {
+ it.each(validPrivateKeytoAccountData)('%s', (input, output) => {
+ expect(JSON.stringify(privateKeyToAccount(input.address, input.ignoreLength))).toEqual(
+ JSON.stringify(output),
+ );
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(invalidPrivateKeytoAccountData)('%s', (input, output) => {
+ expect(() => privateKeyToAccount(input)).toThrow(output);
+ });
+ });
+ });
+ describe('privateKeyToPublicKey', () => {
+ describe('valid cases', () => {
+ it.each(validPrivateKeyToPublicKeyData)('%s', (privateKey, isCompressed, output) => {
+ expect(privateKeyToPublicKey(privateKey, isCompressed)).toEqual(output);
+ });
+ });
+ });
+
+ describe('Signing and Recovery of Transaction', () => {
+ it.each(transactionsTestData)('sign transaction', async txData => {
+ const account = create();
+
+ const signedResult = await signTransaction(
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ TransactionFactory.fromTxData(txData as unknown as TxData),
+ account.privateKey,
+ );
+ expect(signedResult).toBeDefined();
+ expect(signedResult.messageHash).toBeDefined();
+ expect(signedResult.rawTransaction).toBeDefined();
+ expect(signedResult.transactionHash).toBeDefined();
+ expect(signedResult.r).toMatch(/0[xX][0-9a-fA-F]{64}/);
+ expect(signedResult.s).toMatch(/0[xX][0-9a-fA-F]{64}/);
+ expect(signedResult.v).toMatch(/0[xX][0-9a-fA-F]+/);
+ });
+
+ it.each(transactionsTestData)('Recover transaction', async txData => {
+ const account = create();
+ const txObj = { ...txData, from: account.address };
+ const signedResult = await signTransaction(
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ TransactionFactory.fromTxData(txObj),
+ account.privateKey,
+ );
+ expect(signedResult).toBeDefined();
+
+ const address: Address = recoverTransaction(signedResult.rawTransaction);
+ expect(address).toBeDefined();
+ expect(address).toEqual(account.address);
+ });
+ });
+
+ describe('Hash Message', () => {
+ it.each(validHashMessageData)('%s', (message, hash) => {
+ expect(hashMessage(message)).toEqual(hash);
+ });
+ });
+
+ describe('Sign Message', () => {
+ describe('sign', () => {
+ it.each(signatureRecoverData)('%s', (data, testObj) => {
+ const result = sign(data, testObj.privateKey);
+ expect(result.signature).toEqual(testObj.signature || testObj.signatureOrV); // makes sure we get signature and not V value
+ expect(result.r).toEqual(testObj.r);
+ expect(result.s).toEqual(testObj.s);
+ });
+ });
+
+ describe('recover', () => {
+ it.each(signatureRecoverData)('%s', (data, testObj) => {
+ const address = recover(data, testObj.signatureOrV, testObj.prefixedOrR, testObj.s);
+ expect(address).toEqual(testObj.address);
+ });
+ });
+ });
+
+ describe('encrypt', () => {
+ describe('valid cases', () => {
+ it.each(validEncryptData)('%s', async (input, output) => {
+ const result = await encrypt(input[0], input[1], input[2]).catch(err => {
+ throw err;
+ });
+ expect(result.version).toBe(output.version);
+ expect(result.address).toBe(output.address);
+ expect(result.crypto.ciphertext).toBe(output.crypto.ciphertext);
+ expect(result.crypto.cipherparams).toEqual(output.crypto.cipherparams);
+ expect(result.crypto.cipher).toEqual(output.crypto.cipher);
+ expect(result.crypto.kdf).toBe(output.crypto.kdf);
+ expect(result.crypto.kdfparams).toEqual(output.crypto.kdfparams);
+ expect(typeof result.version).toBe('number');
+ expect(typeof result.id).toBe('string');
+ expect(typeof result.crypto.mac).toBe('string');
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(invalidEncryptData)('%s', async (input, output) => {
+ const result = encrypt(input[0], input[1], input[2]);
+ await expect(result).rejects.toThrow(output);
+ });
+ });
+ });
+
+ describe('decrypt', () => {
+ describe('valid cases', () => {
+ it.each(validDecryptData)('%s', async input => {
+ const keystore = await encrypt(input[0], input[1], input[2]).catch(err => {
+ throw err;
+ });
+
+ // make sure decrypt does not throw invalid password error
+ const result = await decrypt(keystore, input[1]);
+
+ expect(JSON.stringify(result)).toEqual(JSON.stringify(privateKeyToAccount(input[3])));
+
+ const keystoreString = JSON.stringify(keystore);
+
+ const stringResult = await decrypt(keystoreString, input[1], true);
+
+ expect(JSON.stringify(stringResult)).toEqual(JSON.stringify(privateKeyToAccount(input[3])));
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(invalidDecryptData)('%s', async (input, output) => {
+ const result = decrypt(input[0], input[1]);
+
+ await expect(result).rejects.toThrow(output);
+ });
+ });
+
+ describe('invalid keystore, fails validation', () => {
+ it.each(invalidKeyStore)('%s', async input => {
+ const result = decrypt(input[0], input[1]);
+
+ await expect(result).rejects.toThrow(Web3ValidatorError);
+ });
+ });
+
+ describe('valid signatures for recover', () => {
+ it.each(validRecover)('&s', (data, signature) => {
+ recover(data, signature);
+ });
+ });
+ });
+});
diff --git a/packages/web3-utils/src/uint8array.ts b/packages/web3-utils/src/uint8array.ts
index 772e648920c..5fa8b952711 100644
--- a/packages/web3-utils/src/uint8array.ts
+++ b/packages/web3-utils/src/uint8array.ts
@@ -21,6 +21,8 @@ export function isUint8Array(data: unknown | Uint8Array): data is Uint8Array {
(data as { constructor: { name: string } })?.constructor?.name === 'Uint8Array'
);
}
+
+// @TODO: Remove this function and its usages once all sub dependencies uses version 1.3.3 or above of @noble/hashes
export function ensureIfUint8Array(data: T) {
if (
!(data instanceof Uint8Array) &&
diff --git a/packages/web3-utils/test/unit/converters_dom.test.ts b/packages/web3-utils/test/unit/converters_dom.test.ts
new file mode 100644
index 00000000000..e7ed91a9573
--- /dev/null
+++ b/packages/web3-utils/test/unit/converters_dom.test.ts
@@ -0,0 +1,439 @@
+/**
+ * @jest-environment jsdom
+ */
+
+/*
+This file is part of web3.js.
+
+web3.js is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web3.js is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with web3.js. If not, see .
+*/
+
+// this file contains the unit test for the event emitter in the DOM environment
+// it is executed in the jsdom environment (see "@jest-environment jsdom" in the top comment of this file)
+
+// ignore the following rule to allow keeping `@jest-environment jsdom` on top:
+// eslint-disable-next-line header/header
+import { TextDecoder, TextEncoder } from 'util';
+// polyfill for jsdom
+// @ts-expect-error ignore the error 'Type 'typeof TextDecoder' is not assignable to type ...'
+global.TextDecoder = TextDecoder;
+global.TextEncoder = TextEncoder;
+
+/* eslint-disable import/first */
+import {
+ asciiToHex,
+ bytesToHex,
+ fromAscii,
+ fromDecimal,
+ fromUtf8,
+ fromWei,
+ hexToAscii,
+ hexToBytes,
+ hexToNumber,
+ hexToNumberString,
+ hexToString,
+ hexToUtf8,
+ numberToHex,
+ stringToHex,
+ toAscii,
+ toDecimal,
+ toHex,
+ toNumber,
+ toUtf8,
+ toWei,
+ utf8ToHex,
+ toChecksumAddress,
+ bytesToUint8Array,
+ toBigInt,
+ toBool,
+} from '../../src/converters';
+
+import {
+ asciiToHexValidData,
+ bytesToHexInvalidData,
+ bytesToHexValidData,
+ fromWeiInvalidData,
+ fromWeiValidData,
+ hexToAsciiValidData,
+ hexToBytesInvalidData,
+ hexToBytesValidData,
+ hexToNumberInvalidData,
+ hexToNumberValidData,
+ hexToUtf8InvalidData,
+ hexToUtf8ValidData,
+ toUtf8ValidData,
+ numberToHexInvalidData,
+ numberToHexValidData,
+ toHexValidData,
+ toHexInvalidData,
+ toWeiInvalidData,
+ toWeiValidData,
+ utf8ToHexInvalidData,
+ utf8ToHexValidData,
+ toCheckSumValidData,
+ bytesToUint8ArrayInvalidData,
+ bytesToUint8ArrayValidData,
+ toBigIntValidData,
+ toBigIntInvalidData,
+ toCheckSumInvalidData,
+ numberToHexstrictValidData,
+ toBoolValidData,
+ toBoolInvalidData,
+} from '../fixtures/converters';
+
+describe('converters', () => {
+ describe('bytesToHex', () => {
+ describe('valid cases', () => {
+ it.each(bytesToHexValidData)('%s', (input, output) => {
+ expect(bytesToHex(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(bytesToHexInvalidData)('%s', (input, output) => {
+ expect(() => bytesToHex(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('hexToBytes', () => {
+ describe('valid cases', () => {
+ it.each(hexToBytesValidData)('%s', (input, output) => {
+ expect(hexToBytes(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToBytesInvalidData)('%s', (input, output) => {
+ expect(() => hexToBytes(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('numberToHex', () => {
+ describe('valid cases', () => {
+ it.each(numberToHexValidData)('%s', (input, output) => {
+ expect(numberToHex(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(numberToHexInvalidData)('%s', (input, output) => {
+ expect(() => numberToHex(input)).toThrow(output);
+ });
+ });
+
+ describe('valid hexstrict cases', () => {
+ it.each(numberToHexstrictValidData)('%s', (input, output) => {
+ expect(numberToHex(input, true)).toEqual(output);
+ });
+ });
+ });
+
+ describe('fromDecimal', () => {
+ describe('valid cases', () => {
+ it.each(numberToHexValidData)('%s', (input, output) => {
+ expect(fromDecimal(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(numberToHexInvalidData)('%s', (input, output) => {
+ expect(() => fromDecimal(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('hexToNumber', () => {
+ describe('valid cases', () => {
+ it.each(hexToNumberValidData)('%s', (input, output) => {
+ expect(hexToNumber(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToNumberInvalidData)('%s', (input, output) => {
+ expect(() => hexToNumber(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('toDecimal', () => {
+ describe('valid cases', () => {
+ it.each(hexToNumberValidData)('%s', (input, output) => {
+ expect(toDecimal(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToNumberInvalidData)('%s', (input, output) => {
+ expect(() => toDecimal(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('hexToNumberString', () => {
+ it.each(hexToNumberValidData)('%s', (input, output) => {
+ expect(hexToNumberString(input)).toEqual(output.toString());
+ });
+ });
+
+ describe('utf8ToHex', () => {
+ describe('valid cases', () => {
+ it.each(utf8ToHexValidData)('%s', (input, output) => {
+ expect(utf8ToHex(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(utf8ToHexInvalidData)('%s', (input, output) => {
+ expect(() => utf8ToHex(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('fromUtf8', () => {
+ describe('valid cases', () => {
+ it.each(utf8ToHexValidData)('%s', (input, output) => {
+ expect(fromUtf8(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(utf8ToHexInvalidData)('%s', (input, output) => {
+ expect(() => fromUtf8(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('stringToHex', () => {
+ describe('valid cases', () => {
+ it.each(utf8ToHexValidData)('%s', (input, output) => {
+ expect(stringToHex(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(utf8ToHexInvalidData)('%s', (input, output) => {
+ expect(() => stringToHex(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('hexToUtf8', () => {
+ describe('valid cases', () => {
+ it.each(hexToUtf8ValidData)('%s', (input, output) => {
+ expect(hexToUtf8(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToUtf8InvalidData)('%s', (input, output) => {
+ expect(() => hexToUtf8(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('toUtf8', () => {
+ describe('valid cases', () => {
+ it.each(toUtf8ValidData)('%s', (input, output) => {
+ expect(toUtf8(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToUtf8InvalidData)('%s', (input, output) => {
+ expect(() => toUtf8(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('hexToString', () => {
+ describe('valid cases', () => {
+ it.each(hexToUtf8ValidData)('%s', (input, output) => {
+ expect(hexToString(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToUtf8InvalidData)('%s', (input, output) => {
+ expect(() => hexToString(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('asciiToHex', () => {
+ describe('valid cases', () => {
+ it.each(asciiToHexValidData)('%s', (input, output) => {
+ expect(asciiToHex(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(utf8ToHexInvalidData)('%s', (input, output) => {
+ expect(() => asciiToHex(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('fromAscii', () => {
+ describe('valid cases', () => {
+ it.each(asciiToHexValidData)('%s', (input, output) => {
+ expect(fromAscii(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(utf8ToHexInvalidData)('%s', (input, output) => {
+ expect(() => fromAscii(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('hexToAscii', () => {
+ describe('valid cases', () => {
+ it.each(hexToAsciiValidData)('%s', (input, output) => {
+ expect(hexToAscii(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToUtf8InvalidData)('%s', (input, output) => {
+ expect(() => hexToAscii(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('toAscii', () => {
+ describe('valid cases', () => {
+ it.each(hexToAsciiValidData)('%s', (input, output) => {
+ expect(toAscii(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(hexToUtf8InvalidData)('%s', (input, output) => {
+ expect(() => toAscii(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('toHex', () => {
+ describe('return value', () => {
+ it.each(toHexValidData)('%s', (input, output) => {
+ expect(toHex(input)).toEqual(output[0]);
+ });
+ });
+
+ describe('return type', () => {
+ it.each(toHexValidData)('%s', (input, output) => {
+ expect(toHex(input, true)).toEqual(output[1]);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(toHexInvalidData)('%s', (input, output) => {
+ expect(() => toHex(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('toNumber', () => {
+ it.each([...hexToNumberValidData, [123, 123], ['123', 123]])('%s', (input, output) => {
+ expect(toNumber(input)).toEqual(output);
+ });
+ });
+
+ describe('fromWei', () => {
+ describe('valid cases', () => {
+ it.each(fromWeiValidData)('%s', (input, output) => {
+ expect(fromWei(input[0], input[1])).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(fromWeiInvalidData)('%s', (input, output) => {
+ expect(() => fromWei(input[0], input[1])).toThrow(output);
+ });
+ });
+ });
+
+ describe('toWei', () => {
+ describe('valid cases', () => {
+ it.each(toWeiValidData)('%s', (input, output) => {
+ expect(toWei(output, input[1])).toEqual(input[0].toString());
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(toWeiInvalidData)('%s', (input, output) => {
+ expect(() => toWei(input[0], input[1])).toThrow(output);
+ });
+ });
+ });
+ describe('toChecksumAddress', () => {
+ describe('valid cases', () => {
+ it.each(toCheckSumValidData)('%s', (input, output) => {
+ expect(toChecksumAddress(input)).toEqual(output);
+ });
+ });
+ describe('invalid cases', () => {
+ it.each(toCheckSumInvalidData)('%s', (input, output) => {
+ expect(() => toChecksumAddress(input)).toThrow(output);
+ });
+ });
+ });
+ describe('bytesToUint8Array', () => {
+ describe('bytesToUint8Array', () => {
+ describe('valid cases', () => {
+ it.each(bytesToUint8ArrayValidData)('%s', (input, output) => {
+ expect(bytesToUint8Array(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(bytesToUint8ArrayInvalidData)('%s', (input, output) => {
+ expect(() => bytesToUint8Array(input)).toThrow(output);
+ });
+ });
+ });
+ });
+ describe('toBigInt', () => {
+ describe('valid cases', () => {
+ it.each(toBigIntValidData)('%s', (input, output) => {
+ expect(toBigInt(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(toBigIntInvalidData)('%s', (input, output) => {
+ expect(() => toBigInt(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('toBool', () => {
+ describe('valid cases', () => {
+ it.each(toBoolValidData)('%s', (input, output) => {
+ expect(toBool(input)).toEqual(output);
+ });
+ });
+
+ describe('invalid cases', () => {
+ it.each(toBoolInvalidData)('%s', (input, output) => {
+ expect(() => toBool(input)).toThrow(output);
+ });
+ });
+ });
+});
diff --git a/packages/web3-utils/test/unit/hash_dom.test.ts b/packages/web3-utils/test/unit/hash_dom.test.ts
new file mode 100644
index 00000000000..1e4dd67cf0c
--- /dev/null
+++ b/packages/web3-utils/test/unit/hash_dom.test.ts
@@ -0,0 +1,166 @@
+/**
+ * @jest-environment jsdom
+ */
+
+/*
+This file is part of web3.js.
+
+web3.js is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web3.js is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with web3.js. If not, see .
+*/
+
+// this file contains the unit test for the event emitter in the DOM environment
+// it is executed in the jsdom environment (see "@jest-environment jsdom" in the top comment of this file)
+
+// ignore the following rule to allow keeping `@jest-environment jsdom` on top:
+// eslint-disable-next-line header/header
+import { TextEncoder } from 'util';
+// polyfill for jsdom
+global.TextEncoder = TextEncoder;
+
+/* eslint-disable import/first */
+import { keccak256 } from 'js-sha3';
+import {
+ sha3,
+ sha3Raw,
+ soliditySha3,
+ soliditySha3Raw,
+ encodePacked,
+ keccak256 as web3keccak256,
+} from '../../src/hash';
+import {
+ sha3Data,
+ sha3ValidData,
+ soliditySha3RawValidData,
+ sha3RawValidData,
+ soliditySha3ValidData,
+ soliditySha3InvalidData,
+ compareSha3JSValidData,
+ compareSha3JSRawValidData,
+ encodePackData,
+ encodePackedInvalidData,
+ keccak256ValidData,
+ soliditySha3BigIntValidData,
+} from '../fixtures/hash';
+
+describe('hash', () => {
+ describe('sha3', () => {
+ describe('valid cases', () => {
+ it.each(sha3ValidData)('%s', (input, output) => {
+ expect(sha3(input)).toEqual(output);
+ });
+ });
+
+ describe('compare with js-sha3 normal cases', () => {
+ it.each(sha3Data)('%s', input => {
+ expect(sha3(input)).toBe(`0x${keccak256(input)}`);
+ });
+ });
+
+ describe('compare with js-sha3 uint8array cases', () => {
+ it.each(compareSha3JSValidData)('%s', (input, output) => {
+ expect(sha3(input)).toBe(`0x${keccak256(output)}`);
+ });
+ });
+ });
+
+ describe('sha3Raw', () => {
+ describe('valid cases', () => {
+ it.each(sha3RawValidData)('%s', (input, output) => {
+ expect(sha3Raw(input)).toEqual(output);
+ });
+ });
+ describe('comparing with js-sha3 cases', () => {
+ it.each(compareSha3JSRawValidData)('%s', (input, output) => {
+ expect(sha3Raw(input)).toBe(`0x${keccak256(output)}`);
+ });
+ });
+ });
+
+ describe('soliditySha3', () => {
+ describe('valid cases', () => {
+ it.each(soliditySha3ValidData)('%s', (input, output) => {
+ expect(soliditySha3(...input)).toEqual(output);
+ });
+ });
+ describe('invalid cases', () => {
+ it.each(soliditySha3InvalidData)('%s', (input, output) => {
+ expect(() => soliditySha3(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('soliditySha3Raw', () => {
+ describe('valid cases', () => {
+ it.each(soliditySha3RawValidData)('%s', (input, output) => {
+ expect(soliditySha3Raw(...input)).toEqual(output);
+ });
+ });
+ describe('invalid cases', () => {
+ it.each(soliditySha3InvalidData)('%s', (input, output) => {
+ expect(() => soliditySha3Raw(input)).toThrow(output);
+ });
+ });
+ });
+
+ describe('encodePacked', () => {
+ describe('valid cases', () => {
+ it.each(encodePackData)('%s', (input, output) => {
+ expect(encodePacked(...input)).toEqual(output);
+ });
+ });
+ describe('invalid cases', () => {
+ it.each(encodePackedInvalidData)('%s', (input, output) => {
+ expect(() => encodePacked(input)).toThrow(output);
+ });
+ });
+ });
+ describe('keccak256', () => {
+ describe('valid cases', () => {
+ it.each(keccak256ValidData)('%s', (input, output) => {
+ expect(web3keccak256(input)).toEqual(output);
+ });
+ });
+ });
+
+ describe('extra types supporting', () => {
+ it('object', () => {
+ const res = soliditySha3({
+ historicBlock: {
+ hash: '0xcba0b90a5e65512202091c12a2e3b328f374715b9f1c8f32cb4600c726fe2aa6',
+ height: 1,
+ },
+ networkId: 5777,
+ });
+ expect(res).toBe('0x00203462b63e3a8ca15da715e490c676b0e370f47823e31383fe43c25da3b78d');
+ });
+ it('object in string', () => {
+ const res = soliditySha3(
+ '{"contents":"pragma solidity >=0.4.21 <0.6.0;\\n\\ncontract Migrations {\\n address public owner;\\n uint public last_completed_migration;\\n\\n constructor() public {\\n owner = msg.sender;\\n }\\n\\n modifier restricted() {\\n if (msg.sender == owner) _;\\n }\\n\\n function setCompleted(uint completed) public restricted {\\n last_completed_migration = completed;\\n }\\n\\n function upgrade(address new_address) public restricted {\\n Migrations upgraded = Migrations(new_address);\\n upgraded.setCompleted(last_completed_migration);\\n }\\n}\\n","sourcePath":"/Users/gnidan/src/work/reproduce/2019/01/21/artifacts/contracts/Migrations.sol"}',
+ );
+ expect(res).toBe('0xdb092e2751b8dcb7c8509baade3c0ac290414a71685823c3cbeb28667970b0bd');
+ });
+ it('another object in string', () => {
+ const res = soliditySha3(
+ '{"bytes":"608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610314806100606000396000f3fe608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630900f01014610067578063445df0ac146100b85780638da5cb5b146100e3578063fdacd5761461013a575b600080fd5b34801561007357600080fd5b506100b66004803603602081101561008a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610175565b005b3480156100c457600080fd5b506100cd61025d565b6040518082815260200191505060405180910390f35b3480156100ef57600080fd5b506100f8610263565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561014657600080fd5b506101736004803603602081101561015d57600080fd5b8101908080359060200190929190505050610288565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561025a5760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561024057600080fd5b505af1158015610254573d6000803e3d6000fd5b50505050505b50565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102e557806001819055505b5056fea165627a7a7230582013359aba5684f88626fb6a58a003236e309ef1462172af4afb4afb9bd2532b510029","linkReferences":[]}',
+ );
+ expect(res).toBe('0x46e99868594ceb46b7cd37e4b33d635f12a7751671f8c51dd8218fa0dcf82901');
+ });
+
+ describe('BigInt soliditySha3', () => {
+ it.each(soliditySha3BigIntValidData)('%s', (input, output) => {
+ expect(soliditySha3(...input)).toEqual(output);
+ });
+ });
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 18cbb781cec..90bbf007848 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1386,12 +1386,12 @@
dependencies:
"@noble/hashes" "1.3.1"
-"@noble/hashes@1.1.2", "@noble/hashes@~1.1.1":
+"@noble/hashes@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183"
integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==
-"@noble/hashes@1.3.0", "@noble/hashes@~1.3.0":
+"@noble/hashes@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1"
integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==
@@ -1401,10 +1401,15 @@
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
-"@noble/hashes@~1.3.1":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
- integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
+"@noble/hashes@~1.1.1":
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.5.tgz#1a0377f3b9020efe2fae03290bd2a12140c95c11"
+ integrity sha512-LTMZiiLc+V4v1Yi16TD6aX2gmtKszNye0pQgbaLqkvhIqP7nVsSaJsWloGQjJfJ8offaoP5GtX3yY5swbcJxxQ==
+
+"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
+ integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
"@noble/secp256k1@1.6.3", "@noble/secp256k1@~1.6.0":
version "1.6.3"
@@ -2301,6 +2306,11 @@
dependencies:
"@babel/types" "^7.3.0"
+"@types/benchmark@^2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@types/benchmark/-/benchmark-2.1.5.tgz#940c1850c18fdfdaee3fd6ed29cd92ae0d445b45"
+ integrity sha512-cKio2eFB3v7qmKcvIHLUMw/dIx/8bhWPuzpzRT4unCPRTD8VdA9Zb0afxpcxOqR4PixRS7yT42FqGS8BYL8g1w==
+
"@types/bn.js@^4.11.3":
version "4.11.6"
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c"
@@ -3505,6 +3515,14 @@ before-after-hook@^2.2.0:
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==
+benchmark@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629"
+ integrity sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==
+ dependencies:
+ lodash "^4.17.4"
+ platform "^1.3.3"
+
big-integer@^1.6.44:
version "1.6.51"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
@@ -8913,7 +8931,7 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21:
+lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -10463,6 +10481,11 @@ pkg-dir@^4.2.0:
dependencies:
find-up "^4.0.0"
+platform@^1.3.3:
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7"
+ integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
+
posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"