From 4096ebf40df3959f17e0e9a587b2d2c7c906faf6 Mon Sep 17 00:00:00 2001
From: mubarakone <52806204+mubarakone@users.noreply.github.com>
Date: Fri, 18 Jul 2025 19:14:01 -0700
Subject: [PATCH 1/4] Update index.js
- issue 1674 fix
---
components/RPCList/index.js | 141 +++++++++++++++++++++++++++++++++++-
1 file changed, 139 insertions(+), 2 deletions(-)
diff --git a/components/RPCList/index.js b/components/RPCList/index.js
index 20f9455b61..f12f49ef23 100644
--- a/components/RPCList/index.js
+++ b/components/RPCList/index.js
@@ -11,13 +11,97 @@ import { Tooltip } from "../../components/Tooltip";
import useAccount from "../../hooks/useAccount";
import { Popover, PopoverDisclosure, usePopoverStore } from "@ariakit/react/popover";
+// Test functions for trace and archive support
+const testTraceSupport = async (rpcUrl) => {
+ const payload = {
+ jsonrpc: "2.0",
+ method: "debug_traceTransaction",
+ params: [
+ "0x5a5efc6dd80fd85b291d0c2f79a1c88f2cb36aa9e5bd1951972e8b4cf5d9b17b"
+ ],
+ id: 1,
+ };
+
+ try {
+ const response = await fetch(rpcUrl, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+
+ const data = await response.json();
+ return data.result ? "supported" : "not-supported";
+ } catch (error) {
+ return "error";
+ }
+};
+
+const testArchiveSupport = async (rpcUrl) => {
+ const payload = {
+ jsonrpc: "2.0",
+ method: "eth_getBalance",
+ params: [
+ "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
+ "0x0"
+ ],
+ id: 1,
+ };
+
+ try {
+ const response = await fetch(rpcUrl, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+
+ const data = await response.json();
+ return data.result ? "supported" : "not-supported";
+ } catch (error) {
+ return "error";
+ }
+};
+
export default function RPCList({ chain, lang }) {
const [sortChains, setSorting] = useState(true);
+ const [supportCache, setSupportCache] = useState({});
const urlToData = chain.rpc.reduce((all, c) => ({ ...all, [c.url]: c }), {});
const chains = useRPCData(chain.rpc);
+ // Test trace and archive support for each RPC
+ useEffect(() => {
+ const testSupport = async () => {
+ const newCache = { ...supportCache };
+
+ for (const chain of chains || []) {
+ if (chain.data?.url && !supportCache[chain.data.url]) {
+ newCache[chain.data.url] = {
+ trace: "testing",
+ archive: "testing"
+ };
+
+ // Test both features in parallel
+ const [traceResult, archiveResult] = await Promise.all([
+ testTraceSupport(chain.data.url),
+ testArchiveSupport(chain.data.url)
+ ]);
+
+ newCache[chain.data.url] = {
+ trace: traceResult,
+ archive: archiveResult
+ };
+ }
+ }
+
+ setSupportCache(newCache);
+ };
+
+ if (chains?.length > 0) {
+ testSupport();
+ }
+ }, [chains]);
+
const data = useMemo(() => {
const sortedData = sortChains
? chains?.sort((a, b) => {
@@ -70,12 +154,23 @@ export default function RPCList({ chain, lang }) {
const lat = latency ? (latency / 1000).toFixed(3) + "s" : null;
+ // Add trace and archive support data
+ const support = supportCache[url] || { trace: "unknown", archive: "unknown" };
+
return {
...rest,
- data: { ...data, height, latency: lat, trust, disableConnect },
+ data: {
+ ...data,
+ height,
+ latency: lat,
+ trust,
+ disableConnect,
+ traceSupport: support.trace,
+ archiveSupport: support.archive
+ },
};
});
- }, [chains]);
+ }, [chains, supportCache]);
const { rpcData, hasLlamaNodesRpc } = useLlamaNodesRpcData(chain.chainId, data);
@@ -113,6 +208,8 @@ export default function RPCList({ chain, lang }) {
@@ -211,6 +338,16 @@ const Row = ({ values, chain, privacy, lang, className }) => {
{isLoading ? : }
|
+
+
+ {isLoading ? : }
+
+ |
+
+
+ {isLoading ? : }
+
+ |
{isLoading ? (
From 7c60ca5dbc178550d89dd143ebe7c773b1928e8f Mon Sep 17 00:00:00 2001
From: mintdart <96025197+mintdart@users.noreply.github.com>
Date: Mon, 21 Jul 2025 19:12:02 +0900
Subject: [PATCH 2/4] refactor
---
components/RPCList/index.js | 75 ++++++++++++++-----------------------
1 file changed, 29 insertions(+), 46 deletions(-)
diff --git a/components/RPCList/index.js b/components/RPCList/index.js
index f12f49ef23..a0579a400e 100644
--- a/components/RPCList/index.js
+++ b/components/RPCList/index.js
@@ -10,6 +10,7 @@ import { renderProviderText } from "../../utils";
import { Tooltip } from "../../components/Tooltip";
import useAccount from "../../hooks/useAccount";
import { Popover, PopoverDisclosure, usePopoverStore } from "@ariakit/react/popover";
+import { useQuery } from "@tanstack/react-query";
// Test functions for trace and archive support
const testTraceSupport = async (rpcUrl) => {
@@ -63,45 +64,11 @@ const testArchiveSupport = async (rpcUrl) => {
export default function RPCList({ chain, lang }) {
const [sortChains, setSorting] = useState(true);
- const [supportCache, setSupportCache] = useState({});
const urlToData = chain.rpc.reduce((all, c) => ({ ...all, [c.url]: c }), {});
const chains = useRPCData(chain.rpc);
- // Test trace and archive support for each RPC
- useEffect(() => {
- const testSupport = async () => {
- const newCache = { ...supportCache };
-
- for (const chain of chains || []) {
- if (chain.data?.url && !supportCache[chain.data.url]) {
- newCache[chain.data.url] = {
- trace: "testing",
- archive: "testing"
- };
-
- // Test both features in parallel
- const [traceResult, archiveResult] = await Promise.all([
- testTraceSupport(chain.data.url),
- testArchiveSupport(chain.data.url)
- ]);
-
- newCache[chain.data.url] = {
- trace: traceResult,
- archive: archiveResult
- };
- }
- }
-
- setSupportCache(newCache);
- };
-
- if (chains?.length > 0) {
- testSupport();
- }
- }, [chains]);
-
const data = useMemo(() => {
const sortedData = sortChains
? chains?.sort((a, b) => {
@@ -154,9 +121,6 @@ export default function RPCList({ chain, lang }) {
const lat = latency ? (latency / 1000).toFixed(3) + "s" : null;
- // Add trace and archive support data
- const support = supportCache[url] || { trace: "unknown", archive: "unknown" };
-
return {
...rest,
data: {
@@ -164,13 +128,11 @@ export default function RPCList({ chain, lang }) {
height,
latency: lat,
trust,
- disableConnect,
- traceSupport: support.trace,
- archiveSupport: support.archive
+ disableConnect
},
};
});
- }, [chains, supportCache]);
+ }, [chains]);
const { rpcData, hasLlamaNodesRpc } = useLlamaNodesRpcData(chain.chainId, data);
@@ -296,7 +258,28 @@ const Row = ({ values, chain, privacy, lang, className }) => {
const { mutate: addToNetwork } = useAddToNetwork();
- const getTooltipContent = (support, type) => {
+
+ const traceSupport = useQuery({
+ queryKey: ["support", data?.url],
+ queryFn: () => testTraceSupport(data?.url),
+ staleTime: 1000 * 60 * 60,
+ refetchInterval: 1000 * 60 * 60,
+ refetchOnMount: false,
+ refetchOnWindowFocus: false,
+ enabled: !!data?.url,
+ })
+
+ const archiveSupport = useQuery({
+ queryKey: ["support", data?.url],
+ queryFn: () => testArchiveSupport(data?.url),
+ staleTime: 1000 * 60 * 60,
+ refetchInterval: 1000 * 60 * 60,
+ refetchOnMount: false,
+ refetchOnWindowFocus: false,
+ enabled: !!data?.url,
+ })
+
+ const getSupportTooltipContent = (support, type) => {
switch (support) {
case "supported":
return `${type} methods are supported`;
@@ -339,13 +322,13 @@ const Row = ({ values, chain, privacy, lang, className }) => {
|
-
- {isLoading ? : }
+
+ {isLoading ? : }
|
-
- {isLoading ? : }
+
+ {isLoading ? : }
|
From 7f8e437aabbb5773d44fd6b19659eaa5f16fb571 Mon Sep 17 00:00:00 2001
From: mubarakone <52806204+mubarakone@users.noreply.github.com>
Date: Sun, 24 Aug 2025 19:48:02 -0700
Subject: [PATCH 3/4] fix tx not found error
- tx not found means debug_traceTransaction method is found, which is good
---
components/RPCList/index.js | 40 +++++++++++++++++++------------------
1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/components/RPCList/index.js b/components/RPCList/index.js
index a0579a400e..ded5a37fe6 100644
--- a/components/RPCList/index.js
+++ b/components/RPCList/index.js
@@ -13,50 +13,52 @@ import { Popover, PopoverDisclosure, usePopoverStore } from "@ariakit/react/popo
import { useQuery } from "@tanstack/react-query";
// Test functions for trace and archive support
+
const testTraceSupport = async (rpcUrl) => {
- const payload = {
+ // Test trace support (with fake tx hash)
+ const tracePayload = {
jsonrpc: "2.0",
method: "debug_traceTransaction",
- params: [
- "0x5a5efc6dd80fd85b291d0c2f79a1c88f2cb36aa9e5bd1951972e8b4cf5d9b17b"
- ],
+ params: ["0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", {}],
id: 1,
};
try {
- const response = await fetch(rpcUrl, {
+
+ const traceRes = await fetch(rpcUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
- body: JSON.stringify(payload),
- });
+ body: JSON.stringify(tracePayload),
+ }).then(r => r.json());
+
+ const traceSupported = !traceRes.error?.message.includes("method" || "API");
+ return traceSupported ? "supported" : "not-supported";
- const data = await response.json();
- return data.result ? "supported" : "not-supported";
} catch (error) {
return "error";
}
};
const testArchiveSupport = async (rpcUrl) => {
- const payload = {
+ // Test archive support
+ const archivePayload = {
jsonrpc: "2.0",
method: "eth_getBalance",
- params: [
- "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
- "0x0"
- ],
+ params: ["0x0000000000000000000000000000000000000000", "0x1"],
id: 1,
};
try {
- const response = await fetch(rpcUrl, {
+
+ const archiveRes = await fetch(rpcUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
- body: JSON.stringify(payload),
- });
+ body: JSON.stringify(archivePayload),
+ }).then(r => r.json());
- const data = await response.json();
- return data.result ? "supported" : "not-supported";
+ const archiveSupported = !!archiveRes.result;
+ return archiveSupported ? "supported" : "not-supported";
+
} catch (error) {
return "error";
}
From 39003e377998c3b965fd376c3c08ee2307cca560 Mon Sep 17 00:00:00 2001
From: caranell
Date: Wed, 17 Sep 2025 00:23:33 +0300
Subject: [PATCH 4/4] Fixes to archive/trace support
---
components/RPCList/index.js | 121 +++++++++++++++++++++++++-----------
utils/index.js | 5 ++
2 files changed, 88 insertions(+), 38 deletions(-)
diff --git a/components/RPCList/index.js b/components/RPCList/index.js
index ded5a37fe6..4c8fc98ea5 100644
--- a/components/RPCList/index.js
+++ b/components/RPCList/index.js
@@ -6,36 +6,55 @@ import useAddToNetwork from "../../hooks/useAddToNetwork";
import { useLlamaNodesRpcData } from "../../hooks/useLlamaNodesRpcData";
import { FATHOM_DROPDOWN_EVENTS_ID } from "../../hooks/useAnalytics";
import { useRpcStore } from "../../stores";
-import { renderProviderText } from "../../utils";
+import { renderProviderText, containsAny } from "../../utils";
import { Tooltip } from "../../components/Tooltip";
import useAccount from "../../hooks/useAccount";
import { Popover, PopoverDisclosure, usePopoverStore } from "@ariakit/react/popover";
import { useQuery } from "@tanstack/react-query";
-// Test functions for trace and archive support
+// Functions to test trace and archive support
+
+const SUPPORT_STATUS = {
+ supported: "supported",
+ not_supported: "not-supported",
+ error: "error",
+ testing: "testing",
+ unknown: "unknown",
+};
const testTraceSupport = async (rpcUrl) => {
// Test trace support (with fake tx hash)
+
+ const fakeTxHash = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
const tracePayload = {
jsonrpc: "2.0",
method: "debug_traceTransaction",
- params: ["0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", {}],
+ params: [fakeTxHash, {}],
id: 1,
};
try {
-
const traceRes = await fetch(rpcUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(tracePayload),
- }).then(r => r.json());
+ signal: AbortSignal.timeout(7000),
+ }).then((r) => r.json());
+
+ const errorMessage = traceRes?.error?.message || traceRes?.message;
+
+ // some RPCs might allow the trace with restrictions, better marks those as 'failed to test' instead of 'not supported'
+ if (containsAny(errorMessage, ["auth", "rate", "limit", "api", "allowed", "whitelist", "origin"])) {
+ throw new Error(errorMessage);
+ }
- const traceSupported = !traceRes.error?.message.includes("method" || "API");
- return traceSupported ? "supported" : "not-supported";
+ const traceSupported =
+ containsAny(errorMessage, ["transaction not found", `transaction ${fakeTxHash} not found`]) ||
+ traceRes?.result === null;
+ return traceSupported ? SUPPORT_STATUS.supported : SUPPORT_STATUS.not_supported;
} catch (error) {
- return "error";
+ return SUPPORT_STATUS.error;
}
};
@@ -49,18 +68,17 @@ const testArchiveSupport = async (rpcUrl) => {
};
try {
-
const archiveRes = await fetch(rpcUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(archivePayload),
- }).then(r => r.json());
+ signal: AbortSignal.timeout(7000),
+ }).then((r) => r.json());
- const archiveSupported = !!archiveRes.result;
- return archiveSupported ? "supported" : "not-supported";
-
+ const archiveSupported = Boolean(archiveRes.result);
+ return archiveSupported ? SUPPORT_STATUS.supported : SUPPORT_STATUS.not_supported;
} catch (error) {
- return "error";
+ return SUPPORT_STATUS.error;
}
};
@@ -125,12 +143,12 @@ export default function RPCList({ chain, lang }) {
return {
...rest,
- data: {
- ...data,
- height,
- latency: lat,
- trust,
- disableConnect
+ data: {
+ ...data,
+ height,
+ latency: lat,
+ trust,
+ disableConnect,
},
};
});
@@ -226,14 +244,16 @@ function PrivacyIcon({ tracking, isOpenSource = false }) {
function SupportIcon({ support }) {
switch (support) {
- case "supported":
+ case SUPPORT_STATUS.supported:
return ;
- case "not-supported":
+ case SUPPORT_STATUS.not_supported:
return ;
- case "error":
+ case SUPPORT_STATUS.error:
return ;
- case "testing":
- return ;
+ case SUPPORT_STATUS.testing:
+ return (
+
+ );
default:
return ;
}
@@ -260,37 +280,38 @@ const Row = ({ values, chain, privacy, lang, className }) => {
const { mutate: addToNetwork } = useAddToNetwork();
-
const traceSupport = useQuery({
- queryKey: ["support", data?.url],
+ queryKey: ["trace-support", data?.url],
queryFn: () => testTraceSupport(data?.url),
staleTime: 1000 * 60 * 60,
refetchInterval: 1000 * 60 * 60,
refetchOnMount: false,
refetchOnWindowFocus: false,
enabled: !!data?.url,
- })
+ });
const archiveSupport = useQuery({
- queryKey: ["support", data?.url],
+ queryKey: ["archive-support", data?.url],
queryFn: () => testArchiveSupport(data?.url),
staleTime: 1000 * 60 * 60,
refetchInterval: 1000 * 60 * 60,
refetchOnMount: false,
refetchOnWindowFocus: false,
enabled: !!data?.url,
- })
+ });
const getSupportTooltipContent = (support, type) => {
switch (support) {
- case "supported":
+ case SUPPORT_STATUS.supported:
return `${type} methods are supported`;
- case "not-supported":
+ case SUPPORT_STATUS.not_supported:
return `${type} methods are not supported`;
- case "error":
+ case SUPPORT_STATUS.error:
return `Error testing ${type} support`;
- case "testing":
+ case SUPPORT_STATUS.testing:
return `Testing ${type} support...`;
+ case SUPPORT_STATUS.unknown:
+ return `${type} support unknown`;
default:
return `${type} support unknown`;
}
@@ -324,13 +345,37 @@ const Row = ({ values, chain, privacy, lang, className }) => {
|
-
- {isLoading ? : }
+
+ {isLoading ? (
+
+ ) : (
+
+ )}
|
-
- {isLoading ? : }
+
+ {isLoading ? (
+
+ ) : (
+
+ )}
|
diff --git a/utils/index.js b/utils/index.js
index 4e2213fd39..77e7827bdd 100644
--- a/utils/index.js
+++ b/utils/index.js
@@ -94,3 +94,8 @@ export const notTranslation =
return en[ns][key];
}
};
+
+export const containsAny = (str, substrings) => {
+ if (!str) return false;
+ return substrings.some((substring) => str.toLowerCase().includes(substring.toLowerCase()));
+};
|