diff --git a/packages/web3-eth-abi/src/eip_712.ts b/packages/web3-eth-abi/src/eip_712.ts index 5a46df80be4..bb6485b319d 100644 --- a/packages/web3-eth-abi/src/eip_712.ts +++ b/packages/web3-eth-abi/src/eip_712.ts @@ -17,12 +17,12 @@ along with web3.js. If not, see . /** * The web3.eth.abi functions let you encode and decode parameters to ABI (Application Binary Interface) for function calls to the EVM (Ethereum Virtual Machine). - * + * * For using Web3 ABI functions, first install Web3 package using `npm i web3` or `yarn add web3`. - * After that, Web3 ABI functions will be available. + * After that, Web3 ABI functions will be available. * ```ts * import { Web3 } from 'web3'; - * + * * const web3 = new Web3(); * const encoded = web3.eth.abi.encodeFunctionSignature({ * name: 'myMethod', @@ -35,14 +35,14 @@ along with web3.js. If not, see . * name: 'myString' * }] * }); - * + * * ``` - * + * * For using individual package install `web3-eth-abi` package using `npm i web3-eth-abi` or `yarn add web3-eth-abi` and only import required functions. - * This is more efficient approach for building lightweight applications. + * This is more efficient approach for building lightweight applications. * ```ts * import { encodeFunctionSignature } from 'web3-eth-abi'; - * + * * const encoded = encodeFunctionSignature({ * name: 'myMethod', * type: 'function', @@ -54,13 +54,12 @@ along with web3.js. If not, see . * name: 'myString' * }] * }); - * + * * ``` - * + * * @module ABI */ - // This code was taken from: https://github.com/Mrtenz/eip-712/tree/master import { Eip712TypedData } from 'web3-types'; @@ -231,7 +230,7 @@ const encodeData = ( ): string => { const [types, values] = typedData.types[type].reduce<[string[], unknown[]]>( ([_types, _values], field) => { - if (isNullish(data[field.name]) || isNullish(data[field.name])) { + if (isNullish(data[field.name]) || isNullish(field.type)) { throw new AbiError(`Cannot encode data: missing data for '${field.name}'`, { data, field, diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index 3bb49217192..a2d1fffe191 100644 --- a/packages/web3-eth-accounts/src/account.ts +++ b/packages/web3-eth-accounts/src/account.ts @@ -17,29 +17,29 @@ along with web3.js. If not, see . /** * The web3 accounts package contains functions to generate Ethereum accounts and sign transactions & data. - * + * * For using accounts functions, first install Web3 package using `npm i web3` or `yarn add web3` based on your package manager usage. - * After that, Accounts functions will be available as mentioned in following snippet. + * After that, Accounts functions will be available as mentioned in following snippet. * ```ts * import {Web3} from 'web3'; - * + * * const web3 = new Web3(); * const account = web3.eth.accounts.create(); * const result = web3.eth.accounts.hashMessage("Test Message"); - * + * * ``` - * + * * For using individual package install `web3-eth-accounts` package using `npm i web3-eth-accounts` or `yarn add web3-eth-accounts` and only import required functions. - * This is more efficient approach for building lightweight applications. + * This is more efficient approach for building lightweight applications. * ```ts * import {create,hashMessage} from 'web3-eth-accounts'; - * + * * const account = create(); * const result = hashMessage("Test Message"); - * + * * ``` * @module Accounts - * + * */ import { @@ -98,24 +98,23 @@ import type { SignResult, } from './types.js'; - /** * Get the private key Uint8Array after the validation. - * Note: This function is not exported through main web3 package, so for using it directly import from accounts package. + * Note: This function is not exported through main web3 package, so for using it directly import from accounts package. * @param data - Private key - * @param ignoreLength - Optional, ignore length check during validation + * @param ignoreLength - Optional, ignore length check during validation * @returns The Uint8Array private key * * ```ts * parseAndValidatePrivateKey("0x08c673022000ece7964ea4db2d9369c50442b2869cbd8fc21baaca59e18f642c") - * + * * > Uint8Array(32) [ * 186, 26, 143, 168, 235, 179, 90, 75, * 101, 63, 84, 221, 152, 150, 30, 203, * 8, 113, 94, 226, 53, 213, 216, 5, * 194, 159, 17, 53, 219, 97, 121, 248 * ] - * + * * ``` */ export const parseAndValidatePrivateKey = (data: Bytes, ignoreLength?: boolean): Uint8Array => { @@ -127,7 +126,7 @@ export const parseAndValidatePrivateKey = (data: Bytes, ignoreLength?: boolean): } try { - privateKeyUint8Array = isUint8Array(data) ? (data ) : bytesToUint8Array(data); + privateKeyUint8Array = isUint8Array(data) ? data : bytesToUint8Array(data); } catch { throw new InvalidPrivateKeyError(); } @@ -149,11 +148,11 @@ export const parseAndValidatePrivateKey = (data: Bytes, ignoreLength?: boolean): * * ```ts * web3.eth.accounts.hashMessage("Hello world") - * + * * > "0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede" - * + * * web3.eth.accounts.hashMessage(web3.utils.utf8ToHex("Hello world")) // Will be hex decoded in hashMessage - * + * * > "0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede" * ``` */ @@ -228,7 +227,7 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * Signing a legacy transaction * ```ts * import {signTransaction, Transaction} from 'web3-eth-accounts'; - * + * * signTransaction(new Transaction({ * to: '0x118C2E5F57FD62C2B5b46a5ae9216F4FF4011a07', * value: '0x186A0', @@ -238,7 +237,7 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * chainId: 1, * nonce: 0 }), * '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318') - * + * * > { * messageHash: '0x28b7b75f7ba48d588a902c1ff4d5d13cc0ca9ac0aaa39562368146923fb853bf', * v: '0x25', @@ -247,11 +246,11 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * rawTransaction: '0xf869808609184e72a0008352081294118c2e5f57fd62c2b5b46a5ae9216f4ff4011a07830186a08025a00601b0017b0e20dd0eeda4b895fbc1a9e8968990953482214f880bae593e71b5a0690d984493560552e3ebdcc19a65b9c301ea9ddc82d3ab8cfde60485fd5722ce', * transactionHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' * ``` - * + * * Signing an eip 1559 transaction * ```ts * import {signTransaction, Transaction} from 'web3-eth-accounts'; - * + * * signTransaction(new Transaction({ * to: '0xF0109fC8DF283027b6285cc889F5aA624EaC1F55', * maxPriorityFeePerGas: '0x3B9ACA00', @@ -271,11 +270,11 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * transactionHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' * } * ``` - * + * * Signing an eip 2930 transaction * ```ts * import {signTransaction, Transaction} from 'web3-eth-accounts'; - * + * * signTransaction(new Transaction ({ * chainId: 1, * nonce: 0, @@ -294,7 +293,7 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * }, * ], * }),"0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318") - * + * * > { * messageHash: '0xc55ea24bdb4c379550a7c9a6818ac39ca33e75bc78ddb862bd82c31cc1c7a073', * v: '0x26', @@ -366,11 +365,11 @@ export const recoverTransaction = (rawTransaction: HexString): Address => { * @param s - S value in signature * @param prefixed - (default: false) If the last parameter is true, the given message will NOT automatically be prefixed with `"\\x19Ethereum Signed Message:\\n" + message.length + message`, and assumed to be already prefixed. * @returns The Ethereum address used to sign this data - * + * * ```ts * const data = 'Some data'; * const sigObj = web3.eth.accounts.sign(data, '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728') - * + * * > { * message: 'Some data', * messageHash: '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655', @@ -379,10 +378,10 @@ export const recoverTransaction = (rawTransaction: HexString): Address => { * s: '0x53e41351267b20d4a89ebfe9c8f03c04de9b345add4a52f15bd026b63c8fb150', * signature: '0xa8037a6116c176a25e6fc224947fde9e79a2deaa0dd8b67b366fbdfdbffc01f953e41351267b20d4a89ebfe9c8f03c04de9b345add4a52f15bd026b63c8fb1501b' * } - * + * * // now recover * web3.eth.accounts.recover(data, sigObj.v, sigObj.r, sigObj.s) - * + * * > 0xEB014f8c8B418Db6b45774c326A0E64C78914dC0 * ``` */ @@ -422,7 +421,7 @@ export const recover = ( const address = toChecksumAddress(`0x${publicHash.slice(-40)}`); return address; -};; +}; /** * Get the ethereum Address from a private key @@ -433,7 +432,7 @@ export const recover = ( * @example * ```ts * web3.eth.accounts.privateKeyToAddress("0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728") - * + * * > "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0" * ``` */ @@ -462,7 +461,7 @@ export const privateKeyToAddress = (privateKey: Bytes): string => { * @example * ```ts * web3.eth.accounts.privateKeyToPublicKey("0x1e046a882bb38236b646c9f135cf90ad90a140810f439875f2a6dd8e50fa261f", true) - * + * * > "0x42beb65f179720abaa3ec9a70a539629cbbc5ec65bb57e7fc78977796837e537662dd17042e6449dc843c281067a4d6d8d1a1775a13c41901670d5de7ee6503a" // uncompressed public key * ``` */ @@ -485,7 +484,7 @@ export const privateKeyToPublicKey = (privateKey: Bytes, isCompressed: boolean): * * Encrypt using scrypt options: * ```ts - * + * * web3.eth.accounts.encrypt( * '0x67f476289210e3bef3c1c75e4de993ff0a00663df00def84e73aa7411eac18a6', * '123', @@ -659,7 +658,7 @@ export const encrypt = async ( * * ```ts * web3.eth.accounts.privateKeyToAccount("0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709"); - * + * * > { * address: '0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa01', * privateKey: '0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709', @@ -740,8 +739,8 @@ export const create = (): Web3Account => { * mac: 'efbf6d3409f37c0084a79d5fdf9a6f5d97d11447517ef1ea8374f51e581b7efd' * } * }, '123').then(console.log); - * - * + * + * * > { * address: '0xcdA9A91875fc35c8Ac1320E098e584495d66e47c', * privateKey: '67f476289210e3bef3c1c75e4de993ff0a00663df00def84e73aa7411eac18a6', diff --git a/packages/web3-eth-accounts/src/tx/baseTransaction.ts b/packages/web3-eth-accounts/src/tx/baseTransaction.ts index 3f8da6d4e41..5762b8889e9 100644 --- a/packages/web3-eth-accounts/src/tx/baseTransaction.ts +++ b/packages/web3-eth-accounts/src/tx/baseTransaction.ts @@ -578,7 +578,11 @@ export abstract class BaseTransaction { return postfix; } // eslint-disable-next-line class-methods-use-this - private _ecsign(msgHash: Uint8Array, privateKey: Uint8Array, chainId?: bigint): ECDSASignature { + protected _ecsign( + msgHash: Uint8Array, + privateKey: Uint8Array, + chainId?: bigint, + ): ECDSASignature { const signature = secp256k1.sign(msgHash, privateKey); const signatureBytes = signature.toCompactRawBytes(); diff --git a/packages/web3-utils/src/hash.ts b/packages/web3-utils/src/hash.ts index 0289a429a52..d8d959e4509 100644 --- a/packages/web3-utils/src/hash.ts +++ b/packages/web3-utils/src/hash.ts @@ -73,6 +73,41 @@ import { leftPad, rightPad, toTwosComplement } from './string_manipulation.js'; const SHA3_EMPTY_BYTES = '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'; +/** + * A wrapper for ethereum-cryptography/keccak256 to allow hashing a `string` and a `bigint` in addition to `UInt8Array` + * @param data - the input to hash + * @returns - the Keccak-256 hash of the input + * + * @example + * ```ts + * console.log(web3.utils.keccak256Wrapper('web3.js')); + * > 0x63667efb1961039c9bb0d6ea7a5abdd223a3aca7daa5044ad894226e1f83919a + * + * console.log(web3.utils.keccak256Wrapper(1)); + * > 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6 + * + * console.log(web3.utils.keccak256Wrapper(0xaf12fd)); + * > 0x358640fd4719fa923525d74ab5ae80a594301aba5543e3492b052bf4598b794c + * ``` + */ +export const keccak256Wrapper = ( + data: Bytes | Numbers | string | ReadonlyArray, +): string => { + let processedData; + if (typeof data === 'bigint' || typeof data === 'number') { + processedData = utf8ToBytes(data.toString()); + } else if (Array.isArray(data)) { + processedData = new Uint8Array(data); + } else if (typeof data === 'string' && !isHexStrict(data)) { + processedData = utf8ToBytes(data); + } else { + processedData = bytesToUint8Array(data as Bytes); + } + return bytesToHex(keccak256(validatorUtils.ensureIfUint8Array(processedData))); +}; + +export { keccak256Wrapper as keccak256 }; + /** * computes the Keccak-256 hash of the input and returns a hexstring * @param data - the input to hash @@ -99,7 +134,7 @@ export const sha3 = (data: Bytes): string | undefined => { } else { updatedData = data; } - const hash = bytesToHex(keccak256(validatorUtils.ensureIfUint8Array(updatedData))); + const hash = keccak256Wrapper(updatedData); // EIP-1052 if hash is equal to c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470, keccak was given empty data return hash === SHA3_EMPTY_BYTES ? undefined : hash; @@ -128,41 +163,6 @@ export const sha3Raw = (data: Bytes): string => { return hash; }; -/** - * A wrapper for ethereum-cryptography/keccak256 to allow hashing a `string` and a `bigint` in addition to `UInt8Array` - * @param data - the input to hash - * @returns - the Keccak-256 hash of the input - * - * @example - * ```ts - * console.log(web3.utils.keccak256Wrapper('web3.js')); - * > 0x63667efb1961039c9bb0d6ea7a5abdd223a3aca7daa5044ad894226e1f83919a - * - * console.log(web3.utils.keccak256Wrapper(1)); - * > 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6 - * - * console.log(web3.utils.keccak256Wrapper(0xaf12fd)); - * > 0x358640fd4719fa923525d74ab5ae80a594301aba5543e3492b052bf4598b794c - * ``` - */ -export const keccak256Wrapper = ( - data: Bytes | Numbers | string | ReadonlyArray, -): string => { - let processedData; - if (typeof data === 'bigint' || typeof data === 'number') { - processedData = utf8ToBytes(data.toString()); - } else if (Array.isArray(data)) { - processedData = new Uint8Array(data); - } else if (typeof data === 'string' && !isHexStrict(data)) { - processedData = utf8ToBytes(data); - } else { - processedData = bytesToUint8Array(data as Bytes); - } - return bytesToHex(keccak256(validatorUtils.ensureIfUint8Array(processedData))); -}; - -export { keccak256Wrapper as keccak256 }; - /** * returns type and value * @param arg - the input to return the type and value diff --git a/packages/web3/test/integration/web3.test.ts b/packages/web3/test/integration/web3.test.ts index 37587954bb0..54720890901 100644 --- a/packages/web3/test/integration/web3.test.ts +++ b/packages/web3/test/integration/web3.test.ts @@ -35,7 +35,7 @@ import { isSocket, isWs, itIf, - waitForOpenConnection + waitForOpenConnection, } from '../shared_fixtures/system_tests_utils'; /* eslint-disable jest/no-standalone-expect */ @@ -58,7 +58,7 @@ describe('Web3 instance', () => { try { await closeOpenConnection(web3); } catch (e) { - console.warn("Failed to close open con", e) + console.warn('Failed to close open con', e); } }); @@ -67,7 +67,11 @@ describe('Web3 instance', () => { }); afterEach(async () => { - if (isWs) { + if ( + isWs && + web3?.provider?.supportsSubscriptions && + web3.provider?.supportsSubscriptions() + ) { // make sure we try to close the connection after it is established if ( web3?.provider && @@ -126,7 +130,6 @@ describe('Web3 instance', () => { it('should be able use "utils"', () => { web3 = new Web3(); - expect(web3.utils.hexToNumber('0x5')).toBe(5); }); @@ -312,7 +315,7 @@ describe('Web3 instance', () => { } catch (e) { // ignored } - }) + }); it('should update defaults on contract instance', () => { const hardfork = 'berlin'; @@ -331,6 +334,5 @@ describe('Web3 instance', () => { // ignored } }); - }); }); diff --git a/scripts/system_tests_utils.ts b/scripts/system_tests_utils.ts index da58fc19d91..48ea2129c06 100644 --- a/scripts/system_tests_utils.ts +++ b/scripts/system_tests_utils.ts @@ -154,10 +154,14 @@ export const waitForOpenConnection = async ( }); export const closeOpenConnection = async (web3Context: Web3Context) => { - if (!isSocket || web3Context?.provider instanceof HttpProvider) { + if ( + !isSocket || + web3Context?.provider instanceof HttpProvider || + (web3Context?.provider?.supportsSubscriptions && + !web3Context.provider?.supportsSubscriptions()) + ) { return; } - // make sure we try to close the connection after it is established if ( web3Context?.provider && @@ -165,20 +169,17 @@ export const closeOpenConnection = async (web3Context: Web3Context) => { ) { await waitForOpenConnection(web3Context); } - // If an error happened during closing, that is acceptable at tests, just print a 'warn'. if (web3Context?.provider) { (web3Context.provider as unknown as Web3BaseProvider).on('error', (err: any) => { console.warn('error while trying to close the connection', err); }); } - // Wait a bit to ensure the connection does not have a pending data that // could cause an error if written after closing the connection. await new Promise(resolve => { setTimeout(resolve, 500); }); - if ( web3Context?.provider && 'disconnect' in (web3Context.provider as unknown as Web3BaseProvider)