diff --git a/src/components/MethodName.tsx b/src/components/MethodName.tsx index 55ff909..446265b 100644 --- a/src/components/MethodName.tsx +++ b/src/components/MethodName.tsx @@ -1,58 +1,17 @@ -import React, { useState, useEffect, useContext } from "react"; -import { fourBytesURL } from "../url"; -import { RuntimeContext } from "../useRuntime"; +import React from "react"; +import { use4Bytes } from "../use4Bytes"; type MethodNameProps = { data: string; }; const MethodName: React.FC = ({ data }) => { - const runtime = useContext(RuntimeContext); - - const [name, setName] = useState(); - useEffect(() => { - if (data === "0x") { - setName("Transfer"); - return; - } - - let _name = data.slice(0, 10); - - // Try to resolve 4bytes name - const fourBytes = _name.slice(2); - const { config } = runtime; - if (!config) { - setName(_name); - return; - } - - const signatureURL = fourBytesURL(config.assetsURLPrefix ?? "", fourBytes); - fetch(signatureURL) - .then(async (res) => { - if (!res.ok) { - console.error(`Signature does not exist in 4bytes DB: ${fourBytes}`); - return; - } - - const sig = await res.text(); - const cut = sig.indexOf("("); - let method = sig.slice(0, cut); - method = method.charAt(0).toUpperCase() + method.slice(1); - setName(method); - return; - }) - .catch((err) => { - console.error(`Couldn't fetch signature URL ${signatureURL}`, err); - }); - - // Use the default 4 bytes as name - setName(_name); - }, [runtime, data]); + const methodName = use4Bytes(data); return (
-

- {name} +

+ {methodName}

); diff --git a/src/use4Bytes.ts b/src/use4Bytes.ts new file mode 100644 index 0000000..11f29d2 --- /dev/null +++ b/src/use4Bytes.ts @@ -0,0 +1,72 @@ +import { useState, useEffect, useContext } from "react"; +import { RuntimeContext } from "./useRuntime"; +import { fourBytesURL } from "./url"; + +const cache = new Map(); + +export const use4Bytes = (data: string) => { + const runtime = useContext(RuntimeContext); + const assetsURLPrefix = runtime.config?.assetsURLPrefix; + + let rawFourBytes = data.slice(0, 10); + + const [name, setName] = useState(); + const [fourBytes, setFourBytes] = useState(); + useEffect(() => { + if (assetsURLPrefix === undefined || fourBytes === undefined) { + return; + } + + const signatureURL = fourBytesURL(assetsURLPrefix, fourBytes); + fetch(signatureURL) + .then(async (res) => { + if (!res.ok) { + console.error(`Signature does not exist in 4bytes DB: ${fourBytes}`); + + // Use the default 4 bytes as name + setName(rawFourBytes); + cache.set(fourBytes, null); + return; + } + + const sig = await res.text(); + const cut = sig.indexOf("("); + let method = sig.slice(0, cut); + method = method.charAt(0).toUpperCase() + method.slice(1); + setName(method); + cache.set(fourBytes, method); + return; + }) + .catch((err) => { + console.error(`Couldn't fetch signature URL ${signatureURL}`, err); + + // Use the default 4 bytes as name + setName(rawFourBytes); + }); + }, [rawFourBytes, assetsURLPrefix, fourBytes]); + + if (data === "0x") { + return "Transfer"; + } + if (assetsURLPrefix === undefined) { + return rawFourBytes; + } + + // Try to resolve 4bytes name + const entry = cache.get(rawFourBytes.slice(2)); + if (entry === null) { + return rawFourBytes; + } + if (entry !== undefined) { + // Simulates LRU + cache.delete(entry); + cache.set(rawFourBytes.slice(2), entry); + return entry; + } + if (name === undefined && fourBytes === undefined) { + setFourBytes(rawFourBytes.slice(2)); + return ""; + } + + return name; +};