66 */
77
88import { QueryClient , QueryClientProvider } from '@tanstack/react-query' ;
9- import type { Chain } from 'viem' ;
10- import { createConfig , http , WagmiProvider } from 'wagmi' ;
9+ import { createConfig , http } from '@wagmi/core' ;
10+ import { mainnet } from 'viem/chains' ;
11+ import { WagmiProvider } from 'wagmi' ;
1112import React , { useEffect , useMemo , useState } from 'react' ;
1213
1314import { WagmiProviderInitializedContext } from '@openzeppelin/ui-builder-adapter-evm-core' ;
1415import type { EcosystemReactUiProviderProps } from '@openzeppelin/ui-types' ;
16+ import { logger } from '@openzeppelin/ui-utils' ;
1517
16- import { polkadotChains } from './chains ' ;
17- import { initializePolkadotWallet } from './implementation ' ;
18+ import { polkadotUiKitManager , type PolkadotUiKitManagerState } from './polkadotUiKitManager ' ;
19+ import type { RainbowKitKitConfig , RainbowKitProviderProps } from './rainbowkit ' ;
1820
1921/**
2022 * Props for the PolkadotWalletUiRoot component.
2123 */
22- export interface PolkadotWalletUiRootProps extends EcosystemReactUiProviderProps {
23- /** Optional override for chains to configure (defaults to all Polkadot ecosystem chains) */
24- chains ?: readonly [ Chain , ...Chain [ ] ] ;
25- }
24+ export type PolkadotWalletUiRootProps = EcosystemReactUiProviderProps ;
2625
27- // Create a stable QueryClient for react-query
28- const queryClient = new QueryClient ( ) ;
26+ // Create a single QueryClient instance to be reused
27+ const stableQueryClient = new QueryClient ( ) ;
28+
29+ // Create a minimal, default WagmiConfig to use when no other config is ready.
30+ // This ensures WagmiProvider can always be mounted with a valid config object.
31+ const minimalDefaultWagmiConfig = createConfig ( {
32+ chains : [ mainnet ] , // At least one chain is required in wagmi v2.20+
33+ connectors : [ ] ,
34+ transports : {
35+ [ mainnet . id ] : http ( ) ,
36+ } ,
37+ } ) ;
2938
3039/**
3140 * Polkadot ecosystem wallet UI root component.
@@ -34,6 +43,9 @@ const queryClient = new QueryClient();
3443 * EVM-compatible networks. It wraps children with WagmiProvider and
3544 * QueryClientProvider configured for Polkadot Hub and parachain networks.
3645 *
46+ * When RainbowKit is configured, it wraps children with RainbowKitProvider
47+ * to enable the RainbowKit UI components.
48+ *
3749 * @example
3850 * ```tsx
3951 * import { PolkadotWalletUiRoot } from '@openzeppelin/ui-builder-adapter-polkadot';
@@ -47,57 +59,98 @@ const queryClient = new QueryClient();
4759 * }
4860 * ```
4961 *
50- * @example
51- * ```tsx
52- * // Using with specific chains only
53- * import { PolkadotWalletUiRoot, polkadotHub, moonbeam } from '@openzeppelin/ui-builder-adapter-polkadot';
54- *
55- * function App() {
56- * return (
57- * <PolkadotWalletUiRoot chains={[polkadotHub, moonbeam]}>
58- * <YourAppContent />
59- * </PolkadotWalletUiRoot>
60- * );
61- * }
62- * ```
63- *
6462 * @remarks
6563 * The component pre-configures all Polkadot ecosystem EVM networks by default:
6664 * - Hub networks: Polkadot Hub, Kusama Hub, Polkadot Hub TestNet
6765 * - Parachains: Moonbeam, Moonriver, Moonbase Alpha
68- *
69- * For production apps, you should integrate with RainbowKit or another
70- * wallet UI library. This component provides the base wagmi/react-query
71- * providers that those libraries require.
7266 */
73- export const PolkadotWalletUiRoot : React . FC < PolkadotWalletUiRootProps > = ( {
74- children,
75- chains = polkadotChains ,
76- } ) => {
77- const [ isProviderInitialized , setIsProviderInitialized ] = useState ( false ) ;
67+ export const PolkadotWalletUiRoot : React . FC < PolkadotWalletUiRootProps > = ( { children } ) => {
68+ const [ managerState , setManagerState ] = useState < PolkadotUiKitManagerState > (
69+ polkadotUiKitManager . getState ( )
70+ ) ;
71+
72+ useEffect ( ( ) => {
73+ const handleStateChange = ( ) => {
74+ setManagerState ( polkadotUiKitManager . getState ( ) ) ;
75+ } ;
76+ const unsubscribe = polkadotUiKitManager . subscribe ( handleStateChange ) ;
77+ handleStateChange ( ) ;
78+ return unsubscribe ;
79+ } , [ ] ) ;
7880
79- // Create wagmi config with Polkadot ecosystem chains
80- const wagmiConfig = useMemo ( ( ) => {
81- const transports = Object . fromEntries ( chains . map ( ( chain ) => [ chain . id , http ( ) ] ) ) ;
81+ const queryClient = useMemo ( ( ) => stableQueryClient , [ ] ) ;
8282
83- return createConfig ( {
84- chains,
85- transports,
86- } ) ;
87- } , [ chains ] ) ;
83+ const {
84+ wagmiConfig,
85+ kitProviderComponent,
86+ isKitAssetsLoaded,
87+ currentFullUiKitConfig,
88+ isInitializing,
89+ error,
90+ } = managerState ;
8891
89- // Initialize the wallet implementation singleton with the config
90- useEffect ( ( ) => {
91- initializePolkadotWallet ( wagmiConfig ) ;
92- // Mark provider as initialized after the wallet implementation is set up
93- setIsProviderInitialized ( true ) ;
94- } , [ wagmiConfig ] ) ;
92+ const configForWagmiProvider = wagmiConfig || minimalDefaultWagmiConfig ;
93+ const isWagmiContextEffectivelyReady = ! ! wagmiConfig && ! error ;
94+
95+ let finalChildren = children ;
96+
97+ // When RainbowKit is configured, wrap children with RainbowKitProvider
98+ if (
99+ isWagmiContextEffectivelyReady &&
100+ currentFullUiKitConfig ?. kitName === 'rainbowkit' &&
101+ kitProviderComponent &&
102+ isKitAssetsLoaded
103+ ) {
104+ const DynKitProvider = kitProviderComponent ;
105+ const kitConfig : RainbowKitKitConfig = currentFullUiKitConfig . kitConfig || { } ;
106+ const providerProps : RainbowKitProviderProps = kitConfig . providerProps || { } ;
107+
108+ logger . info (
109+ 'PolkadotWalletUiRoot' ,
110+ 'Wrapping children with dynamically loaded KitProvider (RainbowKit).'
111+ ) ;
112+ finalChildren = < DynKitProvider { ...providerProps } > { children } </ DynKitProvider > ;
113+ } else if ( currentFullUiKitConfig ?. kitName === 'rainbowkit' && ! isWagmiContextEffectivelyReady ) {
114+ logger . info (
115+ 'PolkadotWalletUiRoot' ,
116+ 'RainbowKit configured, but context or assets not ready. Button may show its loading/error state.'
117+ ) ;
118+ }
95119
96120 return (
97- < WagmiProvider config = { wagmiConfig } >
121+ < WagmiProvider config = { configForWagmiProvider } >
98122 < QueryClientProvider client = { queryClient } >
99- < WagmiProviderInitializedContext . Provider value = { isProviderInitialized } >
100- { children }
123+ < WagmiProviderInitializedContext . Provider value = { isWagmiContextEffectivelyReady } >
124+ { finalChildren }
125+ { isInitializing && (
126+ < div
127+ style = { {
128+ position : 'fixed' ,
129+ top : '10px' ,
130+ right : '10px' ,
131+ background : 'rgba(0,0,0,0.1)' ,
132+ padding : '5px' ,
133+ borderRadius : '3px' ,
134+ fontSize : '0.8em' ,
135+ } }
136+ >
137+ Updating network...
138+ </ div >
139+ ) }
140+ { error && ! wagmiConfig && (
141+ < div
142+ style = { {
143+ position : 'fixed' ,
144+ bottom : '10px' ,
145+ left : '10px' ,
146+ background : 'red' ,
147+ color : 'white' ,
148+ padding : '10px' ,
149+ } }
150+ >
151+ Error initializing wallet provider: { error . message }
152+ </ div >
153+ ) }
101154 </ WagmiProviderInitializedContext . Provider >
102155 </ QueryClientProvider >
103156 </ WagmiProvider >
0 commit comments