From 7ab7de3571299575ec70cdb06e54072bf80f9f30 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Mon, 10 Jun 2024 12:57:06 -0400 Subject: [PATCH 1/8] Fix encodeData error condition --- packages/web3-eth-abi/src/eip_712.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) 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, From 6b761af91d9a7d3348482dfc438a2c0896963317 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Thu, 13 Jun 2024 01:10:53 -0400 Subject: [PATCH 2/8] hash fixes --- packages/web3-eth-accounts/src/account.ts | 95 ++++++++++++----------- packages/web3-utils/src/hash.ts | 72 ++++++++--------- 2 files changed, 87 insertions(+), 80 deletions(-) diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index 3bb49217192..9065bb34df9 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,19 +148,22 @@ 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" * ``` */ -export const hashMessage = (message: string): string => { +export const hashMessage = (message: string, noPreamble?: boolean): string => { const messageHex = isHexStrict(message) ? message : utf8ToHex(message); const messageBytes = hexToBytes(messageHex); + if (noPreamble) { + return sha3Raw(messageBytes); + } const preamble = hexToBytes( fromUtf8(`\x19Ethereum Signed Message:\n${messageBytes.byteLength}`), ); @@ -193,10 +195,10 @@ export const hashMessage = (message: string): string => { * } * ``` */ -export const sign = (data: string, privateKey: Bytes): SignResult => { +export const sign = (data: string, privateKey: Bytes, noPreamble: boolean = false): SignResult => { const privateKeyUint8Array = parseAndValidatePrivateKey(privateKey); - const hash = hashMessage(data); + const hash = hashMessage(data, noPreamble); const signature = secp256k1.sign(hash.substring(2), privateKeyUint8Array); const signatureBytes = signature.toCompactRawBytes(); @@ -228,7 +230,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 +240,7 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * chainId: 1, * nonce: 0 }), * '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318') - * + * * > { * messageHash: '0x28b7b75f7ba48d588a902c1ff4d5d13cc0ca9ac0aaa39562368146923fb853bf', * v: '0x25', @@ -247,11 +249,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 +273,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 +296,7 @@ export const sign = (data: string, privateKey: Bytes): SignResult => { * }, * ], * }),"0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318") - * + * * > { * messageHash: '0xc55ea24bdb4c379550a7c9a6818ac39ca33e75bc78ddb862bd82c31cc1c7a073', * v: '0x26', @@ -366,11 +368,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 +381,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 * ``` */ @@ -392,20 +394,21 @@ export const recover = ( prefixedOrR?: boolean | string, s?: string, prefixed?: boolean, + noPreamble?: boolean, ): Address => { if (typeof data === 'object') { const signatureStr = `${data.r}${data.s.slice(2)}${data.v.slice(2)}`; - return recover(data.messageHash, signatureStr, prefixedOrR); + return recover(data.messageHash, signatureStr, prefixedOrR, s, prefixed, noPreamble); } if (typeof signatureOrV === 'string' && typeof prefixedOrR === 'string' && !isNullish(s)) { const signatureStr = `${prefixedOrR}${s.slice(2)}${signatureOrV.slice(2)}`; - return recover(data, signatureStr, prefixed); + return recover(data, signatureStr, prefixed, s, prefixed, noPreamble); } if (isNullish(signatureOrV)) throw new InvalidSignatureError('signature string undefined'); const V_INDEX = 130; // r = first 32 bytes, s = second 32 bytes, v = last byte of signature - const hashedMessage = prefixedOrR ? data : hashMessage(data); + const hashedMessage = prefixedOrR ? data : hashMessage(data, noPreamble); let v = parseInt(signatureOrV.substring(V_INDEX), 16); // 0x + r + s + v if (v > 26) { @@ -422,7 +425,7 @@ export const recover = ( const address = toChecksumAddress(`0x${publicHash.slice(-40)}`); return address; -};; +}; /** * Get the ethereum Address from a private key @@ -433,7 +436,7 @@ export const recover = ( * @example * ```ts * web3.eth.accounts.privateKeyToAddress("0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728") - * + * * > "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0" * ``` */ @@ -462,7 +465,7 @@ export const privateKeyToAddress = (privateKey: Bytes): string => { * @example * ```ts * web3.eth.accounts.privateKeyToPublicKey("0x1e046a882bb38236b646c9f135cf90ad90a140810f439875f2a6dd8e50fa261f", true) - * + * * > "0x42beb65f179720abaa3ec9a70a539629cbbc5ec65bb57e7fc78977796837e537662dd17042e6449dc843c281067a4d6d8d1a1775a13c41901670d5de7ee6503a" // uncompressed public key * ``` */ @@ -485,7 +488,7 @@ export const privateKeyToPublicKey = (privateKey: Bytes, isCompressed: boolean): * * Encrypt using scrypt options: * ```ts - * + * * web3.eth.accounts.encrypt( * '0x67f476289210e3bef3c1c75e4de993ff0a00663df00def84e73aa7411eac18a6', * '123', @@ -659,7 +662,7 @@ export const encrypt = async ( * * ```ts * web3.eth.accounts.privateKeyToAccount("0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709"); - * + * * > { * address: '0xb8CE9ab6943e0eCED004cDe8e3bBed6568B2Fa01', * privateKey: '0x348ce564d427a3311b6536bbcff9390d69395b06ed6c486954e971d960fe8709', @@ -679,8 +682,12 @@ export const privateKeyToAccount = (privateKey: Bytes, ignoreLength?: boolean): signTransaction: (_tx: Transaction) => { throw new TransactionSigningError('Do not have network access to sign the transaction'); }, - sign: (data: Record | string) => - sign(typeof data === 'string' ? data : JSON.stringify(data), privateKeyUint8Array), + sign: (data: Record | string, noPreamble: boolean = false) => + sign( + typeof data === 'string' ? data : JSON.stringify(data), + privateKeyUint8Array, + noPreamble, + ), encrypt: async (password: string, options?: Record) => encrypt(privateKeyUint8Array, password, options), }; @@ -740,8 +747,8 @@ export const create = (): Web3Account => { * mac: 'efbf6d3409f37c0084a79d5fdf9a6f5d97d11447517ef1ea8374f51e581b7efd' * } * }, '123').then(console.log); - * - * + * + * * > { * address: '0xcdA9A91875fc35c8Ac1320E098e584495d66e47c', * privateKey: '67f476289210e3bef3c1c75e4de993ff0a00663df00def84e73aa7411eac18a6', 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 From 82552937b9313f31a3997073500ff39d3641146b Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Thu, 13 Jun 2024 01:11:33 -0400 Subject: [PATCH 3/8] lint:fix --- packages/web3-eth-accounts/src/account.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index 9065bb34df9..34970da2fc3 100644 --- a/packages/web3-eth-accounts/src/account.ts +++ b/packages/web3-eth-accounts/src/account.ts @@ -195,7 +195,7 @@ export const hashMessage = (message: string, noPreamble?: boolean): string => { * } * ``` */ -export const sign = (data: string, privateKey: Bytes, noPreamble: boolean = false): SignResult => { +export const sign = (data: string, privateKey: Bytes, noPreamble = false): SignResult => { const privateKeyUint8Array = parseAndValidatePrivateKey(privateKey); const hash = hashMessage(data, noPreamble); @@ -682,7 +682,7 @@ export const privateKeyToAccount = (privateKey: Bytes, ignoreLength?: boolean): signTransaction: (_tx: Transaction) => { throw new TransactionSigningError('Do not have network access to sign the transaction'); }, - sign: (data: Record | string, noPreamble: boolean = false) => + sign: (data: Record | string, noPreamble = false) => sign( typeof data === 'string' ? data : JSON.stringify(data), privateKeyUint8Array, From ff9c1da032a9ae997f1ceab443f80f7e727491c6 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Thu, 13 Jun 2024 13:09:32 -0400 Subject: [PATCH 4/8] revert some changes --- packages/web3-eth-accounts/src/account.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index 34970da2fc3..e325b3eba50 100644 --- a/packages/web3-eth-accounts/src/account.ts +++ b/packages/web3-eth-accounts/src/account.ts @@ -682,12 +682,8 @@ export const privateKeyToAccount = (privateKey: Bytes, ignoreLength?: boolean): signTransaction: (_tx: Transaction) => { throw new TransactionSigningError('Do not have network access to sign the transaction'); }, - sign: (data: Record | string, noPreamble = false) => - sign( - typeof data === 'string' ? data : JSON.stringify(data), - privateKeyUint8Array, - noPreamble, - ), + sign: (data: Record | string) => + sign(typeof data === 'string' ? data : JSON.stringify(data), privateKeyUint8Array), encrypt: async (password: string, options?: Record) => encrypt(privateKeyUint8Array, password, options), }; From 01580895d4440ecb2b78ddbcef6356323ec3bac4 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Fri, 14 Jun 2024 13:21:53 -0400 Subject: [PATCH 5/8] revert noPreamble --- packages/web3-eth-accounts/src/account.ts | 16 ++++++---------- .../web3-eth-accounts/src/tx/baseTransaction.ts | 6 +++++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index e325b3eba50..ec5116a3690 100644 --- a/packages/web3-eth-accounts/src/account.ts +++ b/packages/web3-eth-accounts/src/account.ts @@ -156,14 +156,11 @@ export const parseAndValidatePrivateKey = (data: Bytes, ignoreLength?: boolean): * > "0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede" * ``` */ -export const hashMessage = (message: string, noPreamble?: boolean): string => { +export const hashMessage = (message: string): string => { const messageHex = isHexStrict(message) ? message : utf8ToHex(message); const messageBytes = hexToBytes(messageHex); - if (noPreamble) { - return sha3Raw(messageBytes); - } const preamble = hexToBytes( fromUtf8(`\x19Ethereum Signed Message:\n${messageBytes.byteLength}`), ); @@ -195,10 +192,10 @@ export const hashMessage = (message: string, noPreamble?: boolean): string => { * } * ``` */ -export const sign = (data: string, privateKey: Bytes, noPreamble = false): SignResult => { +export const sign = (data: string, privateKey: Bytes): SignResult => { const privateKeyUint8Array = parseAndValidatePrivateKey(privateKey); - const hash = hashMessage(data, noPreamble); + const hash = hashMessage(data); const signature = secp256k1.sign(hash.substring(2), privateKeyUint8Array); const signatureBytes = signature.toCompactRawBytes(); @@ -394,21 +391,20 @@ export const recover = ( prefixedOrR?: boolean | string, s?: string, prefixed?: boolean, - noPreamble?: boolean, ): Address => { if (typeof data === 'object') { const signatureStr = `${data.r}${data.s.slice(2)}${data.v.slice(2)}`; - return recover(data.messageHash, signatureStr, prefixedOrR, s, prefixed, noPreamble); + return recover(data.messageHash, signatureStr, prefixedOrR, s, prefixed); } if (typeof signatureOrV === 'string' && typeof prefixedOrR === 'string' && !isNullish(s)) { const signatureStr = `${prefixedOrR}${s.slice(2)}${signatureOrV.slice(2)}`; - return recover(data, signatureStr, prefixed, s, prefixed, noPreamble); + return recover(data, signatureStr, prefixed, s, prefixed); } if (isNullish(signatureOrV)) throw new InvalidSignatureError('signature string undefined'); const V_INDEX = 130; // r = first 32 bytes, s = second 32 bytes, v = last byte of signature - const hashedMessage = prefixedOrR ? data : hashMessage(data, noPreamble); + const hashedMessage = prefixedOrR ? data : hashMessage(data); let v = parseInt(signatureOrV.substring(V_INDEX), 16); // 0x + r + s + v if (v > 26) { 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(); From aaef824f2a09b118f28b3bba714da6c2189c33da Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Fri, 14 Jun 2024 13:24:13 -0400 Subject: [PATCH 6/8] revert recover --- packages/web3-eth-accounts/src/account.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index ec5116a3690..a2d1fffe191 100644 --- a/packages/web3-eth-accounts/src/account.ts +++ b/packages/web3-eth-accounts/src/account.ts @@ -394,11 +394,11 @@ export const recover = ( ): Address => { if (typeof data === 'object') { const signatureStr = `${data.r}${data.s.slice(2)}${data.v.slice(2)}`; - return recover(data.messageHash, signatureStr, prefixedOrR, s, prefixed); + return recover(data.messageHash, signatureStr, prefixedOrR); } if (typeof signatureOrV === 'string' && typeof prefixedOrR === 'string' && !isNullish(s)) { const signatureStr = `${prefixedOrR}${s.slice(2)}${signatureOrV.slice(2)}`; - return recover(data, signatureStr, prefixed, s, prefixed); + return recover(data, signatureStr, prefixed); } if (isNullish(signatureOrV)) throw new InvalidSignatureError('signature string undefined'); From 2f456e61ac493f27627e04544cfe65b7ef2f3701 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Mon, 17 Jun 2024 10:21:59 -0400 Subject: [PATCH 7/8] fix integration tests --- packages/web3/test/integration/web3.test.ts | 14 ++++++++------ scripts/system_tests_utils.ts | 11 ++++++----- 2 files changed, 14 insertions(+), 11 deletions(-) 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..5750dcf8591 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) From 7408a3dcee54865f7a102a541f0a233ffac5126e Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Mon, 17 Jun 2024 10:59:51 -0400 Subject: [PATCH 8/8] fix integration tests --- scripts/system_tests_utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system_tests_utils.ts b/scripts/system_tests_utils.ts index 5750dcf8591..48ea2129c06 100644 --- a/scripts/system_tests_utils.ts +++ b/scripts/system_tests_utils.ts @@ -157,7 +157,7 @@ export const closeOpenConnection = async (web3Context: Web3Context) => { if ( !isSocket || web3Context?.provider instanceof HttpProvider || - (web3Context.provider?.supportsSubscriptions && + (web3Context?.provider?.supportsSubscriptions && !web3Context.provider?.supportsSubscriptions()) ) { return;