@@ -47,7 +47,7 @@ function App() {
4747 const [ chainArray , setChainArray ] = useState ( ) ; // chainId.network/chains.json result
4848 const [ connected , setConnected ] = useState ( "not connected" ) ;
4949 const [ selectedRpcs , setSelectedRpcs ] = useState ( { } ) ; // chainId -> rpc URL mapping
50-
50+ const [ currentRpc , setCurrentRpc ] = useState ( null ) ; // Currently active RPC URL
5151
5252 // On Mount
5353 useEffect ( ( ) => {
@@ -59,7 +59,7 @@ function App() {
5959 fetch ( "https://chainid.network/chains.json" )
6060 . then ( ( res ) => res . json ( ) )
6161 . then ( ( arr ) => {
62- const ethereumChainIds = [ 1 , 11155111 , 1337 ] ;
62+ const ethereumChainIds = [ 1 , 11155111 , 560048 ] ;
6363 // move ethereum networks to the top
6464 const sortedArr = arr . sort ( ( a , b ) => {
6565 if ( ethereumChainIds . includes ( a . chainId ) && ethereumChainIds . includes ( b . chainId ) ) {
@@ -111,50 +111,79 @@ function App() {
111111 // Find a working RPC URL from the chain data
112112 let provider ;
113113 let rpcUrl = null ;
114-
115- // Use selected RPC if available, otherwise find first public RPC
114+
115+ // Use selected RPC if available, otherwise try RPCs until one works
116116 if ( selectedRpcs [ chainlistObject . chainId ] ) {
117117 rpcUrl = selectedRpcs [ chainlistObject . chainId ] ;
118+
119+ if ( rpcUrl ) {
120+ try {
121+ provider = new ethers . providers . JsonRpcProvider ( rpcUrl , {
122+ name : chainlistObject . name ,
123+ chainId : chainlistObject . chainId ,
124+ ensAddress : chainlistObject ?. ens ?. registry ,
125+ } ) ;
126+ } catch ( err ) {
127+ console . error ( err ) ;
128+ }
129+ }
130+
131+ setProvider ( provider ) ;
132+ if ( provider ) {
133+ const timeoutPromise = new Promise ( ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( "Timeout" ) ) , 3000 ) ) ;
134+
135+ Promise . race ( [ provider . getNetwork ( ) , timeoutPromise ] )
136+ . then ( ( ) => {
137+ setConnected ( "connected" ) ;
138+ setCurrentRpc ( rpcUrl ) ;
139+ } )
140+ . catch ( ( ) => {
141+ setErrorMessage ( "Can't connect to the network at " + rpcUrl ) ;
142+ setConnected ( "not connected" ) ;
143+ setCurrentRpc ( null ) ;
144+ } ) ;
145+ }
118146 } else {
119- // Filter out Infura RPCs and find a public RPC
120- const publicRpcs = chainlistObject . rpc ?. filter ( rpc =>
121- ! rpc . includes ( 'infura.io' ) &&
122- ! rpc . includes ( '${' ) &&
123- rpc . startsWith ( 'http' )
124- ) || [ ] ;
125-
147+ // Auto-select: race all RPCs and use the fastest one
148+ const publicRpcs =
149+ chainlistObject . rpc ?. filter (
150+ ( rpc ) => ! rpc . includes ( "infura.io" ) && ! rpc . includes ( "${" ) && rpc . startsWith ( "http" )
151+ ) || [ ] ;
152+
126153 if ( publicRpcs . length > 0 ) {
127- rpcUrl = publicRpcs [ 0 ] ;
128- } else if ( chainlistObject . rpc && chainlistObject . rpc . length > 0 ) {
129- // Fallback to first RPC if no public RPCs found
130- rpcUrl = chainlistObject . rpc [ 0 ] ;
131- }
132- }
133-
134- if ( rpcUrl ) {
135- try {
136- provider = new ethers . providers . JsonRpcProvider ( rpcUrl , {
137- name : chainlistObject . name ,
138- chainId : chainlistObject . chainId ,
139- ensAddress : chainlistObject ?. ens ?. registry ,
154+ // Create promises for all RPCs with timeout
155+ const rpcPromises = publicRpcs . map ( async ( rpcUrl ) => {
156+ const testProvider = new ethers . providers . JsonRpcProvider ( rpcUrl , {
157+ name : chainlistObject . name ,
158+ chainId : chainlistObject . chainId ,
159+ ensAddress : chainlistObject ?. ens ?. registry ,
160+ } ) ;
161+
162+ const timeoutPromise = new Promise ( ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( "Timeout" ) ) , 3000 ) ) ;
163+
164+ await Promise . race ( [ testProvider . getNetwork ( ) , timeoutPromise ] ) ;
165+ return { provider : testProvider , url : rpcUrl } ;
140166 } ) ;
141- } catch ( err ) {
142- console . error ( err ) ;
143- }
144- }
145- setProvider ( provider ) ;
146- provider
147- . getNetwork ( )
148- . then ( ( data ) => {
149- setConnected ( "connected" ) ;
150- } )
151- . catch ( ( err ) => {
152- rpcUrl
153- ? setErrorMessage ( "Can't connect to the network at " + rpcUrl )
154- : setErrorMessage ( "Can't connect to the network: No RPC found" ) ;
155167
168+ // Race all RPCs and use the first one that succeeds
169+ Promise . any ( rpcPromises )
170+ . then ( ( { provider, url } ) => {
171+ setProvider ( provider ) ;
172+ setConnected ( "connected" ) ;
173+ setCurrentRpc ( url ) ;
174+ console . log ( `Successfully connected to fastest RPC: ${ url } ` ) ;
175+ } )
176+ . catch ( ( ) => {
177+ setErrorMessage ( "Can't connect to any available RPC" ) ;
178+ setConnected ( "not connected" ) ;
179+ setCurrentRpc ( null ) ;
180+ } ) ;
181+ } else {
182+ setErrorMessage ( "No public RPCs available" ) ;
156183 setConnected ( "not connected" ) ;
157- } ) ;
184+ setCurrentRpc ( null ) ;
185+ }
186+ }
158187 } , [ chainIndex , chainArray , selectedRpcs ] ) ;
159188
160189 const chainIdToIndex = ( id ) => {
@@ -163,9 +192,9 @@ function App() {
163192 } ;
164193
165194 const handleRpcChange = ( chainId , rpcUrl ) => {
166- setSelectedRpcs ( prev => ( {
195+ setSelectedRpcs ( ( prev ) => ( {
167196 ...prev ,
168- [ chainId ] : rpcUrl
197+ [ chainId ] : rpcUrl ,
169198 } ) ) ;
170199 } ;
171200
@@ -316,27 +345,27 @@ function App() {
316345 />
317346 { chainArray [ chainIndex ] ?. rpc ?. length > 0 && (
318347 < div className = "mt-3" >
319- < label className = "block text-sm font-medium text-gray-700 mb-2" >
320- Select RPC Endpoint:
321- </ label >
348+ < label className = "block text-sm font-medium text-gray-700 mb-2" > Select RPC Endpoint:</ label >
322349 < select
323350 className = "block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-ceruleanBlue-100 focus:border-ceruleanBlue-100 text-sm"
324- value = { selectedRpcs [ chainArray [ chainIndex ] . chainId ] || '' }
351+ value = { selectedRpcs [ chainArray [ chainIndex ] . chainId ] || "" }
325352 onChange = { ( e ) => handleRpcChange ( chainArray [ chainIndex ] . chainId , e . target . value ) }
326353 >
327354 < option value = "" > Auto-select (default)</ option >
328355 { chainArray [ chainIndex ] . rpc
329- . filter ( rpc => ! rpc . includes ( '${' ) && rpc . startsWith ( ' http' ) )
356+ . filter ( ( rpc ) => ! rpc . includes ( "${" ) && rpc . startsWith ( " http" ) )
330357 . map ( ( rpc , i ) => (
331358 < option key = { i } value = { rpc } >
332- { rpc . length > 50 ? rpc . substring ( 0 , 50 ) + ' ...' : rpc }
359+ { rpc . length > 50 ? rpc . substring ( 0 , 50 ) + " ..." : rpc }
333360 </ option >
334361 ) ) }
335362 </ select >
336- { selectedRpcs [ chainArray [ chainIndex ] . chainId ] && (
363+ { selectedRpcs [ chainArray [ chainIndex ] . chainId ] ? (
337364 < div className = "text-xs text-gray-600 mt-1" >
338365 Using: { selectedRpcs [ chainArray [ chainIndex ] . chainId ] }
339366 </ div >
367+ ) : (
368+ currentRpc && < div className = "text-xs text-gray-600 mt-1 flex" > Auto-selected: { currentRpc } </ div >
340369 ) }
341370 </ div >
342371 ) }
0 commit comments