diff --git a/.changeset/signed-odd-length-hex.md b/.changeset/signed-odd-length-hex.md new file mode 100644 index 0000000000..1d2bd2cf99 --- /dev/null +++ b/.changeset/signed-odd-length-hex.md @@ -0,0 +1,5 @@ +--- +"viem": patch +--- + +Fixed `hexToBigInt` and `hexToNumber` throwing `RangeError: The number 1.5 cannot be converted to a BigInt` when `signed: true` is used with an odd-length hex value (e.g. the documented example `hexToBigInt('0x1a4', { signed: true })`, or minimal-encoded RPC quantities such as `0x0`). The byte size of the value is now rounded up. diff --git a/src/utils/encoding/fromHex.test.ts b/src/utils/encoding/fromHex.test.ts index ac91c8fa5b..8bc4da3e6c 100644 --- a/src/utils/encoding/fromHex.test.ts +++ b/src/utils/encoding/fromHex.test.ts @@ -46,6 +46,10 @@ describe('converts hex to number', () => { expect(hexToNumber('0x00027760a62ec2ac', { signed: true })).toBe( 694206942069420, ) + + // odd-length hex + expect(hexToNumber('0x0', { signed: true })).toBe(0) + expect(hexToNumber('0x1a4', { signed: true })).toBe(420) }) test('args: size', () => { @@ -129,6 +133,11 @@ describe('converts hex to bigint', () => { { signed: true }, ), ).toBe(-12312312312312312412n) + + // odd-length hex + expect(hexToBigInt('0x0', { signed: true })).toBe(0n) + expect(hexToBigInt('0xf', { signed: true })).toBe(15n) + expect(hexToBigInt('0x1a4', { signed: true })).toBe(420n) }) test('args: size', () => { diff --git a/src/utils/encoding/fromHex.ts b/src/utils/encoding/fromHex.ts index 993b98a1d5..13bf84960c 100644 --- a/src/utils/encoding/fromHex.ts +++ b/src/utils/encoding/fromHex.ts @@ -137,7 +137,7 @@ export function hexToBigInt(hex: Hex, opts: HexToBigIntOpts = {}): bigint { const value = BigInt(hex) if (!signed) return value - const size = (hex.length - 2) / 2 + const size = Math.ceil((hex.length - 2) / 2) const max = (1n << (BigInt(size) * 8n - 1n)) - 1n if (value <= max) return value