Merge branch 'feature/integrate-swr' into develop
This commit is contained in:
commit
f1d06b5025
15
package-lock.json
generated
15
package-lock.json
generated
@ -46,6 +46,7 @@
|
|||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-syntax-highlighter": "^15.4.5",
|
"react-syntax-highlighter": "^15.4.5",
|
||||||
"serve": "^13.0.2",
|
"serve": "^13.0.2",
|
||||||
|
"swr": "^1.1.1",
|
||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"use-keyboard-shortcut": "^1.1.0",
|
"use-keyboard-shortcut": "^1.1.0",
|
||||||
"web-vitals": "^1.0.1"
|
"web-vitals": "^1.0.1"
|
||||||
@ -17205,6 +17206,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/swr": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/swr/-/swr-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-ZpUHyU3N3snj2QGFeE2Fd3BXl1CVS6YQIQGb1ttPAkTmvwZqDyV3GRMNPsaeAYCBM74tfn4XbKx28FVQR0mS7Q==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/symbol-tree": {
|
"node_modules/symbol-tree": {
|
||||||
"version": "3.2.4",
|
"version": "3.2.4",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
@ -31069,6 +31078,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"swr": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/swr/-/swr-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-ZpUHyU3N3snj2QGFeE2Fd3BXl1CVS6YQIQGb1ttPAkTmvwZqDyV3GRMNPsaeAYCBM74tfn4XbKx28FVQR0mS7Q==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"symbol-tree": {
|
"symbol-tree": {
|
||||||
"version": "3.2.4"
|
"version": "3.2.4"
|
||||||
},
|
},
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-syntax-highlighter": "^15.4.5",
|
"react-syntax-highlighter": "^15.4.5",
|
||||||
"serve": "^13.0.2",
|
"serve": "^13.0.2",
|
||||||
|
"swr": "^1.1.1",
|
||||||
"typescript": "^4.5.4",
|
"typescript": "^4.5.4",
|
||||||
"use-keyboard-shortcut": "^1.1.0",
|
"use-keyboard-shortcut": "^1.1.0",
|
||||||
"web-vitals": "^1.0.1"
|
"web-vitals": "^1.0.1"
|
||||||
|
@ -1,20 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes";
|
import { useMethodSelector } from "../use4Bytes";
|
||||||
|
|
||||||
type MethodNameProps = {
|
type MethodNameProps = {
|
||||||
data: string;
|
data: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MethodName: React.FC<MethodNameProps> = ({ data }) => {
|
const MethodName: React.FC<MethodNameProps> = ({ data }) => {
|
||||||
const rawFourBytes = rawInputTo4Bytes(data);
|
const [isSimpleTransfer, methodName, methodTitle] = useMethodSelector(data);
|
||||||
const fourBytesEntry = use4Bytes(rawFourBytes);
|
|
||||||
const methodName = fourBytesEntry?.name ?? rawFourBytes;
|
|
||||||
const isSimpleTransfer = rawFourBytes === "0x";
|
|
||||||
const methodTitle = isSimpleTransfer
|
|
||||||
? "ETH Transfer"
|
|
||||||
: methodName === rawFourBytes
|
|
||||||
? methodName
|
|
||||||
: `${methodName} [${rawFourBytes}]`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -37,7 +37,7 @@ import PercentagePosition from "../components/PercentagePosition";
|
|||||||
import DecodedParamsTable from "./decoder/DecodedParamsTable";
|
import DecodedParamsTable from "./decoder/DecodedParamsTable";
|
||||||
import InputDecoder from "./decoder/InputDecoder";
|
import InputDecoder from "./decoder/InputDecoder";
|
||||||
import {
|
import {
|
||||||
rawInputTo4Bytes,
|
extract4Bytes,
|
||||||
use4Bytes,
|
use4Bytes,
|
||||||
useTransactionDescription,
|
useTransactionDescription,
|
||||||
} from "../use4Bytes";
|
} from "../use4Bytes";
|
||||||
@ -74,7 +74,8 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
txData.confirmedData?.blockBaseFeePerGas !== undefined &&
|
txData.confirmedData?.blockBaseFeePerGas !== undefined &&
|
||||||
txData.confirmedData?.blockBaseFeePerGas !== null;
|
txData.confirmedData?.blockBaseFeePerGas !== null;
|
||||||
|
|
||||||
const fourBytes = txData.to !== null ? rawInputTo4Bytes(txData.data) : "0x";
|
const fourBytes =
|
||||||
|
txData.to !== null ? extract4Bytes(txData.data) ?? "0x" : "0x";
|
||||||
const fourBytesEntry = use4Bytes(fourBytes);
|
const fourBytesEntry = use4Bytes(fourBytes);
|
||||||
const fourBytesTxDesc = useTransactionDescription(
|
const fourBytesTxDesc = useTransactionDescription(
|
||||||
fourBytesEntry,
|
fourBytesEntry,
|
||||||
|
@ -4,9 +4,10 @@ import {
|
|||||||
Interface,
|
Interface,
|
||||||
TransactionDescription,
|
TransactionDescription,
|
||||||
} from "@ethersproject/abi";
|
} from "@ethersproject/abi";
|
||||||
|
import { BigNumberish } from "@ethersproject/bignumber";
|
||||||
|
import useSWR from "swr";
|
||||||
import { RuntimeContext } from "./useRuntime";
|
import { RuntimeContext } from "./useRuntime";
|
||||||
import { fourBytesURL } from "./url";
|
import { fourBytesURL } from "./url";
|
||||||
import { BigNumberish } from "@ethersproject/bignumber";
|
|
||||||
|
|
||||||
export type FourBytesEntry = {
|
export type FourBytesEntry = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -15,13 +16,14 @@ export type FourBytesEntry = {
|
|||||||
|
|
||||||
export type FourBytesMap = Record<string, FourBytesEntry | null | undefined>;
|
export type FourBytesMap = Record<string, FourBytesEntry | null | undefined>;
|
||||||
|
|
||||||
const simpleTransfer: FourBytesEntry = {
|
/**
|
||||||
name: "transfer",
|
* Given a hex input data; extract the method selector
|
||||||
signature: undefined,
|
*
|
||||||
};
|
* @param rawInput Raw tx input including the "0x"
|
||||||
|
* @returns the first 4 bytes, including the "0x" or null if the input
|
||||||
const fullCache = new Map<string, FourBytesEntry | null>();
|
* contains an invalid selector, e.g., txs with 0x00 data; simple transfers (0x)
|
||||||
|
* return null as well as it is not a method selector
|
||||||
|
*/
|
||||||
export const extract4Bytes = (rawInput: string): string | null => {
|
export const extract4Bytes = (rawInput: string): string | null => {
|
||||||
if (rawInput.length < 10) {
|
if (rawInput.length < 10) {
|
||||||
return null;
|
return null;
|
||||||
@ -29,8 +31,6 @@ export const extract4Bytes = (rawInput: string): string | null => {
|
|||||||
return rawInput.slice(0, 10);
|
return rawInput.slice(0, 10);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const rawInputTo4Bytes = (rawInput: string) => rawInput.slice(0, 10);
|
|
||||||
|
|
||||||
const fetch4Bytes = async (
|
const fetch4Bytes = async (
|
||||||
assetsURLPrefix: string,
|
assetsURLPrefix: string,
|
||||||
fourBytes: string
|
fourBytes: string
|
||||||
@ -61,6 +61,7 @@ const fetch4Bytes = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: migrate to swr and merge with use4Bytes
|
||||||
export const useBatch4Bytes = (
|
export const useBatch4Bytes = (
|
||||||
rawFourByteSigs: string[] | undefined
|
rawFourByteSigs: string[] | undefined
|
||||||
): FourBytesMap => {
|
): FourBytesMap => {
|
||||||
@ -98,56 +99,60 @@ export const useBatch4Bytes = (
|
|||||||
* @param rawFourBytes an hex string containing the 4bytes signature in the "0xXXXXXXXX" format.
|
* @param rawFourBytes an hex string containing the 4bytes signature in the "0xXXXXXXXX" format.
|
||||||
*/
|
*/
|
||||||
export const use4Bytes = (
|
export const use4Bytes = (
|
||||||
rawFourBytes: string
|
rawFourBytes: string | null
|
||||||
): FourBytesEntry | null | undefined => {
|
): FourBytesEntry | null | undefined => {
|
||||||
if (rawFourBytes !== "0x") {
|
if (rawFourBytes !== null && !rawFourBytes.startsWith("0x")) {
|
||||||
if (rawFourBytes.length !== 10 || !rawFourBytes.startsWith("0x")) {
|
throw new Error(
|
||||||
throw new Error(
|
`rawFourBytes must contain a bytes hex string starting with 0x; received value: "${rawFourBytes}"`
|
||||||
`rawFourBytes must contain a 4 bytes hex method signature starting with 0x; received value: "${rawFourBytes}"`
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const runtime = useContext(RuntimeContext);
|
const { config } = useContext(RuntimeContext);
|
||||||
const assetsURLPrefix = runtime.config?.assetsURLPrefix;
|
const assetsURLPrefix = config?.assetsURLPrefix;
|
||||||
|
|
||||||
const fourBytes = rawFourBytes.slice(2);
|
const fourBytesFetcher = (key: string | null) => {
|
||||||
const [entry, setEntry] = useState<FourBytesEntry | null | undefined>(
|
// TODO: throw error?
|
||||||
fullCache.get(fourBytes)
|
|
||||||
);
|
|
||||||
useEffect(() => {
|
|
||||||
if (assetsURLPrefix === undefined) {
|
if (assetsURLPrefix === undefined) {
|
||||||
return;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (fourBytes === "") {
|
if (key === null || key === "0x") {
|
||||||
return;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadSig = async () => {
|
// Handle simple transfers with invalid selector like tx:
|
||||||
const entry = await fetch4Bytes(assetsURLPrefix, fourBytes);
|
// 0x8bcbdcc1589b5c34c1e55909c8269a411f0267a4fed59a73dd4348cc71addbb9,
|
||||||
fullCache.set(fourBytes, entry);
|
// which contains 0x00 as data
|
||||||
setEntry(entry);
|
if (key.length !== 10) {
|
||||||
};
|
return undefined;
|
||||||
loadSig();
|
}
|
||||||
}, [fourBytes, assetsURLPrefix]);
|
|
||||||
|
|
||||||
if (rawFourBytes === "0x") {
|
return fetch4Bytes(assetsURLPrefix, key.slice(2));
|
||||||
return simpleTransfer;
|
};
|
||||||
}
|
|
||||||
if (assetsURLPrefix === undefined) {
|
const { data, error } = useSWR<FourBytesEntry | null | undefined>(
|
||||||
|
rawFourBytes,
|
||||||
|
fourBytesFetcher
|
||||||
|
);
|
||||||
|
if (error) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
// Try to resolve 4bytes name
|
export const useMethodSelector = (data: string): [boolean, string, string] => {
|
||||||
if (entry === null || entry === undefined) {
|
const rawFourBytes = extract4Bytes(data);
|
||||||
return entry;
|
const fourBytesEntry = use4Bytes(rawFourBytes);
|
||||||
}
|
const isSimpleTransfer = data === "0x";
|
||||||
|
const methodName = isSimpleTransfer
|
||||||
|
? "transfer"
|
||||||
|
: fourBytesEntry?.name ?? rawFourBytes ?? "-";
|
||||||
|
const methodTitle = isSimpleTransfer
|
||||||
|
? "ETH Transfer"
|
||||||
|
: methodName === rawFourBytes
|
||||||
|
? methodName
|
||||||
|
: `${methodName} [${rawFourBytes}]`;
|
||||||
|
|
||||||
// Simulates LRU
|
return [isSimpleTransfer, methodName, methodTitle];
|
||||||
// TODO: implement LRU purging
|
|
||||||
fullCache.delete(fourBytes);
|
|
||||||
fullCache.set(fourBytes, entry);
|
|
||||||
return entry;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTransactionDescription = (
|
export const useTransactionDescription = (
|
||||||
|
Loading…
Reference in New Issue
Block a user