fix(checkout-widgets): parse hex chain ids so the bridge stops demanding a network switch - #2944
Merged
Merged
Conversation
…ing a network switch `eth_chainId` returns a hex quantity per EIP-695. BridgeReviewSummary parsed it with `parseInt(value, 10)`, which yields 0 for any hex input, so the current chain never matched `from.network` and the "Switch to <chain>" drawer opened on every submit — on every chain, for every wallet. Withdrawals from zkEVM were unusable. This was introduced in #2928: the tooling upgrade removed an `eslint-disable-next-line radix` and satisfied the rule by hardcoding radix 10. The suppression was load-bearing — the radix was omitted deliberately so hex would auto-detect. For Passport the failure was terminal rather than merely annoying: Passport rejects `wallet_switchEthereumChain` by design, and NetworkSwitchDrawer was the only `checkout.switchNetwork` call site without a catch, so each click produced an unhandled rejection and flooded error reporting instead of telling the user anything. - Add `parseChainId` to lib/chains, with tests pinning the hex cases - Use it at every `eth_chainId` call site; the other four still carried the same fragile `eslint-disable radix` and were one autofix away from this bug - Catch switch failures in NetworkSwitchDrawer and surface them as copy - Hide the switch button for Passport, which cannot switch networks Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
View your CI Pipeline Execution ↗ for commit 68070f6
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗ ☁️ Nx Cloud last updated this comment at |
timm088
approved these changes
Aug 7, 2026
alex-connolly
added a commit
that referenced
this pull request
Aug 7, 2026
…fallout Follow-up to #2944. That bug shipped because the rule which would have caught it was set to `warn`, so nothing failed CI. This promotes three rules that catch runtime defects rather than style preferences, and clears the codebase of them so the gate stays green. Promoted to error: - typescript/no-non-null-asserted-optional-chain — `a?.b!` is undefined at runtime while typed as present - typescript/no-base-to-string — stringifying an object yields "[object Object]", silently gutting error messages and analytics payloads - eslint/preserve-caught-error — rethrowing without `cause` discards the original stack Two real defects surfaced by this: - tokenBridge.getFee passed `async () => {...}` to Promise.all without invoking it, so Promise.all resolved the function object and the chain-id validation never ran. Note this restores validation that has been dead: callers passing mismatched chain ids will now get the intended error. - PayWithCoins reported sale failures via `error.toString()` on a SignOrderError ({ type, data }), so every failure event carried the literal string "[object Object]" instead of the failure type. Also fixed: an undefined provider could reach NetworkSwitchDrawer via `from?.browserProvider!`; OrderSummary dereferenced a possibly-missing smartCheckoutResult; SaleWidget built block-explorer links containing "undefined"; fundingBalanceFees pushed fees with a missing required token. `oxlint --fix` was not used. On this repo it rewrites `.sort()` to `.toSorted()` (ES2023, while tsconfig targets ES2022), drops entries from React dependency arrays, and leaves dead whitespace. Every change here is hand-written. Deferred, with counts, to keep this reviewable: - no-floating-promises (230) — the rule closest to #2944's root cause. Needs per-site judgment (`void` for fire-and-forget, real handling for user-triggered actions), so it gets its own PR. - no-unsafe-enum-comparison (93) — needs a canonical type per comparison - react-hooks/exhaustive-deps (235) — every fix changes render behaviour Do not enable the `radix` rule. It is off (style category), and its autofix is what caused #2944. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Customer impact
Illuvium users cannot bridge ILV from Immutable zkEVM back to Ethereum. The bridge prompts "Switch to Immutable zkEVM", and neither the in-widget switch nor a manual MetaMask switch clears it. Reported against
toolkit.immutable.com/ethereum-bridge/, reproduced by the reporter and confirmed here against the deployed bundle.Root cause
eth_chainIdreturns a hex quantity per EIP-695 (0x343b).BridgeReviewSummaryparsed it withparseInt(value, 10), which returns 0 for any hex input. The current chain therefore never matchedfrom.network, so the network-switch drawer opened on every submit — every chain, every wallet.Introduced in #2928 (
chore(build): upgrade repo tooling to latest versions), which removed aneslint-disable-next-line radixand satisfied the rule by hardcoding radix 10:The suppression was load-bearing. The radix was omitted deliberately so
0xwould auto-detect.For Passport the failure was terminal rather than merely annoying. Passport rejects
wallet_switchEthereumChainby design, andNetworkSwitchDrawerwas the onlycheckout.switchNetworkcall site without acatch, so every click produced an unhandled promise rejection. That is theSwitching networks with Passport provider is not supportedflood in the customer's console; the accompanying429s are Sentry rate-limiting that flood, not an API limit.Verified against production: the chunk hash in the customer's stack trace (
WalletApproveHero-Btpgg9el.js) matches@imtbl/checkout-widgets@2.24.4exactly, and line 500 of that deployed file is the uncaughtswitchNetworkcall.Affected versions
2.24.02.24.0→2.24.52.23.0Changes
parseChainIdtolib/chains, with tests pinning the hex caseseth_chainIdcall site. The other four (SwapForm,WalletList,ReadyToConnect,SwitchNetworkZkEVM) were not broken, but each still carried the same fragileeslint-disable radixand was one autofix away from this bugNetworkSwitchDrawerand surface them as copy instead of an unhandled rejectionTesting
pnpm typecheckcleanlib,bridge,swap,connectparseChainIdcases cover hex, decimal, number, bigint, and invalid inputFollow-ups (not in this PR)
no-floating-promisesis set towarn, which is why the uncaughtswitchNetworkshipped silently — there are ~230 more repo-wide. A separate PR promotes that and related rules toerrorand burns them down.Note for that PR: do not enable the
radixrule. It is currently off (stylecategory), and its autofix is what caused this outage.🤖 Generated with Claude Code