Skip to content

Commit e78a9d6

Browse files
committed
Auto select RPC
1 parent 25c93d3 commit e78a9d6

File tree

1 file changed

+77
-48
lines changed

1 file changed

+77
-48
lines changed

src/App.js

Lines changed: 77 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)