@imtbl/checkout-widgets 2.24.4 → 2.24.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/browser/{AddTokensWidget-DuUFROT3.js → AddTokensWidget-DtKOUsGu.js} +3 -3
  2. package/dist/browser/{BridgeWidget-hq-FrbN3.js → BridgeWidget-BEyIilgs.js} +7 -7
  3. package/dist/browser/{CommerceWidget-DWiMfCWY.js → CommerceWidget-lHiaZb79.js} +13 -13
  4. package/dist/browser/{FeesBreakdown-qdVxOL0i.js → FeesBreakdown-CGoQZNw_.js} +1 -1
  5. package/dist/browser/{OnRampWidget-Bdiw7ATC.js → OnRampWidget-XiCeV2Y1.js} +3 -3
  6. package/dist/browser/{SaleWidget-hjvQ_UrC.js → SaleWidget-wg7122ny.js} +10 -10
  7. package/dist/browser/{SpendingCapHero-B1igTsUC.js → SpendingCapHero-50L-8e0O.js} +1 -1
  8. package/dist/browser/{SwapWidget-DhwWytog.js → SwapWidget-DyRGb56t.js} +7 -8
  9. package/dist/browser/{TokenImage-CGWnVL_Z.js → TokenImage-BSEcsGPt.js} +1 -1
  10. package/dist/browser/{TopUpView-BZxdHU6y.js → TopUpView-BruGxwia.js} +1 -1
  11. package/dist/browser/{WalletApproveHero-Btpgg9el.js → WalletApproveHero-BNeRqb6c.js} +46 -20
  12. package/dist/browser/{WalletWidget-C07lsS9H.js → WalletWidget-Qucp_iny.js} +3 -3
  13. package/dist/browser/{auto-track-DIuUVS9U.js → auto-track-YBHEPAZ3.js} +1 -1
  14. package/dist/browser/{index-BI3HRAbF.js → index-B_AfOz3m.js} +1 -1
  15. package/dist/browser/{index-CX_Q0bB9.js → index-BuHtApNC.js} +1 -1
  16. package/dist/browser/{index-BViG2No5.js → index-C1C2zjQB.js} +1 -1
  17. package/dist/browser/{index-fALsJci7.js → index-CZghGU-d.js} +54 -27
  18. package/dist/browser/{index-DHwKjlaG.js → index-DRpwE8WW.js} +1 -1
  19. package/dist/browser/{index-MXd6hJdY.js → index-Do4ES1-4.js} +2 -2
  20. package/dist/browser/{index-DAKBWys4.js → index-DqtCQcyE.js} +1 -1
  21. package/dist/browser/{index-BQfU8gia.js → index-DtCucxzi.js} +1 -1
  22. package/dist/browser/index.js +1 -1
  23. package/dist/browser/{index.umd-BcJ3xskH.js → index.umd-CjyGntCd.js} +1 -1
  24. package/dist/browser/{useInterval-CqSdWQaT.js → useInterval-C-BIKYov.js} +1 -1
  25. package/dist/types/lib/chains.d.ts +15 -0
  26. package/package.json +7 -7
  27. package/src/components/NetworkSwitchDrawer/NetworkSwitchDrawer.tsx +50 -30
  28. package/src/lib/chains.test.ts +42 -1
  29. package/src/lib/chains.ts +21 -0
  30. package/src/locales/en.json +8 -1
  31. package/src/widgets/bridge/components/BridgeReviewSummary.tsx +2 -1
  32. package/src/widgets/connect/components/WalletList.tsx +3 -3
  33. package/src/widgets/connect/views/ReadyToConnect.tsx +3 -3
  34. package/src/widgets/connect/views/SwitchNetworkZkEVM.tsx +3 -3
  35. package/src/widgets/swap/components/SwapForm.tsx +2 -2
@@ -1,5 +1,7 @@
1
1
  import { ChainId, ChainName, ChainSlug } from '@imtbl/checkout-sdk';
2
- import { getChainIdBySlug, getChainNameById, getChainSlugById } from './chains';
2
+ import {
3
+ getChainIdBySlug, getChainNameById, getChainSlugById, parseChainId,
4
+ } from './chains';
3
5
 
4
6
  describe('getChainNameById', () => {
5
7
  const tests = [
@@ -48,3 +50,42 @@ describe('getChainIdBySlug', () => {
48
50
  });
49
51
  });
50
52
  });
53
+
54
+ describe('parseChainId', () => {
55
+ // Regression: a lint autofix once rewrote `parseInt(chainId)` to
56
+ // `parseInt(chainId, 10)`, which returns 0 for the hex values EIP-695
57
+ // mandates. Every chain then read as "wrong network" and the bridge became
58
+ // unusable. These cases pin the hex handling down.
59
+ const hexCases = [
60
+ { value: '0x343b', expected: ChainId.IMTBL_ZKEVM_MAINNET },
61
+ { value: '0x34a1', expected: ChainId.IMTBL_ZKEVM_TESTNET },
62
+ { value: '0x1', expected: ChainId.ETHEREUM },
63
+ { value: '0xaa36a7', expected: ChainId.SEPOLIA },
64
+ ];
65
+
66
+ hexCases.forEach(({ value, expected }) => {
67
+ it(`should parse hex ${value} as ${expected}`, () => {
68
+ expect(parseChainId(value)).toEqual(expected);
69
+ });
70
+ });
71
+
72
+ it('should parse a decimal string', () => {
73
+ expect(parseChainId('13371')).toEqual(ChainId.IMTBL_ZKEVM_MAINNET);
74
+ });
75
+
76
+ it('should pass through a number', () => {
77
+ expect(parseChainId(13371)).toEqual(ChainId.IMTBL_ZKEVM_MAINNET);
78
+ });
79
+
80
+ it('should parse a bigint', () => {
81
+ expect(parseChainId(BigInt(13371))).toEqual(ChainId.IMTBL_ZKEVM_MAINNET);
82
+ });
83
+
84
+ const invalidCases = [null, undefined, '', 'not-a-chain', '0x', 0, -1, 1.5];
85
+
86
+ invalidCases.forEach((value) => {
87
+ it(`should return null for ${JSON.stringify(value)}`, () => {
88
+ expect(parseChainId(value)).toBeNull();
89
+ });
90
+ });
91
+ });
package/src/lib/chains.ts CHANGED
@@ -1,5 +1,26 @@
1
1
  import { ChainId, ChainName, ChainSlug } from '@imtbl/checkout-sdk';
2
2
 
3
+ /**
4
+ * Parse a chain id as returned by an EIP-1193 provider (e.g. `eth_chainId`).
5
+ *
6
+ * EIP-695 specifies a hex-encoded quantity such as `0x343b`, but providers are
7
+ * inconsistent and may return a decimal string or a number instead. `Number()`
8
+ * handles all three.
9
+ *
10
+ * Do NOT reach for `parseInt(value, 10)` here: it silently returns 0 for hex
11
+ * input, which reads as "wrong network" for every chain. Use this helper so the
12
+ * radix decision lives in one tested place rather than at each call site.
13
+ *
14
+ * Returns `null` when the value cannot be parsed, so callers can tell an
15
+ * unknown chain apart from a legitimately parsed id.
16
+ */
17
+ export function parseChainId(chainId: unknown): ChainId | null {
18
+ if (chainId === null || chainId === undefined || chainId === '') return null;
19
+ const parsed = Number(chainId);
20
+ if (!Number.isInteger(parsed) || parsed <= 0) return null;
21
+ return parsed as ChainId;
22
+ }
23
+
3
24
  export function getChainNameById(chainId: ChainId): ChainName {
4
25
  switch (chainId) {
5
26
  case ChainId.ETHEREUM: return ChainName.ETHEREUM;
@@ -1237,7 +1237,14 @@
1237
1237
  "controlledSwitch": {
1238
1238
  "body": "You'll need to switch to the {{chain}} network to proceed"
1239
1239
  },
1240
- "switchButton": "Switch to {{chain}}"
1240
+ "unsupportedSwitch": {
1241
+ "body": "Your {{wallet}} can't switch networks. Go back and choose a different wallet to use the {{chain}} network."
1242
+ },
1243
+ "switchFailed": {
1244
+ "body": "We couldn't switch to the {{chain}} network. Check your {{wallet}} and try again."
1245
+ },
1246
+ "switchButton": "Switch to {{chain}}",
1247
+ "retryButton": "Try again"
1241
1248
  },
1242
1249
  "walletConnectionError": {
1243
1250
  "unableToConnect": {
@@ -22,6 +22,7 @@ import {
22
22
  isWalletConnectProvider,
23
23
  } from '../../../lib/provider';
24
24
  import { calculateCryptoToFiat, getChainImage, isNativeToken } from '../../../lib/utils';
25
+ import { parseChainId } from '../../../lib/chains';
25
26
  import {
26
27
  DEFAULT_QUOTE_REFRESH_INTERVAL,
27
28
  DEFAULT_TOKEN_DECIMALS,
@@ -391,7 +392,7 @@ export function BridgeReviewSummary() {
391
392
  return;
392
393
  }
393
394
  const currentChainId = await provider.send('eth_chainId', []);
394
- const parsedChainId = parseInt(String(currentChainId), 10);
395
+ const parsedChainId = parseChainId(currentChainId);
395
396
  if (parsedChainId !== from?.network) {
396
397
  setShowSwitchNetworkDrawer(true);
397
398
  return;
@@ -51,6 +51,7 @@ import { BrowserWalletItem } from './BrowserWalletItem';
51
51
  import { identifyUser } from '../../../lib/analytics/identifyUser';
52
52
  import { NonPassportWarningDrawer } from './NonPassportWarningDrawer';
53
53
  import { removeSpace } from '../../../lib/utils';
54
+ import { parseChainId } from '../../../lib/chains';
54
55
 
55
56
  export interface WalletListProps {
56
57
  targetWalletRdns?: string;
@@ -136,11 +137,10 @@ export function WalletList(props: WalletListProps) {
136
137
  const handleConnectViewUpdate = async (provider: WrappedBrowserProvider) => {
137
138
  const isPassport = isPassportProvider(provider);
138
139
  const chainId = await provider.send!('eth_chainId', []);
139
- // eslint-disable-next-line radix
140
- const parsedChainId = parseInt(chainId.toString());
140
+ const parsedChainId = parseChainId(chainId);
141
141
  if (
142
142
  parsedChainId !== targetChainId
143
- && !allowedChains?.includes(parsedChainId)
143
+ && !(parsedChainId && allowedChains?.includes(parsedChainId))
144
144
  ) {
145
145
  // TODO: What do we do with Passport here as it can't connect to L1
146
146
  if (isPassport) {
@@ -20,6 +20,7 @@ import { ViewContext, ViewActions } from '../../../context/view-context/ViewCont
20
20
  import { isMetaMaskProvider, isPassportProvider } from '../../../lib/provider';
21
21
  import { UserJourney, useAnalytics } from '../../../context/analytics-provider/SegmentAnalyticsProvider';
22
22
  import { identifyUser } from '../../../lib/analytics/identifyUser';
23
+ import { parseChainId } from '../../../lib/chains';
23
24
 
24
25
  export interface ReadyToConnectProps {
25
26
  targetChainId: ChainId;
@@ -89,9 +90,8 @@ export function ReadyToConnect({ targetChainId, allowedChains }: ReadyToConnectP
89
90
  // eslint-disable-next-line @typescript-eslint/no-shadow
90
91
  const handleConnectViewUpdate = async (provider: WrappedBrowserProvider) => {
91
92
  const chainId = await provider.send!('eth_chainId', []);
92
- // eslint-disable-next-line radix
93
- const parsedChainId = parseInt(chainId.toString());
94
- if (parsedChainId !== targetChainId && !allowedChains?.includes(parsedChainId)) {
93
+ const parsedChainId = parseChainId(chainId);
94
+ if (parsedChainId !== targetChainId && !(parsedChainId && allowedChains?.includes(parsedChainId))) {
95
95
  // TODO: What do we do with Passport here as it can't connect to L1
96
96
  if (isPassport) {
97
97
  viewDispatch({
@@ -3,6 +3,7 @@ import {
3
3
  } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { isWalletConnectProvider } from '../../../lib/provider';
6
+ import { parseChainId } from '../../../lib/chains';
6
7
  import { SimpleTextBody } from '../../../components/Body/SimpleTextBody';
7
8
  import { FooterButton } from '../../../components/Footer/FooterButton';
8
9
  import { HeaderNavigation } from '../../../components/Header/HeaderNavigation';
@@ -34,8 +35,7 @@ export function SwitchNetworkZkEVM() {
34
35
 
35
36
  const checkCorrectNetwork = async () => {
36
37
  const currentChainId = await provider.send('eth_chainId', []);
37
- // eslint-disable-next-line radix
38
- const parsedChainId = Number(currentChainId.toString());
38
+ const parsedChainId = parseChainId(currentChainId);
39
39
  if (parsedChainId === checkout.config.l2ChainId) {
40
40
  connectDispatch({
41
41
  payload: {
@@ -76,7 +76,7 @@ export function SwitchNetworkZkEVM() {
76
76
  if (!provider.send) return;
77
77
 
78
78
  const currentChainId = await provider.send('eth_chainId', []) as `0x${string}`;
79
- const parsedChainId = Number(currentChainId);
79
+ const parsedChainId = parseChainId(currentChainId);
80
80
 
81
81
  if (parsedChainId === checkout.config.l2ChainId) {
82
82
  connectDispatch({
@@ -47,6 +47,7 @@ import { ConnectLoaderContext } from '../../../context/connect-loader-context/Co
47
47
  import useDebounce from '../../../lib/hooks/useDebounce';
48
48
  import { CancellablePromise } from '../../../lib/async/cancellablePromise';
49
49
  import { isPassportProvider } from '../../../lib/provider';
50
+ import { parseChainId } from '../../../lib/chains';
50
51
  import { formatSwapFees } from '../functions/swapFees';
51
52
  import { processGasFree } from '../functions/processGasFree';
52
53
  import { processSecondaryFees } from '../functions/processSecondaryFees';
@@ -885,8 +886,7 @@ export function SwapForm({
885
886
  try {
886
887
  // check for switch network here
887
888
  const currentChainId = await (provider.provider as any).send('eth_chainId', []);
888
- // eslint-disable-next-line radix
889
- const parsedChainId = parseInt(currentChainId.toString());
889
+ const parsedChainId = parseChainId(currentChainId);
890
890
  if (parsedChainId !== checkout.config.l2ChainId) {
891
891
  setShowNetworkSwitchDrawer(true);
892
892
  return;