@hongming-wang/usdc-bridge-widget 0.2.1 → 0.2.2

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.
package/dist/index.d.mts CHANGED
@@ -59,7 +59,12 @@ interface BridgeChainConfig {
59
59
  chain: Chain;
60
60
  /** USDC token contract address on this chain (checksummed) */
61
61
  usdcAddress: `0x${string}`;
62
- /** Circle TokenMessenger contract address for CCTP transfers */
62
+ /**
63
+ * Circle TokenMessenger contract address for CCTP transfers.
64
+ * While marked optional for type flexibility, this address is required
65
+ * for bridging to work. The widget will use TOKEN_MESSENGER_ADDRESSES
66
+ * from constants.ts as defaults if not provided via createChainConfig().
67
+ */
63
68
  tokenMessengerAddress?: `0x${string}`;
64
69
  /** URL for the chain's icon/logo image (optional, falls back to initial) */
65
70
  iconUrl?: string;
package/dist/index.d.ts CHANGED
@@ -59,7 +59,12 @@ interface BridgeChainConfig {
59
59
  chain: Chain;
60
60
  /** USDC token contract address on this chain (checksummed) */
61
61
  usdcAddress: `0x${string}`;
62
- /** Circle TokenMessenger contract address for CCTP transfers */
62
+ /**
63
+ * Circle TokenMessenger contract address for CCTP transfers.
64
+ * While marked optional for type flexibility, this address is required
65
+ * for bridging to work. The widget will use TOKEN_MESSENGER_ADDRESSES
66
+ * from constants.ts as defaults if not provided via createChainConfig().
67
+ */
63
68
  tokenMessengerAddress?: `0x${string}`;
64
69
  /** URL for the chain's icon/logo image (optional, falls back to initial) */
65
70
  iconUrl?: string;
package/dist/index.js CHANGED
@@ -127,6 +127,7 @@ var USDC_ADDRESSES = {
127
127
  // Sonic
128
128
  480: "0x79A02482A880bCE3F13e09Da970dC34db4CD24d1",
129
129
  // World Chain
130
+ // Note: Monad is defined but not yet supported by Circle Bridge Kit SDK
130
131
  10200: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603",
131
132
  // Monad
132
133
  1329: "0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392",
@@ -617,6 +618,8 @@ function useBridgeQuote(sourceChainId, destChainId, amount) {
617
618
  }
618
619
 
619
620
  // src/hooks.ts
621
+ var _useBridgeEstimateWarned = false;
622
+ var _useFormatNumberWarned = false;
620
623
  function useUSDCBalance(chainConfig) {
621
624
  const { address } = (0, import_wagmi2.useAccount)();
622
625
  const {
@@ -685,6 +688,8 @@ function useAllUSDCBalances(chainConfigs) {
685
688
  return {
686
689
  balances,
687
690
  isLoading,
691
+ // Cast to () => void since we don't need the Promise return value.
692
+ // The caller just needs to trigger a refetch, not await it.
688
693
  refetch
689
694
  };
690
695
  }
@@ -767,9 +772,12 @@ function useUSDCAllowance(chainConfig, spenderAddress) {
767
772
  }
768
773
  function useBridgeEstimate(sourceChainId, destChainId, amount) {
769
774
  (0, import_react2.useEffect)(() => {
770
- console.warn(
771
- "[DEPRECATED] useBridgeEstimate is deprecated and will be removed in a future version. Use useBridgeQuote from './useBridge' instead."
772
- );
775
+ if (!_useBridgeEstimateWarned) {
776
+ _useBridgeEstimateWarned = true;
777
+ console.warn(
778
+ "[DEPRECATED] useBridgeEstimate is deprecated and will be removed in a future version. Use useBridgeQuote from './useBridge' instead."
779
+ );
780
+ }
773
781
  }, []);
774
782
  const [estimate, setEstimate] = (0, import_react2.useState)(null);
775
783
  const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
@@ -825,9 +833,12 @@ function useBridgeEstimate(sourceChainId, destChainId, amount) {
825
833
  }
826
834
  function useFormatNumber() {
827
835
  (0, import_react2.useEffect)(() => {
828
- console.warn(
829
- "[DEPRECATED] useFormatNumber is deprecated and will be removed in a future version. Use the formatNumber utility function from './utils' directly instead."
830
- );
836
+ if (!_useFormatNumberWarned) {
837
+ _useFormatNumberWarned = true;
838
+ console.warn(
839
+ "[DEPRECATED] useFormatNumber is deprecated and will be removed in a future version. Use the formatNumber utility function from './utils' directly instead."
840
+ );
841
+ }
831
842
  }, []);
832
843
  return (0, import_react2.useCallback)(
833
844
  (value, decimals = 2) => {
@@ -1995,10 +2006,10 @@ function BridgeWidget({
1995
2006
  sourceChainConfig
1996
2007
  );
1997
2008
  (0, import_react3.useEffect)(() => {
1998
- if (address) {
2009
+ if (isConnected && address) {
1999
2010
  refetchAllBalances();
2000
2011
  }
2001
- }, [address, refetchAllBalances]);
2012
+ }, [isConnected, address, refetchAllBalances]);
2002
2013
  const { bridge: executeBridge, state: bridgeState, reset: resetBridge } = useBridge();
2003
2014
  const { isLoading: isConfirming, isSuccess } = (0, import_wagmi3.useWaitForTransactionReceipt)({
2004
2015
  hash: txHash
package/dist/index.mjs CHANGED
@@ -47,6 +47,7 @@ var USDC_ADDRESSES = {
47
47
  // Sonic
48
48
  480: "0x79A02482A880bCE3F13e09Da970dC34db4CD24d1",
49
49
  // World Chain
50
+ // Note: Monad is defined but not yet supported by Circle Bridge Kit SDK
50
51
  10200: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603",
51
52
  // Monad
52
53
  1329: "0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392",
@@ -537,6 +538,8 @@ function useBridgeQuote(sourceChainId, destChainId, amount) {
537
538
  }
538
539
 
539
540
  // src/hooks.ts
541
+ var _useBridgeEstimateWarned = false;
542
+ var _useFormatNumberWarned = false;
540
543
  function useUSDCBalance(chainConfig) {
541
544
  const { address } = useAccount2();
542
545
  const {
@@ -605,6 +608,8 @@ function useAllUSDCBalances(chainConfigs) {
605
608
  return {
606
609
  balances,
607
610
  isLoading,
611
+ // Cast to () => void since we don't need the Promise return value.
612
+ // The caller just needs to trigger a refetch, not await it.
608
613
  refetch
609
614
  };
610
615
  }
@@ -687,9 +692,12 @@ function useUSDCAllowance(chainConfig, spenderAddress) {
687
692
  }
688
693
  function useBridgeEstimate(sourceChainId, destChainId, amount) {
689
694
  useEffect2(() => {
690
- console.warn(
691
- "[DEPRECATED] useBridgeEstimate is deprecated and will be removed in a future version. Use useBridgeQuote from './useBridge' instead."
692
- );
695
+ if (!_useBridgeEstimateWarned) {
696
+ _useBridgeEstimateWarned = true;
697
+ console.warn(
698
+ "[DEPRECATED] useBridgeEstimate is deprecated and will be removed in a future version. Use useBridgeQuote from './useBridge' instead."
699
+ );
700
+ }
693
701
  }, []);
694
702
  const [estimate, setEstimate] = useState2(null);
695
703
  const [isLoading, setIsLoading] = useState2(false);
@@ -745,9 +753,12 @@ function useBridgeEstimate(sourceChainId, destChainId, amount) {
745
753
  }
746
754
  function useFormatNumber() {
747
755
  useEffect2(() => {
748
- console.warn(
749
- "[DEPRECATED] useFormatNumber is deprecated and will be removed in a future version. Use the formatNumber utility function from './utils' directly instead."
750
- );
756
+ if (!_useFormatNumberWarned) {
757
+ _useFormatNumberWarned = true;
758
+ console.warn(
759
+ "[DEPRECATED] useFormatNumber is deprecated and will be removed in a future version. Use the formatNumber utility function from './utils' directly instead."
760
+ );
761
+ }
751
762
  }, []);
752
763
  return useCallback2(
753
764
  (value, decimals = 2) => {
@@ -1934,10 +1945,10 @@ function BridgeWidget({
1934
1945
  sourceChainConfig
1935
1946
  );
1936
1947
  useEffect3(() => {
1937
- if (address) {
1948
+ if (isConnected && address) {
1938
1949
  refetchAllBalances();
1939
1950
  }
1940
- }, [address, refetchAllBalances]);
1951
+ }, [isConnected, address, refetchAllBalances]);
1941
1952
  const { bridge: executeBridge, state: bridgeState, reset: resetBridge } = useBridge();
1942
1953
  const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt2({
1943
1954
  hash: txHash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hongming-wang/usdc-bridge-widget",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "A reusable USDC cross-chain bridge widget powered by Circle CCTP",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -804,12 +804,12 @@ export function BridgeWidget({
804
804
  sourceChainConfig
805
805
  );
806
806
 
807
- // Refetch balances when wallet connects or address changes
807
+ // Refetch balances when wallet connects, disconnects, or address changes
808
808
  useEffect(() => {
809
- if (address) {
809
+ if (isConnected && address) {
810
810
  refetchAllBalances();
811
811
  }
812
- }, [address, refetchAllBalances]);
812
+ }, [isConnected, address, refetchAllBalances]);
813
813
 
814
814
  // Bridge hook
815
815
  const { bridge: executeBridge, state: bridgeState, reset: resetBridge } = useBridge();
@@ -1027,6 +1027,7 @@ export function BridgeWidget({
1027
1027
  onConnectWallet();
1028
1028
  } else {
1029
1029
  // Warn when onConnectWallet is not provided - helps developers debug
1030
+ // Note: Bundlers typically strip console.warn in production builds
1030
1031
  console.warn(
1031
1032
  "[BridgeWidget] onConnectWallet prop is not provided. " +
1032
1033
  "Please provide onConnectWallet to handle wallet connection " +
@@ -293,6 +293,37 @@ describe("BridgeWidget - Disconnected State", () => {
293
293
  expect(screen.queryByText(/1,000.00 USDC/)).toBeNull();
294
294
  expect(screen.queryByText(/500.00 USDC/)).toBeNull();
295
295
  });
296
+
297
+ it("refetches balances when isConnected changes to true", () => {
298
+ const refetchMock = vi.fn();
299
+ mockUseAllUSDCBalances.mockReturnValue({
300
+ balances: {},
301
+ isLoading: false,
302
+ refetch: refetchMock,
303
+ });
304
+
305
+ // Start disconnected
306
+ mockUseAccount.mockReturnValue({
307
+ address: undefined,
308
+ isConnected: false,
309
+ });
310
+
311
+ const { rerender } = render(<BridgeWidget />);
312
+
313
+ // Refetch should not be called when disconnected
314
+ expect(refetchMock).not.toHaveBeenCalled();
315
+
316
+ // Simulate wallet connection
317
+ mockUseAccount.mockReturnValue({
318
+ address: "0x1234567890123456789012345678901234567890",
319
+ isConnected: true,
320
+ });
321
+
322
+ rerender(<BridgeWidget />);
323
+
324
+ // Refetch should be called after connection
325
+ expect(refetchMock).toHaveBeenCalled();
326
+ });
296
327
  });
297
328
 
298
329
  describe("BridgeWidget - Chain Switch Required", () => {
package/src/constants.ts CHANGED
@@ -29,6 +29,7 @@ export const USDC_ADDRESSES: Record<number, `0x${string}`> = {
29
29
  130: "0x078D782b760474a361dDA0AF3839290b0EF57AD6", // Unichain
30
30
  146: "0x29219dd400f2Bf60E5a23d13Be72B486D4038894", // Sonic
31
31
  480: "0x79A02482A880bCE3F13e09Da970dC34db4CD24d1", // World Chain
32
+ // Note: Monad is defined but not yet supported by Circle Bridge Kit SDK
32
33
  10200: "0x754704Bc059F8C67012fEd69BC8A327a5aafb603", // Monad
33
34
  1329: "0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392", // Sei
34
35
  50: "0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1", // XDC
package/src/hooks.ts CHANGED
@@ -12,6 +12,10 @@ import { USDC_DECIMALS } from "./constants";
12
12
  import { formatNumber } from "./utils";
13
13
  import { getBridgeChain } from "./useBridge";
14
14
 
15
+ // Module-level flags to emit deprecation warnings only once per session
16
+ let _useBridgeEstimateWarned = false;
17
+ let _useFormatNumberWarned = false;
18
+
15
19
  /**
16
20
  * Hook to get USDC balance for a specific chain
17
21
  */
@@ -119,6 +123,8 @@ export function useAllUSDCBalances(chainConfigs: BridgeChainConfig[]): {
119
123
  return {
120
124
  balances,
121
125
  isLoading,
126
+ // Cast to () => void since we don't need the Promise return value.
127
+ // The caller just needs to trigger a refetch, not await it.
122
128
  refetch: refetch as () => void,
123
129
  };
124
130
  }
@@ -249,12 +255,15 @@ export function useBridgeEstimate(
249
255
  destChainId: number | undefined,
250
256
  amount: string
251
257
  ) {
252
- // Emit deprecation warning once
258
+ // Emit deprecation warning once per session
253
259
  useEffect(() => {
254
- console.warn(
255
- "[DEPRECATED] useBridgeEstimate is deprecated and will be removed in a future version. " +
256
- "Use useBridgeQuote from './useBridge' instead."
257
- );
260
+ if (!_useBridgeEstimateWarned) {
261
+ _useBridgeEstimateWarned = true;
262
+ console.warn(
263
+ "[DEPRECATED] useBridgeEstimate is deprecated and will be removed in a future version. " +
264
+ "Use useBridgeQuote from './useBridge' instead."
265
+ );
266
+ }
258
267
  }, []);
259
268
 
260
269
  const [estimate, setEstimate] = useState<BridgeEstimate | null>(null);
@@ -341,12 +350,15 @@ export function useBridgeEstimate(
341
350
  * const formatted = formatNumber(1234.56, 2);
342
351
  */
343
352
  export function useFormatNumber() {
344
- // Emit deprecation warning once
353
+ // Emit deprecation warning once per session
345
354
  useEffect(() => {
346
- console.warn(
347
- "[DEPRECATED] useFormatNumber is deprecated and will be removed in a future version. " +
348
- "Use the formatNumber utility function from './utils' directly instead."
349
- );
355
+ if (!_useFormatNumberWarned) {
356
+ _useFormatNumberWarned = true;
357
+ console.warn(
358
+ "[DEPRECATED] useFormatNumber is deprecated and will be removed in a future version. " +
359
+ "Use the formatNumber utility function from './utils' directly instead."
360
+ );
361
+ }
350
362
  }, []);
351
363
 
352
364
  return useCallback(
package/src/types.ts CHANGED
@@ -55,7 +55,12 @@ export interface BridgeChainConfig {
55
55
  chain: Chain;
56
56
  /** USDC token contract address on this chain (checksummed) */
57
57
  usdcAddress: `0x${string}`;
58
- /** Circle TokenMessenger contract address for CCTP transfers */
58
+ /**
59
+ * Circle TokenMessenger contract address for CCTP transfers.
60
+ * While marked optional for type flexibility, this address is required
61
+ * for bridging to work. The widget will use TOKEN_MESSENGER_ADDRESSES
62
+ * from constants.ts as defaults if not provided via createChainConfig().
63
+ */
59
64
  tokenMessengerAddress?: `0x${string}`;
60
65
  /** URL for the chain's icon/logo image (optional, falls back to initial) */
61
66
  iconUrl?: string;
package/src/useBridge.ts CHANGED
@@ -5,7 +5,9 @@ import { createViemAdapterFromProvider } from "@circle-fin/adapter-viem-v2";
5
5
  import type { BridgeChainConfig } from "./types";
6
6
  import type { EIP1193Provider } from "viem";
7
7
 
8
- // Maximum number of events to retain to prevent memory growth
8
+ // Maximum number of events to retain to prevent memory growth.
9
+ // 100 events is sufficient to track a full bridge lifecycle (approve, burn, attestation, mint)
10
+ // while preventing unbounded memory growth in long-running sessions.
9
11
  const MAX_EVENTS = 100;
10
12
 
11
13
  // Chain ID to BridgeChain enum mapping
@@ -256,7 +258,8 @@ export function useBridge(): UseBridgeResult {
256
258
  kit.off("fetchAttestation", handleFetchAttestation);
257
259
  kit.off("mint", handleMint);
258
260
  } catch {
259
- // Ignore errors during cleanup (kit may not support off)
261
+ // Bridge Kit's off() method may not exist in all versions or may throw
262
+ // if listeners were already removed. Safe to ignore during cleanup.
260
263
  }
261
264
  };
262
265