@@ -353,7 +358,7 @@ const Details: React.FC
= ({
) : resolvedTxDesc === undefined ? (
<>Waiting for data...>
) : resolvedTxDesc === null ? (
- <>No decoded data>
+ <>Can't decode data>
) : (
= ({ txData, log, logDesc }) => (
-
-
-
- {log.logIndex}
-
-
-
-
-
Address
-
-
-
-
-
-
+const LogEntry: React.FC
= ({ txData, log, logDesc }) => {
+ const rawTopic0 = log.topics[0];
+ const topic0 = useTopic0(rawTopic0);
+
+ const topic0LogDesc = useMemo(() => {
+ if (!topic0) {
+ return topic0;
+ }
+ if (!topic0.signatures) {
+ return undefined;
+ }
+
+ const sigs = topic0.signatures;
+ for (const sig of sigs) {
+ const logFragment = Fragment.fromString(`event ${sig}`);
+ const intf = new Interface([logFragment]);
+ try {
+ return intf.parseLog(log);
+ } catch (err) {
+ // Ignore on purpose; try to match other sigs
+ }
+ }
+ return undefined;
+ }, [topic0, log]);
+
+ const resolvedLogDesc = logDesc ?? topic0LogDesc;
+
+ return (
+
+
+
+ {log.logIndex}
+
+
+
-
-
- Parameters
-
- Decoded
- Raw
-
-
-
-
- {logDesc === undefined ? (
-
-
- Waiting for data...
-
-
- ) : logDesc === null ? (
-
- ) : (
- <>
-
+
+
+ Parameters
+
+ Decoded
+ Raw
+
+
+
+
+ {resolvedLogDesc === undefined ? (
- >
- )}
-
-
- {log.topics.map((t, i) => (
-
-
{i === 0 && "Topics"}
-
-
- {i}
-
-
{t}
+ ) : resolvedLogDesc === null ? (
+
+
+ Can't decode data
+
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+ {log.topics.map((t, i) => (
+
+
{i === 0 && "Topics"}
+
+
+ {i}
+
+ {t}
+
+
+ ))}
+
- ))}
-
-
-
-
+
+
+
+
-
-);
+ );
+};
export default React.memo(LogEntry);
diff --git a/src/url.ts b/src/url.ts
index 9b80e34..a229fd1 100644
--- a/src/url.ts
+++ b/src/url.ts
@@ -5,6 +5,9 @@ export const fourBytesURL = (
fourBytes: string
): string => `${assetsURLPrefix}/signatures/${fourBytes}`;
+export const topic0URL = (assetsURLPrefix: string, topic0: string): string =>
+ `${assetsURLPrefix}/topic0/${topic0}`;
+
export const tokenLogoURL = (
assetsURLPrefix: string,
address: string
@@ -27,13 +30,13 @@ export enum SourcifySource {
const sourcifyIPNS =
"k51qzi5uqu5dll0ocge71eudqnrgnogmbr37gsgl12uubsinphjoknl6bbi41p";
-const ipfsGatewayPrefix = `http://localhost:8080/ipns/${sourcifyIPNS}`;
+const defaultIpfsGatewayPrefix = `https://ipfs.io/ipns/${sourcifyIPNS}`;
const sourcifyHttpRepoPrefix = `https://repo.sourcify.dev`;
const snapshotPrefix = "http://localhost:3006";
const resolveSourcifySource = (source: SourcifySource) => {
if (source === SourcifySource.IPFS_IPNS) {
- return ipfsGatewayPrefix;
+ return defaultIpfsGatewayPrefix;
}
if (source === SourcifySource.CENTRAL_SERVER) {
return sourcifyHttpRepoPrefix;
diff --git a/src/useTopic0.ts b/src/useTopic0.ts
new file mode 100644
index 0000000..adcef1e
--- /dev/null
+++ b/src/useTopic0.ts
@@ -0,0 +1,77 @@
+import { useState, useEffect, useContext } from "react";
+import { RuntimeContext } from "./useRuntime";
+import { topic0URL } from "./url";
+
+export type Topic0Entry = {
+ signatures: string[] | undefined;
+};
+
+const fullCache = new Map();
+
+/**
+ * Extract topic0 DB info
+ *
+ * @param rawTopic0 an hex string containing the keccak256 of event signature
+ */
+export const useTopic0 = (
+ rawTopic0: string
+): Topic0Entry | null | undefined => {
+ if (rawTopic0.length !== 66 || !rawTopic0.startsWith("0x")) {
+ throw new Error(
+ `rawTopic0 must contain a 32 bytes hex event signature starting with 0x; received value: "${rawTopic0}"`
+ );
+ }
+
+ const runtime = useContext(RuntimeContext);
+ const assetsURLPrefix = runtime.config?.assetsURLPrefix;
+
+ const topic0 = rawTopic0.slice(2);
+ const [entry, setEntry] = useState(
+ fullCache.get(topic0)
+ );
+ useEffect(() => {
+ if (assetsURLPrefix === undefined) {
+ return;
+ }
+
+ const signatureURL = topic0URL(assetsURLPrefix, topic0);
+ fetch(signatureURL)
+ .then(async (res) => {
+ if (!res.ok) {
+ console.error(`Signature does not exist in topic0 DB: ${topic0}`);
+ fullCache.set(topic0, null);
+ setEntry(null);
+ return;
+ }
+
+ // Get only the first occurrence, for now ignore alternative param names
+ const sig = await res.text();
+ const sigs = sig.split(";");
+ const entry: Topic0Entry = {
+ signatures: sigs,
+ };
+ setEntry(entry);
+ fullCache.set(topic0, entry);
+ })
+ .catch((err) => {
+ console.error(`Couldn't fetch signature URL ${signatureURL}`, err);
+ setEntry(null);
+ fullCache.set(topic0, null);
+ });
+ }, [topic0, assetsURLPrefix]);
+
+ if (assetsURLPrefix === undefined) {
+ return undefined;
+ }
+
+ // Try to resolve topic0 name
+ if (entry === null || entry === undefined) {
+ return entry;
+ }
+
+ // Simulates LRU
+ // TODO: implement LRU purging
+ fullCache.delete(topic0);
+ fullCache.set(topic0, entry);
+ return entry;
+};
diff --git a/topic0 b/topic0
new file mode 160000
index 0000000..52559d5
--- /dev/null
+++ b/topic0
@@ -0,0 +1 @@
+Subproject commit 52559d5690d491f8191a2d3fdb3c037516adc68f
diff --git a/trustwallet b/trustwallet
index d612796..e439c36 160000
--- a/trustwallet
+++ b/trustwallet
@@ -1 +1 @@
-Subproject commit d612796060acaa8a621b1dd25c1a41a24452953e
+Subproject commit e439c36937deb321ad01c23ac23941e8a491efe9