From dfc20332c1c298d05c52e4d05db51d83b80fe4de Mon Sep 17 00:00:00 2001 From: samsamtrum Date: Tue, 2 Jun 2026 00:58:10 +0700 Subject: [PATCH] fix connect chain id normalization --- packages/connect/src/utils/helpers.test.ts | 21 ++++++++++++++++++ packages/connect/src/utils/helpers.ts | 25 ++++++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 packages/connect/src/utils/helpers.test.ts diff --git a/packages/connect/src/utils/helpers.test.ts b/packages/connect/src/utils/helpers.test.ts new file mode 100644 index 000000000..7c5e5ea78 --- /dev/null +++ b/packages/connect/src/utils/helpers.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from 'vitest' + +import { normalizeChainId } from './helpers' + +describe('normalizeChainId', () => { + it('normalizes supported chain id values', () => { + expect(normalizeChainId(1)).toBe(1) + expect(normalizeChainId(1n)).toBe(1) + expect(normalizeChainId('1')).toBe(1) + expect(normalizeChainId('0x1')).toBe(1) + expect(normalizeChainId({ chainId: '0x2105' })).toBe(8453) + }) + + it('rejects invalid chain id values', () => { + expect(() => normalizeChainId('1abc')).toThrow('Invalid chain id') + expect(() => normalizeChainId('abc')).toThrow('Invalid chain id') + expect(() => normalizeChainId('0x')).toThrow('Invalid chain id') + expect(() => normalizeChainId(Number.NaN)).toThrow('Invalid chain id') + expect(() => normalizeChainId(BigInt(Number.MAX_SAFE_INTEGER) + 1n)).toThrow('Invalid chain id') + }) +}) diff --git a/packages/connect/src/utils/helpers.ts b/packages/connect/src/utils/helpers.ts index 1c7ab011c..46d5664c4 100644 --- a/packages/connect/src/utils/helpers.ts +++ b/packages/connect/src/utils/helpers.ts @@ -138,13 +138,30 @@ export const normalizeChainId = (chainId: string | number | bigint | { chainId: if (typeof chainId === 'object') { return normalizeChainId(chainId.chainId) } + + let normalizedChainId: number + if (typeof chainId === 'string') { - return Number.parseInt(chainId, chainId.trim().substring(0, 2) === '0x' ? 16 : 10) + const trimmed = chainId.trim() + const isHex = trimmed.startsWith('0x') + if (isHex ? !/^0x[\da-f]+$/iu.test(trimmed) : !/^\d+$/u.test(trimmed)) { + throw new Error(`Invalid chain id: ${chainId}`) + } + normalizedChainId = Number.parseInt(trimmed, isHex ? 16 : 10) + } else if (typeof chainId === 'bigint') { + if (chainId < 0n || chainId > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error(`Invalid chain id: ${chainId.toString()}`) + } + normalizedChainId = Number(chainId) + } else { + normalizedChainId = chainId } - if (typeof chainId === 'bigint') { - return Number(chainId) + + if (!Number.isSafeInteger(normalizedChainId) || normalizedChainId < 0) { + throw new Error(`Invalid chain id: ${chainId.toString()}`) } - return chainId + + return normalizedChainId } export const isSequenceUrl = (url?: string): url is string => {