From 1b9f26a3f0b92a1d607f9e574444a8aa12420aa8 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 26 Oct 2021 22:10:37 -0300 Subject: [PATCH 01/54] First working prototype with call tree --- src/Transaction.tsx | 10 ++++ src/transaction/Trace.tsx | 39 ++++++++++++++++ src/transaction/TraceItem.tsx | 68 +++++++++++++++++++++++++++ src/useErigonHooks.ts | 86 +++++++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+) create mode 100644 src/transaction/Trace.tsx create mode 100644 src/transaction/TraceItem.tsx diff --git a/src/Transaction.tsx b/src/Transaction.tsx index a240c7e..04cdd8b 100644 --- a/src/Transaction.tsx +++ b/src/Transaction.tsx @@ -25,6 +25,12 @@ const Logs = React.lazy( /* webpackChunkName: "txlogs", webpackPrefetch: true */ "./transaction/Logs" ) ); +const Trace = React.lazy( + () => + import( + /* webpackChunkName: "txtrace", webpackPrefetch: true */ "./transaction/Trace" + ) +); type TransactionParams = { txhash: string; @@ -87,6 +93,7 @@ const Transaction: React.FC = () => { {txData && ` (${txData.confirmedData?.logs?.length ?? 0})`} )} + Trace @@ -105,6 +112,9 @@ const Transaction: React.FC = () => { + + + diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx new file mode 100644 index 0000000..45e438a --- /dev/null +++ b/src/transaction/Trace.tsx @@ -0,0 +1,39 @@ +import React, { useContext } from "react"; +import AddressHighlighter from "../components/AddressHighlighter"; +import DecoratedAddressLink from "../components/DecoratedAddressLink"; +import ContentFrame from "../ContentFrame"; +import { TransactionData } from "../types"; +import { useTraceTransaction } from "../useErigonHooks"; +import { RuntimeContext } from "../useRuntime"; +import TraceItem from "./TraceItem"; + +type TraceProps = { + txData: TransactionData; +}; + +const Trace: React.FC = ({ txData }) => { + const { provider } = useContext(RuntimeContext); + const traces = useTraceTransaction(provider, txData.transactionHash); + + return ( + +
+
+ + + +
+ {traces?.map((t, i, a) => ( + + ))} +
+
+ ); +}; + +export default React.memo(Trace); diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx new file mode 100644 index 0000000..f3179ef --- /dev/null +++ b/src/transaction/TraceItem.tsx @@ -0,0 +1,68 @@ +import React from "react"; +import AddressHighlighter from "../components/AddressHighlighter"; +import DecoratedAddressLink from "../components/DecoratedAddressLink"; +import { TransactionData } from "../types"; +import { rawInputTo4Bytes } from "../use4Bytes"; +import { TraceGroup } from "../useErigonHooks"; + +type TraceItemProps = { + t: TraceGroup; + txData: TransactionData; + last: boolean; +}; + +const TraceItem: React.FC = ({ t, txData, last }) => { + const raw4Bytes = rawInputTo4Bytes(t.input); + return ( + <> +
+
+
+ {!last && ( +
+ )} +
+
+ {t.depth} + {t.type} + + + + + + . + {raw4Bytes} + ( + {t.input.length > 10 && ( + + input=[{t.input.slice(10)}] + + )} + ) +
+
+ {t.children && ( +
+
+
+ {t.children.map((tc, i, a) => ( + + ))} +
+
+ )} + + ); +}; + +export default React.memo(TraceItem); diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index 7322a0d..2bb308c 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -308,3 +308,89 @@ export const useInternalOperations = ( return intTransfers; }; + +export type TraceEntry = { + type: string; + depth: number; + from: string; + to: string; + value: BigNumber; + input: string; +}; + +export type TraceGroup = TraceEntry & { + children: TraceGroup[] | null; +}; + +export const useTraceTransaction = ( + provider: JsonRpcProvider | undefined, + txHash: string +): TraceGroup[] | undefined => { + const [traceGroups, setTraceGroups] = useState(); + + useEffect(() => { + if (!provider) { + setTraceGroups(undefined); + return; + } + + const traceTx = async () => { + const results = await provider.send("ots_traceTransaction", [txHash]); + + // Implement better formatter + for (let i = 0; i < results.length; i++) { + results[i].from = provider.formatter.address(results[i].from); + results[i].to = provider.formatter.address(results[i].to); + } + + // Build trace tree + const buildTraceTree = ( + flatList: TraceEntry[], + depth: number = 0 + ): TraceGroup[] => { + const entries: TraceGroup[] = []; + + let children: TraceEntry[] | null = null; + for (let i = 0; i < flatList.length; i++) { + if (flatList[i].depth === depth) { + if (children !== null) { + const childrenTree = buildTraceTree(children, depth + 1); + const prev = entries.pop(); + if (prev) { + prev.children = childrenTree; + entries.push(prev); + } + } + + entries.push({ + ...flatList[i], + children: null, + }); + children = null; + } else { + if (children === null) { + children = []; + } + children.push(flatList[i]); + } + } + if (children !== null) { + const childrenTree = buildTraceTree(children, depth + 1); + const prev = entries.pop(); + if (prev) { + prev.children = childrenTree; + entries.push(prev); + } + } + + return entries; + }; + + const traceTree = buildTraceTree(results); + setTraceGroups(traceTree); + }; + traceTx(); + }, [provider, txHash]); + + return traceGroups; +}; From 5229cb8c958e8f07ce994d49dba45d8094d1bd10 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:07:56 -0300 Subject: [PATCH 02/54] Disable brotli on nginx for now --- nginx/conf.d/default.conf | 2 +- nginx/nginx.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx/conf.d/default.conf b/nginx/conf.d/default.conf index b5d141b..4fdf9a1 100644 --- a/nginx/conf.d/default.conf +++ b/nginx/conf.d/default.conf @@ -118,7 +118,7 @@ server { index index.html; try_files $uri /index.html; - brotli_static on; + # brotli_static on; } #error_page 404 /404.html; diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 7364514..72d7924 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -4,7 +4,7 @@ worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; -load_module modules/ngx_http_brotli_static_module.so; +#load_module modules/ngx_http_brotli_static_module.so; events { worker_connections 1024; From 48986de7f3c3047f6ea8dcc9a3999c4635da7976 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:08:26 -0300 Subject: [PATCH 03/54] Add 4bytes decoding support to trace view --- src/transaction/TraceItem.tsx | 8 ++++++-- src/use4Bytes.ts | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index f3179ef..dd8bbef 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -2,7 +2,7 @@ import React from "react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import { TransactionData } from "../types"; -import { rawInputTo4Bytes } from "../use4Bytes"; +import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; type TraceItemProps = { @@ -13,6 +13,8 @@ type TraceItemProps = { const TraceItem: React.FC = ({ t, txData, last }) => { const raw4Bytes = rawInputTo4Bytes(t.input); + const fourBytesEntry = use4Bytes(raw4Bytes); + return ( <>
@@ -36,7 +38,9 @@ const TraceItem: React.FC = ({ t, txData, last }) => { . - {raw4Bytes} + + {fourBytesEntry ? fourBytesEntry.name : raw4Bytes} + ( {t.input.length > 10 && ( diff --git a/src/use4Bytes.ts b/src/use4Bytes.ts index 9fe9252..6dab197 100644 --- a/src/use4Bytes.ts +++ b/src/use4Bytes.ts @@ -61,8 +61,7 @@ export const use4Bytes = ( const sigs = await res.text(); const sig = sigs.split(";")[0]; const cut = sig.indexOf("("); - let method = sig.slice(0, cut); - method = method.charAt(0).toUpperCase() + method.slice(1); + const method = sig.slice(0, cut); const entry: FourBytesEntry = { name: method, From 0445ccd448f957ab573f482cf27c65d97d04c90c Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:09:03 -0300 Subject: [PATCH 04/54] Remove depth info --- src/transaction/TraceItem.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index dd8bbef..c1d4457 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -25,7 +25,6 @@ const TraceItem: React.FC = ({ t, txData, last }) => { )}
- {t.depth} {t.type} From 309739e547518ff7a2b97c60bfa760c453f8969c Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:14:42 -0300 Subject: [PATCH 05/54] Add tree decoration to from address --- src/transaction/Trace.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 45e438a..0be2110 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -18,7 +18,7 @@ const Trace: React.FC = ({ txData }) => { return (
-
+
= ({ txData }) => { />
- {traces?.map((t, i, a) => ( - - ))} +
+
+
+ {traces?.map((t, i, a) => ( + + ))} +
+
); From 277fa8f37cb8d4e79c5c74b42780981a2fd384b9 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:18:18 -0300 Subject: [PATCH 06/54] Different color for STATICCALL --- src/transaction/TraceItem.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index c1d4457..eaa702d 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -37,7 +37,11 @@ const TraceItem: React.FC = ({ t, txData, last }) => { . - + {fourBytesEntry ? fourBytesEntry.name : raw4Bytes} ( From 8992ea233677df254e33b034423b352c3961ac62 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:20:01 -0300 Subject: [PATCH 07/54] Add 0x decoration prefix to input --- src/transaction/TraceItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index eaa702d..8e4d4ff 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -47,7 +47,7 @@ const TraceItem: React.FC = ({ t, txData, last }) => { ( {t.input.length > 10 && ( - input=[{t.input.slice(10)}] + input=[0x{t.input.slice(10)}] )} ) From 56df620c7cdada08cea81c22210a08577303f9f5 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:33:14 -0300 Subject: [PATCH 08/54] Add color decoration to DELEGATECALL tracing --- src/transaction/TraceItem.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 8e4d4ff..136e6bb 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -39,7 +39,11 @@ const TraceItem: React.FC = ({ t, txData, last }) => { . {fourBytesEntry ? fourBytesEntry.name : raw4Bytes} From 5188cd980e05e078d32fdeb3fa8224385215fd05 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 01:34:44 -0300 Subject: [PATCH 09/54] Add horizontal scroll to trace tree --- src/transaction/Trace.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 0be2110..568988c 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -17,7 +17,7 @@ const Trace: React.FC = ({ txData }) => { return ( -
+
Date: Wed, 27 Oct 2021 05:14:46 -0300 Subject: [PATCH 10/54] Add value field to call tree --- src/transaction/TraceItem.tsx | 6 ++++++ src/useErigonHooks.ts | 1 + 2 files changed, 7 insertions(+) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 136e6bb..3b6b9ef 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -1,6 +1,7 @@ import React from "react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; +import FormattedBalance from "../components/FormattedBalance"; import { TransactionData } from "../types"; import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; @@ -48,6 +49,11 @@ const TraceItem: React.FC = ({ t, txData, last }) => { > {fourBytesEntry ? fourBytesEntry.name : raw4Bytes} + {t.value && !t.value.isZero() && ( + + {"{"}value: ETH{"}"} + + )} ( {t.input.length > 10 && ( diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index 2bb308c..62b2449 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -341,6 +341,7 @@ export const useTraceTransaction = ( for (let i = 0; i < results.length; i++) { results[i].from = provider.formatter.address(results[i].from); results[i].to = provider.formatter.address(results[i].to); + results[i].value = provider.formatter.bigNumber(results[i].value); } // Build trace tree From d27df7d27150f362f2377aaa699da3fb1f743782 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 14:57:38 -0300 Subject: [PATCH 11/54] Omit missing value field --- src/transaction/TraceItem.tsx | 2 +- src/useErigonHooks.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 3b6b9ef..4de951a 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -42,7 +42,7 @@ const TraceItem: React.FC = ({ t, txData, last }) => { className={`font-bold ${ t.type === "STATICCALL" ? "text-red-700" - : t.type === "DELEGATECALL" + : t.type === "DELEGATECALL" || t.type === "CALLCODE" ? "text-gray-400" : "text-blue-900" }`} diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index 62b2449..dc7de4e 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -341,7 +341,10 @@ export const useTraceTransaction = ( for (let i = 0; i < results.length; i++) { results[i].from = provider.formatter.address(results[i].from); results[i].to = provider.formatter.address(results[i].to); - results[i].value = provider.formatter.bigNumber(results[i].value); + results[i].value = + results[i].value === null + ? null + : provider.formatter.bigNumber(results[i].value); } // Build trace tree From 3ea9dc764345ad8b10598d56ad019edcc7b85289 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 15:49:15 -0300 Subject: [PATCH 12/54] Micro optimization for large traces --- src/components/AddressHighlighter.tsx | 31 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/components/AddressHighlighter.tsx b/src/components/AddressHighlighter.tsx index e8078d6..7d37b2a 100644 --- a/src/components/AddressHighlighter.tsx +++ b/src/components/AddressHighlighter.tsx @@ -21,20 +21,37 @@ const AddressHighlighter: React.FC = ({ }, [setSelection, address]); return ( -
+ {children} + + ); +}; + +type _AddressHighlighterImplProps = { + selected: boolean; + select: () => void; + deselect: () => void; +}; + +const AddressHighlighterImpl: React.FC<_AddressHighlighterImplProps> = + React.memo(({ selected, select, deselect, children }) => ( +
{children}
- ); -}; + )); -export default React.memo(AddressHighlighter); +export default AddressHighlighter; From a0677feda77f0c0f204bc07ece6fca11735bfd3f Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 17:03:09 -0300 Subject: [PATCH 13/54] Remove redundant React.memo --- src/components/AddressLink.tsx | 2 +- src/components/AddressOrENSName.tsx | 2 +- src/components/ENSNameLink.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/AddressLink.tsx b/src/components/AddressLink.tsx index a8fd5c3..4b6f99e 100644 --- a/src/components/AddressLink.tsx +++ b/src/components/AddressLink.tsx @@ -24,4 +24,4 @@ const AddressLink: React.FC = ({ ); -export default React.memo(AddressLink); +export default AddressLink; diff --git a/src/components/AddressOrENSName.tsx b/src/components/AddressOrENSName.tsx index 9cb2f9e..c0defc0 100644 --- a/src/components/AddressOrENSName.tsx +++ b/src/components/AddressOrENSName.tsx @@ -48,4 +48,4 @@ const AddressOrENSName: React.FC = ({ ); -export default React.memo(AddressOrENSName); +export default AddressOrENSName; diff --git a/src/components/ENSNameLink.tsx b/src/components/ENSNameLink.tsx index c1da646..ad5df4d 100644 --- a/src/components/ENSNameLink.tsx +++ b/src/components/ENSNameLink.tsx @@ -31,4 +31,4 @@ const ENSNameLink: React.FC = ({ ); -export default React.memo(ENSNameLink); +export default ENSNameLink; From ad94813476d7fbd9d63d5d23cf52827aee01c9d4 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 27 Oct 2021 17:19:20 -0300 Subject: [PATCH 14/54] Remove unnecessary React.memo --- src/transaction/TraceItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 4de951a..e161674 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -82,4 +82,4 @@ const TraceItem: React.FC = ({ t, txData, last }) => { ); }; -export default React.memo(TraceItem); +export default TraceItem; From 09e89c5f4197a762b23cd1ad95268e3011b187f0 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 02:54:36 -0300 Subject: [PATCH 15/54] Retrofit the AddressHighlighter into the new generic SelectionHighlighter --- src/components/AddressHighlighter.tsx | 58 ++++--------------- src/components/SelectionHighlighter.tsx | 76 +++++++++++++++++++++++++ src/transaction/FunctionSignature.tsx | 25 ++++++++ src/transaction/TraceItem.tsx | 16 ++---- src/useSelection.ts | 6 +- 5 files changed, 121 insertions(+), 60 deletions(-) create mode 100644 src/components/SelectionHighlighter.tsx create mode 100644 src/transaction/FunctionSignature.tsx diff --git a/src/components/AddressHighlighter.tsx b/src/components/AddressHighlighter.tsx index 7d37b2a..0848a48 100644 --- a/src/components/AddressHighlighter.tsx +++ b/src/components/AddressHighlighter.tsx @@ -1,5 +1,5 @@ -import React, { useMemo } from "react"; -import { useSelectionContext } from "../useSelection"; +import React from "react"; +import SelectionHighlighter, { addressSelector } from "./SelectionHighlighter"; type AddressHighlighterProps = React.PropsWithChildren<{ address: string; @@ -8,50 +8,14 @@ type AddressHighlighterProps = React.PropsWithChildren<{ const AddressHighlighter: React.FC = ({ address, children, -}) => { - const [selection, setSelection] = useSelectionContext(); - const [select, deselect] = useMemo(() => { - const _select = () => { - setSelection({ type: "address", content: address }); - }; - const _deselect = () => { - setSelection(null); - }; - return [_select, _deselect]; - }, [setSelection, address]); - - return ( - - {children} - - ); -}; - -type _AddressHighlighterImplProps = { - selected: boolean; - select: () => void; - deselect: () => void; -}; - -const AddressHighlighterImpl: React.FC<_AddressHighlighterImplProps> = - React.memo(({ selected, select, deselect, children }) => ( -
- {children} -
- )); +}) => ( + + {children} + +); export default AddressHighlighter; diff --git a/src/components/SelectionHighlighter.tsx b/src/components/SelectionHighlighter.tsx new file mode 100644 index 0000000..baa2ec5 --- /dev/null +++ b/src/components/SelectionHighlighter.tsx @@ -0,0 +1,76 @@ +import React, { useMemo } from "react"; +import { + useSelectionContext, + OptionalSelection, + SelectionType, +} from "../useSelection"; + +export type ContentSelector = ( + selection: OptionalSelection, + content: string +) => boolean; + +export const genericSelector = + (type: SelectionType) => + (selection: OptionalSelection, content: string): boolean => + selection !== null && + selection.type === type && + selection.content === content; + +export const addressSelector: ContentSelector = genericSelector("address"); + +type SelectionHighlighterProps = React.PropsWithChildren<{ + myType: SelectionType; + myContent: string; + selector: ContentSelector; +}>; + +const SelectionHighlighter: React.FC = ({ + myType, + myContent, + selector, + children, +}) => { + const [selection, setSelection] = useSelectionContext(); + const [select, deselect] = useMemo(() => { + const _select = () => { + setSelection({ type: myType, content: myContent }); + }; + const _deselect = () => { + setSelection(null); + }; + return [_select, _deselect]; + }, [setSelection, myType, myContent]); + + return ( + + {children} + + ); +}; + +type HighlighterBoxProps = { + selected: boolean; + select: () => void; + deselect: () => void; +}; + +const HighlighterBox: React.FC = React.memo( + ({ selected, select, deselect, children }) => ( +
+ {children} +
+ ) +); + +export default SelectionHighlighter; diff --git a/src/transaction/FunctionSignature.tsx b/src/transaction/FunctionSignature.tsx new file mode 100644 index 0000000..516e8a7 --- /dev/null +++ b/src/transaction/FunctionSignature.tsx @@ -0,0 +1,25 @@ +import React from "react"; + +type FunctionSignatureProps = { + callType: string; + sig: string; +}; + +const FunctionSignature: React.FC = ({ + callType, + sig, +}) => ( + + {sig} + +); + +export default FunctionSignature; diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index e161674..f8e2288 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -2,6 +2,7 @@ import React from "react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import FormattedBalance from "../components/FormattedBalance"; +import FunctionSignature from "./FunctionSignature"; import { TransactionData } from "../types"; import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; @@ -38,17 +39,10 @@ const TraceItem: React.FC = ({ t, txData, last }) => { . - - {fourBytesEntry ? fourBytesEntry.name : raw4Bytes} - + {t.value && !t.value.isZero() && ( {"{"}value: ETH{"}"} diff --git a/src/useSelection.ts b/src/useSelection.ts index 03a2a92..8dc8f95 100644 --- a/src/useSelection.ts +++ b/src/useSelection.ts @@ -6,12 +6,14 @@ import { useContext, } from "react"; +export type SelectionType = "address" | "value" | "functionSig"; + export type Selection = { - type: "address" | "value"; + type: SelectionType; content: string; }; -type OptionalSelection = Selection | null; +export type OptionalSelection = Selection | null; export const useSelection = (): [ OptionalSelection, From f800f057877e49025fb5f1be1a85b6eca8f2d6d5 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 02:56:17 -0300 Subject: [PATCH 16/54] Add deprecation notice --- src/components/AddressHighlighter.tsx | 1 + src/components/ValueHighlighter.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/components/AddressHighlighter.tsx b/src/components/AddressHighlighter.tsx index 0848a48..9c2c4c3 100644 --- a/src/components/AddressHighlighter.tsx +++ b/src/components/AddressHighlighter.tsx @@ -5,6 +5,7 @@ type AddressHighlighterProps = React.PropsWithChildren<{ address: string; }>; +// TODO: replace all occurences with SelectionHighlighter and remove this component const AddressHighlighter: React.FC = ({ address, children, diff --git a/src/components/ValueHighlighter.tsx b/src/components/ValueHighlighter.tsx index c15b514..b9c813f 100644 --- a/src/components/ValueHighlighter.tsx +++ b/src/components/ValueHighlighter.tsx @@ -6,6 +6,7 @@ type ValueHighlighterProps = React.PropsWithChildren<{ value: BigNumber; }>; +// TODO: replace all occurences with SelectionHighlighter and remove this component const ValueHighlighter: React.FC = ({ value, children, From 05953de0532cc5de2c3cc4a0ac65bdcb3584ee9e Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 02:59:50 -0300 Subject: [PATCH 17/54] Apply selection highlighter to function sigs --- src/components/SelectionHighlighter.tsx | 2 ++ src/transaction/FunctionSignature.tsx | 29 ++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/components/SelectionHighlighter.tsx b/src/components/SelectionHighlighter.tsx index baa2ec5..40a3431 100644 --- a/src/components/SelectionHighlighter.tsx +++ b/src/components/SelectionHighlighter.tsx @@ -18,6 +18,8 @@ export const genericSelector = selection.content === content; export const addressSelector: ContentSelector = genericSelector("address"); +export const functionSigSelector: ContentSelector = + genericSelector("functionSig"); type SelectionHighlighterProps = React.PropsWithChildren<{ myType: SelectionType; diff --git a/src/transaction/FunctionSignature.tsx b/src/transaction/FunctionSignature.tsx index 516e8a7..718138e 100644 --- a/src/transaction/FunctionSignature.tsx +++ b/src/transaction/FunctionSignature.tsx @@ -1,4 +1,7 @@ import React from "react"; +import SelectionHighlighter, { + functionSigSelector, +} from "../components/SelectionHighlighter"; type FunctionSignatureProps = { callType: string; @@ -9,17 +12,23 @@ const FunctionSignature: React.FC = ({ callType, sig, }) => ( - - {sig} - + + {sig} + + ); export default FunctionSignature; From cbab64cd9956236c251fc8e5f66beea9cb48c1fb Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 17:21:01 -0300 Subject: [PATCH 18/54] Dedup and optimize 4bytes calls for really huge traces --- src/transaction/Trace.tsx | 12 +++++-- src/transaction/TraceItem.tsx | 13 ++++++-- src/use4Bytes.ts | 63 +++++++++++++++++++++++++++++++++++ src/useErigonHooks.ts | 38 ++++++++++++++++++++- tsconfig.json | 3 +- 5 files changed, 122 insertions(+), 7 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 568988c..da0b24a 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -1,9 +1,14 @@ -import React, { useContext } from "react"; +import React, { useContext, useMemo } from "react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import ContentFrame from "../ContentFrame"; import { TransactionData } from "../types"; -import { useTraceTransaction } from "../useErigonHooks"; +import { rawInputTo4Bytes, useBatch4Bytes } from "../use4Bytes"; +import { + TraceGroup, + useTraceTransaction, + useUniqueSignatures, +} from "../useErigonHooks"; import { RuntimeContext } from "../useRuntime"; import TraceItem from "./TraceItem"; @@ -14,6 +19,8 @@ type TraceProps = { const Trace: React.FC = ({ txData }) => { const { provider } = useContext(RuntimeContext); const traces = useTraceTransaction(provider, txData.transactionHash); + const uniqueSignatures = useUniqueSignatures(traces); + const sigMap = useBatch4Bytes(uniqueSignatures); return ( @@ -37,6 +44,7 @@ const Trace: React.FC = ({ txData }) => { t={t} txData={txData} last={i === a.length - 1} + fourBytesMap={sigMap} /> ))}
diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index f8e2288..e5390a8 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -4,18 +4,24 @@ import DecoratedAddressLink from "../components/DecoratedAddressLink"; import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; import { TransactionData } from "../types"; -import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes"; +import { FourBytesEntry, rawInputTo4Bytes } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; type TraceItemProps = { t: TraceGroup; txData: TransactionData; last: boolean; + fourBytesMap: Record; }; -const TraceItem: React.FC = ({ t, txData, last }) => { +const TraceItem: React.FC = ({ + t, + txData, + last, + fourBytesMap, +}) => { const raw4Bytes = rawInputTo4Bytes(t.input); - const fourBytesEntry = use4Bytes(raw4Bytes); + const fourBytesEntry = fourBytesMap[raw4Bytes]; return ( <> @@ -67,6 +73,7 @@ const TraceItem: React.FC = ({ t, txData, last }) => { t={tc} txData={txData} last={i === a.length - 1} + fourBytesMap={fourBytesMap} /> ))}
diff --git a/src/use4Bytes.ts b/src/use4Bytes.ts index 6dab197..380c45e 100644 --- a/src/use4Bytes.ts +++ b/src/use4Bytes.ts @@ -7,6 +7,8 @@ export type FourBytesEntry = { signature: string | undefined; }; +export type FourBytesMap = Record; + const simpleTransfer: FourBytesEntry = { name: "Transfer", signature: undefined, @@ -16,6 +18,67 @@ const fullCache = new Map(); export const rawInputTo4Bytes = (rawInput: string) => rawInput.slice(0, 10); +const fetch4Bytes = async ( + assetsURLPrefix: string, + fourBytes: string +): Promise => { + const signatureURL = fourBytesURL(assetsURLPrefix, fourBytes); + + try { + const res = await fetch(signatureURL); + if (!res.ok) { + console.error(`Signature does not exist in 4bytes DB: ${fourBytes}`); + return null; + } + + // Get only the first occurrence, for now ignore alternative param names + const sigs = await res.text(); + const sig = sigs.split(";")[0]; + const cut = sig.indexOf("("); + const method = sig.slice(0, cut); + + const entry: FourBytesEntry = { + name: method, + signature: sig, + }; + return entry; + } catch (err) { + console.error(`Couldn't fetch signature URL ${signatureURL}`, err); + return null; + } +}; + +export const useBatch4Bytes = ( + rawFourByteSigs: string[] | undefined +): FourBytesMap => { + const runtime = useContext(RuntimeContext); + const assetsURLPrefix = runtime.config?.assetsURLPrefix; + + const [fourBytesMap, setFourBytesMap] = useState({}); + useEffect(() => { + if (!rawFourByteSigs || !assetsURLPrefix) { + setFourBytesMap({}); + return; + } + + const loadSigs = async () => { + const promises = rawFourByteSigs.map((s) => + fetch4Bytes(assetsURLPrefix, s.slice(2)) + ); + const results = await Promise.all(promises); + + const _fourBytesMap: Record = {}; + for (let i = 0; i < rawFourByteSigs.length; i++) { + _fourBytesMap[rawFourByteSigs[i]] = results[i]; + } + setFourBytesMap(_fourBytesMap); + }; + loadSigs(); + }, [assetsURLPrefix, rawFourByteSigs]); + + return fourBytesMap; +}; + /** * Extract 4bytes DB info * diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index dc7de4e..0d094ba 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -1,10 +1,11 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useMemo } from "react"; import { Block, BlockWithTransactions } from "@ethersproject/abstract-provider"; import { JsonRpcProvider } from "@ethersproject/providers"; import { getAddress } from "@ethersproject/address"; import { Contract } from "@ethersproject/contracts"; import { BigNumber } from "@ethersproject/bignumber"; import { arrayify, hexDataSlice, isHexString } from "@ethersproject/bytes"; +import { rawInputTo4Bytes } from "./use4Bytes"; import { getInternalOperations } from "./nodeFunctions"; import { TokenMetas, @@ -398,3 +399,38 @@ export const useTraceTransaction = ( return traceGroups; }; + +/** + * Flatten a trace tree and extract and dedup 4byte function signatures + */ +export const useUniqueSignatures = (traces: TraceGroup[] | undefined) => { + const uniqueSignatures = useMemo(() => { + if (!traces) { + return undefined; + } + + const sigs = new Set(); + let nextTraces: TraceGroup[] = [...traces]; + while (nextTraces.length > 0) { + const traces = nextTraces; + nextTraces = []; + for (const t of traces) { + if ( + t.type === "CALL" || + t.type === "DELEGATECALL" || + t.type === "STATICCALL" || + t.type === "CALLCODE" + ) { + sigs.add(rawInputTo4Bytes(t.input)); + } + if (t.children) { + nextTraces.push(...t.children); + } + } + } + + return [...sigs]; + }, [traces]); + + return uniqueSignatures; +}; diff --git a/tsconfig.json b/tsconfig.json index 9d379a3..23c0098 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,8 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "downlevelIteration": true }, "include": ["src"] } From 379c695083ba743ce1363f05c685e6c8b0fa420a Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 17:26:36 -0300 Subject: [PATCH 19/54] Retrofit new 4bytes fetcher function into legacy use4Bytes --- src/use4Bytes.ts | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/src/use4Bytes.ts b/src/use4Bytes.ts index 380c45e..1590e1c 100644 --- a/src/use4Bytes.ts +++ b/src/use4Bytes.ts @@ -110,34 +110,12 @@ export const use4Bytes = ( return; } - const signatureURL = fourBytesURL(assetsURLPrefix, fourBytes); - fetch(signatureURL) - .then(async (res) => { - if (!res.ok) { - console.error(`Signature does not exist in 4bytes DB: ${fourBytes}`); - fullCache.set(fourBytes, null); - setEntry(null); - return; - } - - // Get only the first occurrence, for now ignore alternative param names - const sigs = await res.text(); - const sig = sigs.split(";")[0]; - const cut = sig.indexOf("("); - const method = sig.slice(0, cut); - - const entry: FourBytesEntry = { - name: method, - signature: sig, - }; - setEntry(entry); - fullCache.set(fourBytes, entry); - }) - .catch((err) => { - console.error(`Couldn't fetch signature URL ${signatureURL}`, err); - setEntry(null); - fullCache.set(fourBytes, null); - }); + const loadSig = async () => { + const entry = await fetch4Bytes(assetsURLPrefix, fourBytes); + fullCache.set(fourBytes, entry); + setEntry(entry); + }; + loadSig(); }, [fourBytes, assetsURLPrefix]); if (rawFourBytes === "0x") { From 852ff5f726e2f37323e54505ed8a0bcbd285fd74 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 17:31:57 -0300 Subject: [PATCH 20/54] Remove unused imports --- src/transaction/Trace.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index da0b24a..c40cbc4 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -1,14 +1,10 @@ -import React, { useContext, useMemo } from "react"; +import React, { useContext } from "react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import ContentFrame from "../ContentFrame"; import { TransactionData } from "../types"; -import { rawInputTo4Bytes, useBatch4Bytes } from "../use4Bytes"; -import { - TraceGroup, - useTraceTransaction, - useUniqueSignatures, -} from "../useErigonHooks"; +import { useBatch4Bytes } from "../use4Bytes"; +import { useTraceTransaction, useUniqueSignatures } from "../useErigonHooks"; import { RuntimeContext } from "../useRuntime"; import TraceItem from "./TraceItem"; From 3bfd38641b7d7ca5eff1449b4defc49879231533 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 17:39:10 -0300 Subject: [PATCH 21/54] Correctly render fallback function signature --- src/transaction/TraceItem.tsx | 14 +++++++------- src/use4Bytes.ts | 7 +++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index e5390a8..3e72fed 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -4,7 +4,7 @@ import DecoratedAddressLink from "../components/DecoratedAddressLink"; import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; import { TransactionData } from "../types"; -import { FourBytesEntry, rawInputTo4Bytes } from "../use4Bytes"; +import { extract4Bytes, FourBytesEntry } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; type TraceItemProps = { @@ -20,8 +20,11 @@ const TraceItem: React.FC = ({ last, fourBytesMap, }) => { - const raw4Bytes = rawInputTo4Bytes(t.input); - const fourBytesEntry = fourBytesMap[raw4Bytes]; + const raw4Bytes = extract4Bytes(t.input); + const sigText = + raw4Bytes === null + ? "" + : fourBytesMap[raw4Bytes]?.name ?? raw4Bytes; return ( <> @@ -45,10 +48,7 @@ const TraceItem: React.FC = ({ . - + {t.value && !t.value.isZero() && ( {"{"}value: ETH{"}"} diff --git a/src/use4Bytes.ts b/src/use4Bytes.ts index 1590e1c..5b4a726 100644 --- a/src/use4Bytes.ts +++ b/src/use4Bytes.ts @@ -16,6 +16,13 @@ const simpleTransfer: FourBytesEntry = { const fullCache = new Map(); +export const extract4Bytes = (rawInput: string): string | null => { + if (rawInput.length < 10) { + return null; + } + return rawInput.slice(0, 10); +}; + export const rawInputTo4Bytes = (rawInput: string) => rawInput.slice(0, 10); const fetch4Bytes = async ( From 7b611f96e23be32b1f5a29712add178c23fdcb27 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 17:41:56 -0300 Subject: [PATCH 22/54] Fix fallback case on dedup sig function --- src/useErigonHooks.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index 0d094ba..e0bba21 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -5,7 +5,7 @@ import { getAddress } from "@ethersproject/address"; import { Contract } from "@ethersproject/contracts"; import { BigNumber } from "@ethersproject/bignumber"; import { arrayify, hexDataSlice, isHexString } from "@ethersproject/bytes"; -import { rawInputTo4Bytes } from "./use4Bytes"; +import { extract4Bytes } from "./use4Bytes"; import { getInternalOperations } from "./nodeFunctions"; import { TokenMetas, @@ -414,6 +414,7 @@ export const useUniqueSignatures = (traces: TraceGroup[] | undefined) => { while (nextTraces.length > 0) { const traces = nextTraces; nextTraces = []; + for (const t of traces) { if ( t.type === "CALL" || @@ -421,8 +422,12 @@ export const useUniqueSignatures = (traces: TraceGroup[] | undefined) => { t.type === "STATICCALL" || t.type === "CALLCODE" ) { - sigs.add(rawInputTo4Bytes(t.input)); + const fourBytes = extract4Bytes(t.input); + if (fourBytes) { + sigs.add(fourBytes); + } } + if (t.children) { nextTraces.push(...t.children); } From a3626136a6c066a9e25d28721130617407bd41ed Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 28 Oct 2021 23:39:33 -0300 Subject: [PATCH 23/54] Avoid getting erc20 metadata multiple times in the same session --- src/TokenTransferItem.tsx | 2 +- src/components/DecoratedAddressLink.tsx | 2 +- src/types.ts | 2 +- src/useErigonHooks.ts | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/TokenTransferItem.tsx b/src/TokenTransferItem.tsx index 083f7f0..5a1d5cc 100644 --- a/src/TokenTransferItem.tsx +++ b/src/TokenTransferItem.tsx @@ -15,7 +15,7 @@ import { type TokenTransferItemProps = { t: TokenTransfer; txData: TransactionData; - tokenMeta?: TokenMeta | undefined; + tokenMeta: TokenMeta | null | undefined; }; // TODO: handle partial diff --git a/src/components/DecoratedAddressLink.tsx b/src/components/DecoratedAddressLink.tsx index 0b38fab..a39d2d8 100644 --- a/src/components/DecoratedAddressLink.tsx +++ b/src/components/DecoratedAddressLink.tsx @@ -20,7 +20,7 @@ type DecoratedAddressLinkProps = { selfDestruct?: boolean; txFrom?: boolean; txTo?: boolean; - tokenMeta?: TokenMeta; + tokenMeta?: TokenMeta | null | undefined; }; const DecoratedAddresssLink: React.FC = ({ diff --git a/src/types.ts b/src/types.ts index 5904b31..e71a492 100644 --- a/src/types.ts +++ b/src/types.ts @@ -108,4 +108,4 @@ export type TokenMeta = { decimals: number; }; -export type TokenMetas = Record; +export type TokenMetas = Record; diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index e0bba21..17d629f 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -222,7 +222,7 @@ export const useTxData = ( // Extract token meta const tokenMetas: TokenMetas = {}; for (const t of tokenTransfers) { - if (tokenMetas[t.token]) { + if (tokenMetas[t.token] !== undefined) { continue; } const erc20Contract = new Contract(t.token, erc20, provider); @@ -238,6 +238,7 @@ export const useTxData = ( decimals, }; } catch (err) { + tokenMetas[t.token] = null; console.warn(`Couldn't get token ${t.token} metadata; ignoring`, err); } } From 4da76ae836328b0fceac10e66c5ee5d8b632ee24 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Fri, 29 Oct 2021 22:31:16 -0300 Subject: [PATCH 24/54] Reduce the number of nested divs --- src/transaction/TraceItem.tsx | 47 ++++++++++++++--------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 3e72fed..6bf11dd 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -28,14 +28,12 @@ const TraceItem: React.FC = ({ return ( <> -
-
-
- {!last && ( -
- )} -
-
+
+
+ {!last && ( +
+ )} +
{t.type} @@ -54,29 +52,22 @@ const TraceItem: React.FC = ({ {"{"}value: ETH{"}"} )} - ( - {t.input.length > 10 && ( - - input=[0x{t.input.slice(10)}] - - )} - ) + + ({t.input.length > 10 && <>input=[0x{t.input.slice(10)}]}) +
{t.children && ( -
-
-
- {t.children.map((tc, i, a) => ( - - ))} -
+
+ {t.children.map((tc, i, a) => ( + + ))}
)} From c4615e47bf11ac66290fce900f55a1102fbcf689 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 1 Nov 2021 17:09:47 -0300 Subject: [PATCH 25/54] Add address resolution support to trace tool --- src/Transaction.tsx | 2 +- src/transaction/Trace.tsx | 8 ++++++-- src/transaction/TraceItem.tsx | 5 +++++ src/useResolvedAddresses.ts | 26 ++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/Transaction.tsx b/src/Transaction.tsx index b6934fa..21d821f 100644 --- a/src/Transaction.tsx +++ b/src/Transaction.tsx @@ -127,7 +127,7 @@ const Transaction: React.FC = () => { /> - + diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index c40cbc4..bc5e25a 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -2,17 +2,19 @@ import React, { useContext } from "react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import ContentFrame from "../ContentFrame"; +import TraceItem from "./TraceItem"; import { TransactionData } from "../types"; import { useBatch4Bytes } from "../use4Bytes"; import { useTraceTransaction, useUniqueSignatures } from "../useErigonHooks"; import { RuntimeContext } from "../useRuntime"; -import TraceItem from "./TraceItem"; +import { ResolvedAddresses } from "../api/address-resolver"; type TraceProps = { txData: TransactionData; + resolvedAddresses: ResolvedAddresses | undefined; }; -const Trace: React.FC = ({ txData }) => { +const Trace: React.FC = ({ txData, resolvedAddresses }) => { const { provider } = useContext(RuntimeContext); const traces = useTraceTransaction(provider, txData.transactionHash); const uniqueSignatures = useUniqueSignatures(traces); @@ -28,6 +30,7 @@ const Trace: React.FC = ({ txData }) => { miner={txData.from === txData.confirmedData?.miner} txFrom txTo={txData.from === txData.to} + resolvedAddresses={resolvedAddresses} />
@@ -41,6 +44,7 @@ const Trace: React.FC = ({ txData }) => { txData={txData} last={i === a.length - 1} fourBytesMap={sigMap} + resolvedAddresses={resolvedAddresses} /> ))}
diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 6bf11dd..b4b2fbd 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -6,12 +6,14 @@ import FunctionSignature from "./FunctionSignature"; import { TransactionData } from "../types"; import { extract4Bytes, FourBytesEntry } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; +import { ResolvedAddresses } from "../api/address-resolver"; type TraceItemProps = { t: TraceGroup; txData: TransactionData; last: boolean; fourBytesMap: Record; + resolvedAddresses: ResolvedAddresses | undefined; }; const TraceItem: React.FC = ({ @@ -19,6 +21,7 @@ const TraceItem: React.FC = ({ txData, last, fourBytesMap, + resolvedAddresses, }) => { const raw4Bytes = extract4Bytes(t.input); const sigText = @@ -42,6 +45,7 @@ const TraceItem: React.FC = ({ miner={t.to === txData.confirmedData?.miner} txFrom={t.to === txData.from} txTo={t.to === txData.to} + resolvedAddresses={resolvedAddresses} /> @@ -66,6 +70,7 @@ const TraceItem: React.FC = ({ txData={txData} last={i === a.length - 1} fourBytesMap={fourBytesMap} + resolvedAddresses={resolvedAddresses} /> ))}
diff --git a/src/useResolvedAddresses.ts b/src/useResolvedAddresses.ts index 1936da0..9eadfde 100644 --- a/src/useResolvedAddresses.ts +++ b/src/useResolvedAddresses.ts @@ -2,6 +2,7 @@ import { useState, useEffect, useRef } from "react"; import { JsonRpcProvider } from "@ethersproject/providers"; import { ProcessedTransaction, TransactionData } from "./types"; import { batchPopulate, ResolvedAddresses } from "./api/address-resolver"; +import { TraceGroup } from "./useErigonHooks"; export type AddressCollector = () => string[]; @@ -61,6 +62,31 @@ export const transactionDataCollector = return Array.from(uniqueAddresses); }; +export const tracesCollector = + (traces: TraceGroup[] | undefined): AddressCollector => + () => { + if (traces === undefined) { + return []; + } + + const uniqueAddresses = new Set(); + let searchTraces = [...traces]; + while (searchTraces.length > 0) { + const nextSearch: TraceGroup[] = []; + + for (const g of searchTraces) { + uniqueAddresses.add(g.from); + uniqueAddresses.add(g.to); + if (g.children) { + nextSearch.push(...g.children); + } + } + + searchTraces = nextSearch; + } + return Array.from(uniqueAddresses); + }; + export const useResolvedAddresses = ( provider: JsonRpcProvider | undefined, addrCollector: AddressCollector From bc1d6f35b8cb28b0c4549539dc5d793aa0687f30 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 1 Nov 2021 17:40:38 -0300 Subject: [PATCH 26/54] Add merged trace address resolution --- src/transaction/Trace.tsx | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index bc5e25a..147aa74 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -1,4 +1,4 @@ -import React, { useContext } from "react"; +import React, { useContext, useMemo } from "react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import ContentFrame from "../ContentFrame"; @@ -8,6 +8,7 @@ import { useBatch4Bytes } from "../use4Bytes"; import { useTraceTransaction, useUniqueSignatures } from "../useErigonHooks"; import { RuntimeContext } from "../useRuntime"; import { ResolvedAddresses } from "../api/address-resolver"; +import { tracesCollector, useResolvedAddresses } from "../useResolvedAddresses"; type TraceProps = { txData: TransactionData; @@ -20,6 +21,19 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { const uniqueSignatures = useUniqueSignatures(traces); const sigMap = useBatch4Bytes(uniqueSignatures); + const addrCollector = useMemo(() => tracesCollector(traces), [traces]); + const traceResolvedAddresses = useResolvedAddresses(provider, addrCollector); + const mergedResolvedAddresses = useMemo(() => { + const merge = {}; + if (resolvedAddresses) { + Object.assign(merge, resolvedAddresses); + } + if (traceResolvedAddresses) { + Object.assign(merge, traceResolvedAddresses); + } + return merge; + }, [resolvedAddresses, traceResolvedAddresses]); + return (
@@ -30,7 +44,7 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { miner={txData.from === txData.confirmedData?.miner} txFrom txTo={txData.from === txData.to} - resolvedAddresses={resolvedAddresses} + resolvedAddresses={mergedResolvedAddresses} />
@@ -44,7 +58,7 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { txData={txData} last={i === a.length - 1} fourBytesMap={sigMap} - resolvedAddresses={resolvedAddresses} + resolvedAddresses={mergedResolvedAddresses} /> ))}
From fd5b884caa674b9ee354cd8acab54bdc0de28831 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 2 Nov 2021 21:24:19 -0300 Subject: [PATCH 27/54] Add tree expand/collapse toggles --- src/transaction/TraceItem.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index b4b2fbd..14e2afc 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -1,4 +1,8 @@ -import React from "react"; +import React, { useState } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faPlusSquare } from "@fortawesome/free-regular-svg-icons/faPlusSquare"; +import { faMinusSquare } from "@fortawesome/free-regular-svg-icons/faMinusSquare"; +import { Switch } from "@headlessui/react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import FormattedBalance from "../components/FormattedBalance"; @@ -23,6 +27,7 @@ const TraceItem: React.FC = ({ fourBytesMap, resolvedAddresses, }) => { + const [expanded, setExpanded] = useState(true); const raw4Bytes = extract4Bytes(t.input); const sigText = raw4Bytes === null @@ -31,11 +36,23 @@ const TraceItem: React.FC = ({ return ( <> -
+
{!last && (
)} + {t.children && ( + + + + )}
{t.type} @@ -61,7 +78,7 @@ const TraceItem: React.FC = ({
- {t.children && ( + {expanded && t.children && (
{t.children.map((tc, i, a) => ( Date: Tue, 2 Nov 2021 21:54:25 -0300 Subject: [PATCH 28/54] Hide children nodes seems to performe better on large traces --- src/transaction/TraceItem.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 14e2afc..d97b63f 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -78,8 +78,12 @@ const TraceItem: React.FC = ({
- {expanded && t.children && ( -
+ {t.children && ( +
{t.children.map((tc, i, a) => ( Date: Wed, 3 Nov 2021 04:52:01 -0300 Subject: [PATCH 29/54] Reduce redraws --- src/transaction/TraceItem.tsx | 42 ++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index d97b63f..9f7510c 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -84,20 +84,42 @@ const TraceItem: React.FC = ({ expanded ? "" : "hidden" }`} > - {t.children.map((tc, i, a) => ( - - ))} +
)} ); }; +type TraceChildrenProps = { + c: TraceGroup[]; + txData: TransactionData; + fourBytesMap: Record; + resolvedAddresses: ResolvedAddresses | undefined; +}; + +const TraceChildren: React.FC = React.memo( + ({ c, txData, fourBytesMap, resolvedAddresses }) => { + return ( + <> + {c.map((tc, i, a) => ( + + ))} + + ); + } +); + export default TraceItem; From fd3173c3a6f88f0e12d532730fbf61d11cc19e91 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sat, 6 Nov 2021 02:12:37 -0300 Subject: [PATCH 30/54] Extract TraceInput component --- src/transaction/TraceInput.tsx | 58 ++++++++++++++++++++++++++++++++++ src/transaction/TraceItem.tsx | 42 +++++------------------- 2 files changed, 66 insertions(+), 34 deletions(-) create mode 100644 src/transaction/TraceInput.tsx diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx new file mode 100644 index 0000000..e656d6e --- /dev/null +++ b/src/transaction/TraceInput.tsx @@ -0,0 +1,58 @@ +import React from "react"; +import AddressHighlighter from "../components/AddressHighlighter"; +import DecoratedAddressLink from "../components/DecoratedAddressLink"; +import FormattedBalance from "../components/FormattedBalance"; +import FunctionSignature from "./FunctionSignature"; +import { TraceEntry } from "../useErigonHooks"; +import { TransactionData } from "../types"; +import { ResolvedAddresses } from "../api/address-resolver"; +import { extract4Bytes, FourBytesEntry } from "../use4Bytes"; + +type TraceInputProps = { + t: TraceEntry; + txData: TransactionData; + fourBytesMap: Record; + resolvedAddresses: ResolvedAddresses | undefined; +}; + +const TraceInput: React.FC = ({ + t, + txData, + fourBytesMap, + resolvedAddresses, +}) => { + const raw4Bytes = extract4Bytes(t.input); + const sigText = + raw4Bytes === null + ? "" + : fourBytesMap[raw4Bytes]?.name ?? raw4Bytes; + + return ( +
+ {t.type} + + + + + + . + + {t.value && !t.value.isZero() && ( + + {"{"}value: ETH{"}"} + + )} + + ({t.input.length > 10 && <>input=[0x{t.input.slice(10)}]}) + +
+ ); +}; + +export default TraceInput; diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index 9f7510c..b1e2be3 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -3,14 +3,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPlusSquare } from "@fortawesome/free-regular-svg-icons/faPlusSquare"; import { faMinusSquare } from "@fortawesome/free-regular-svg-icons/faMinusSquare"; import { Switch } from "@headlessui/react"; -import AddressHighlighter from "../components/AddressHighlighter"; -import DecoratedAddressLink from "../components/DecoratedAddressLink"; -import FormattedBalance from "../components/FormattedBalance"; -import FunctionSignature from "./FunctionSignature"; import { TransactionData } from "../types"; -import { extract4Bytes, FourBytesEntry } from "../use4Bytes"; +import { FourBytesEntry } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; import { ResolvedAddresses } from "../api/address-resolver"; +import TraceInput from "./TraceInput"; type TraceItemProps = { t: TraceGroup; @@ -28,11 +25,6 @@ const TraceItem: React.FC = ({ resolvedAddresses, }) => { const [expanded, setExpanded] = useState(true); - const raw4Bytes = extract4Bytes(t.input); - const sigText = - raw4Bytes === null - ? "" - : fourBytesMap[raw4Bytes]?.name ?? raw4Bytes; return ( <> @@ -53,30 +45,12 @@ const TraceItem: React.FC = ({ /> )} -
- {t.type} - - - - - - . - - {t.value && !t.value.isZero() && ( - - {"{"}value: ETH{"}"} - - )} - - ({t.input.length > 10 && <>input=[0x{t.input.slice(10)}]}) - -
+
{t.children && (
Date: Sat, 6 Nov 2021 05:04:50 -0300 Subject: [PATCH 31/54] Typedef component --- src/transaction/decoder/AddressDecoder.tsx | 16 ++++++++-------- src/transaction/decoder/DecodedParamRow.tsx | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/transaction/decoder/AddressDecoder.tsx b/src/transaction/decoder/AddressDecoder.tsx index 45fb30c..a8b5edf 100644 --- a/src/transaction/decoder/AddressDecoder.tsx +++ b/src/transaction/decoder/AddressDecoder.tsx @@ -6,7 +6,7 @@ import { TransactionData } from "../../types"; import { ResolvedAddresses } from "../../api/address-resolver"; type AddressDecoderProps = { - r: any; + r: string; txData: TransactionData; resolvedAddresses?: ResolvedAddresses | undefined; }; @@ -17,17 +17,17 @@ const AddressDecoder: React.FC = ({ resolvedAddresses, }) => (
- + - +
); -export default React.memo(AddressDecoder); +export default AddressDecoder; diff --git a/src/transaction/decoder/DecodedParamRow.tsx b/src/transaction/decoder/DecodedParamRow.tsx index b2b0baf..9384ea1 100644 --- a/src/transaction/decoder/DecodedParamRow.tsx +++ b/src/transaction/decoder/DecodedParamRow.tsx @@ -76,7 +76,7 @@ const DecodedParamRow: React.FC = ({ ) : paramType.baseType === "address" ? ( From 8c46eaabb18e81fdde8a64e7dcac7ef89d25e393 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sat, 6 Nov 2021 05:15:27 -0300 Subject: [PATCH 32/54] Generalize attribute type --- src/transaction/Details.tsx | 8 ++++++-- src/transaction/LogEntry.tsx | 4 ++-- src/transaction/decoder/AddressDecoder.tsx | 12 ++++++------ src/transaction/decoder/DecodedParamRow.tsx | 12 ++++++------ src/transaction/decoder/DecodedParamsTable.tsx | 8 ++++---- src/types.ts | 16 ++++++++++++++++ 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 85cb2fc..7f95594 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -29,7 +29,11 @@ import USDValue from "../components/USDValue"; import FormattedBalance from "../components/FormattedBalance"; import ETH2USDValue from "../components/ETH2USDValue"; import TokenTransferItem from "../TokenTransferItem"; -import { TransactionData, InternalOperation } from "../types"; +import { + TransactionData, + InternalOperation, + toTransactionContext, +} from "../types"; import PercentageBar from "../components/PercentageBar"; import ExternalLink from "../components/ExternalLink"; import RelativePosition from "../components/RelativePosition"; @@ -371,7 +375,7 @@ const Details: React.FC = ({ = ({ diff --git a/src/transaction/decoder/AddressDecoder.tsx b/src/transaction/decoder/AddressDecoder.tsx index a8b5edf..3e74790 100644 --- a/src/transaction/decoder/AddressDecoder.tsx +++ b/src/transaction/decoder/AddressDecoder.tsx @@ -2,27 +2,27 @@ import React from "react"; import AddressHighlighter from "../../components/AddressHighlighter"; import DecoratedAddressLink from "../../components/DecoratedAddressLink"; import Copy from "../../components/Copy"; -import { TransactionData } from "../../types"; +import { SelectedTransactionContext } from "../../types"; import { ResolvedAddresses } from "../../api/address-resolver"; type AddressDecoderProps = { r: string; - txData: TransactionData; + txContext: SelectedTransactionContext; resolvedAddresses?: ResolvedAddresses | undefined; }; const AddressDecoder: React.FC = ({ r, - txData, + txContext, resolvedAddresses, }) => (
diff --git a/src/transaction/decoder/DecodedParamRow.tsx b/src/transaction/decoder/DecodedParamRow.tsx index 9384ea1..83fe0ac 100644 --- a/src/transaction/decoder/DecodedParamRow.tsx +++ b/src/transaction/decoder/DecodedParamRow.tsx @@ -8,7 +8,7 @@ import Uint256Decoder from "./Uint256Decoder"; import AddressDecoder from "./AddressDecoder"; import BooleanDecoder from "./BooleanDecoder"; import BytesDecoder from "./BytesDecoder"; -import { TransactionData } from "../../types"; +import { SelectedTransactionContext } from "../../types"; import { ResolvedAddresses } from "../../api/address-resolver"; type DecodedParamRowProps = { @@ -16,7 +16,7 @@ type DecodedParamRowProps = { i?: number | undefined; r: any; paramType: ParamType; - txData: TransactionData; + txContext: SelectedTransactionContext; arrayElem?: number | undefined; help?: string | undefined; resolvedAddresses?: ResolvedAddresses | undefined; @@ -27,7 +27,7 @@ const DecodedParamRow: React.FC = ({ i, r, paramType, - txData, + txContext, arrayElem, help, resolvedAddresses, @@ -77,7 +77,7 @@ const DecodedParamRow: React.FC = ({ ) : paramType.baseType === "address" ? ( ) : paramType.baseType === "bool" ? ( @@ -106,7 +106,7 @@ const DecodedParamRow: React.FC = ({ i={idx} r={e} paramType={paramType.components[idx]} - txData={txData} + txContext={txContext} /> ))} {paramType.baseType === "array" && @@ -116,7 +116,7 @@ const DecodedParamRow: React.FC = ({ prefix={paramType.name ?? param_{i}} r={e} paramType={paramType.arrayChildren} - txData={txData} + txContext={txContext} arrayElem={idx} /> ))} diff --git a/src/transaction/decoder/DecodedParamsTable.tsx b/src/transaction/decoder/DecodedParamsTable.tsx index 8f4a562..136b169 100644 --- a/src/transaction/decoder/DecodedParamsTable.tsx +++ b/src/transaction/decoder/DecodedParamsTable.tsx @@ -1,14 +1,14 @@ import React from "react"; import { ParamType, Result } from "@ethersproject/abi"; import DecodedParamRow from "./DecodedParamRow"; -import { TransactionData } from "../../types"; +import { SelectedTransactionContext } from "../../types"; import { DevMethod, UserMethod } from "../../useSourcify"; import { ResolvedAddresses } from "../../api/address-resolver"; type DecodedParamsTableProps = { args: Result; paramTypes: ParamType[]; - txData: TransactionData; + txContext: SelectedTransactionContext; hasParamNames?: boolean; userMethod?: UserMethod | undefined; devMethod?: DevMethod | undefined; @@ -18,7 +18,7 @@ type DecodedParamsTableProps = { const DecodedParamsTable: React.FC = ({ args, paramTypes, - txData, + txContext, hasParamNames = true, devMethod, resolvedAddresses, @@ -49,7 +49,7 @@ const DecodedParamsTable: React.FC = ({ i={i} r={r} paramType={paramTypes[i]} - txData={txData} + txContext={txContext} help={devMethod?.params?.[paramTypes[i].name]} resolvedAddresses={resolvedAddresses} /> diff --git a/src/types.ts b/src/types.ts index f54f94a..947aa51 100644 --- a/src/types.ts +++ b/src/types.ts @@ -64,6 +64,22 @@ export type ConfirmedTransactionData = { logs: Log[]; }; +export type SelectedTransactionContext = { + from: string; + to: string | undefined; + miner: string | undefined; +}; + +export const toTransactionContext = ( + txData: TransactionData +): SelectedTransactionContext => { + return { + from: txData.from, + to: txData.to, + miner: txData.confirmedData?.miner, + }; +}; + // The VOID... export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; From 42b585bc40c54add3b75032e0156f2c0743fa1a9 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sat, 6 Nov 2021 15:54:34 -0300 Subject: [PATCH 33/54] Add input decoding to trace --- src/transaction/Details.tsx | 29 ++++------- src/transaction/TraceInput.tsx | 94 ++++++++++++++++++++++++---------- src/transaction/TraceItem.tsx | 6 +-- src/use4Bytes.ts | 30 ++++++++++- 4 files changed, 110 insertions(+), 49 deletions(-) diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 7f95594..a9f716a 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -1,9 +1,5 @@ import React, { useMemo } from "react"; -import { - TransactionDescription, - Fragment, - Interface, -} from "@ethersproject/abi"; +import { TransactionDescription } from "@ethersproject/abi"; import { BigNumber } from "@ethersproject/bignumber"; import { toUtf8String } from "@ethersproject/strings"; import { Tab } from "@headlessui/react"; @@ -40,7 +36,11 @@ import RelativePosition from "../components/RelativePosition"; import PercentagePosition from "../components/PercentagePosition"; import ModeTab from "../components/ModeTab"; import DecodedParamsTable from "./decoder/DecodedParamsTable"; -import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes"; +import { + rawInputTo4Bytes, + use4Bytes, + useTransactionDescription, +} from "../use4Bytes"; import { DevDoc, UserDoc } from "../useSourcify"; import { ResolvedAddresses } from "../api/address-resolver"; @@ -81,18 +81,11 @@ const Details: React.FC = ({ const fourBytes = txData.to !== null ? rawInputTo4Bytes(txData.data) : "0x"; const fourBytesEntry = use4Bytes(fourBytes); - const fourBytesTxDesc = useMemo(() => { - if (!fourBytesEntry) { - return fourBytesEntry; - } - if (!txData || !fourBytesEntry.signature) { - return undefined; - } - const sig = fourBytesEntry?.signature; - const functionFragment = Fragment.fromString(`function ${sig}`); - const intf = new Interface([functionFragment]); - return intf.parseTransaction({ data: txData.data, value: txData.value }); - }, [txData, fourBytesEntry]); + const fourBytesTxDesc = useTransactionDescription( + fourBytesEntry, + txData.data, + txData.value + ); const resolvedTxDesc = txDesc ?? fourBytesTxDesc; const userMethod = txDesc ? userDoc?.methods[txDesc.signature] : undefined; diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index e656d6e..f0fdd9c 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -1,12 +1,18 @@ -import React from "react"; +import React, { useState } from "react"; +import { Switch } from "@headlessui/react"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; +import DecodedParamsTable from "./decoder/DecodedParamsTable"; import { TraceEntry } from "../useErigonHooks"; -import { TransactionData } from "../types"; +import { toTransactionContext, TransactionData } from "../types"; import { ResolvedAddresses } from "../api/address-resolver"; -import { extract4Bytes, FourBytesEntry } from "../use4Bytes"; +import { + extract4Bytes, + FourBytesEntry, + useTransactionDescription, +} from "../use4Bytes"; type TraceInputProps = { t: TraceEntry; @@ -22,35 +28,69 @@ const TraceInput: React.FC = ({ resolvedAddresses, }) => { const raw4Bytes = extract4Bytes(t.input); + const fourBytes = raw4Bytes !== null ? fourBytesMap[raw4Bytes] : null; const sigText = - raw4Bytes === null - ? "" - : fourBytesMap[raw4Bytes]?.name ?? raw4Bytes; + raw4Bytes === null ? "" : fourBytes?.name ?? raw4Bytes; + const hasParams = t.input.length > 10; + + const fourBytesTxDesc = useTransactionDescription( + fourBytes, + t.input, + t.value + ); + + const [expanded, setExpanded] = useState(false); return ( -
- {t.type} - - - - - - . - - {t.value && !t.value.isZero() && ( - - {"{"}value: ETH{"}"} +
+
+ {t.type} + + + + + . + + {t.value && !t.value.isZero() && ( + + {"{"}value: ETH{"}"} + + )} + + ( + {hasParams && ( + + {expanded ? ( + [-] + ) : ( + <>[...] + )} + + )} + {(!hasParams || !expanded) && <>)} + +
+ {hasParams && expanded && fourBytesTxDesc && ( + <> +
+ +
+
)
+ )} - - ({t.input.length > 10 && <>input=[0x{t.input.slice(10)}]}) -
); }; diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index b1e2be3..aceace4 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -28,10 +28,10 @@ const TraceItem: React.FC = ({ return ( <> -
-
+
+
{!last && ( -
+
)} {t.children && ( { + const txDesc = useMemo(() => { + if (!fourBytesEntry) { + return fourBytesEntry; + } + if (!fourBytesEntry.signature || !data || !value) { + return undefined; + } + + const sig = fourBytesEntry?.signature; + const functionFragment = Fragment.fromString(`function ${sig}`); + const intf = new Interface([functionFragment]); + return intf.parseTransaction({ data, value }); + }, [fourBytesEntry, data, value]); + + return txDesc; +}; From f90d9150b82a8de3d7723324f42f87074d457c9c Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sat, 6 Nov 2021 16:14:30 -0300 Subject: [PATCH 34/54] UI fixes --- src/transaction/Trace.tsx | 2 +- src/transaction/TraceInput.tsx | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 147aa74..be7c9b9 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -37,7 +37,7 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { return (
-
+
= ({ const [expanded, setExpanded] = useState(false); return ( -
+
{t.type} @@ -66,7 +66,11 @@ const TraceInput: React.FC = ({ ( {hasParams && ( - + {expanded ? ( [-] ) : ( From 43f0ba0f8d6bcb5cf6773d11d5f4647d70d016d6 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 09:21:02 -0300 Subject: [PATCH 35/54] Remove deprecated parameters --- src/transaction/Details.tsx | 7 +------ src/transaction/LogEntry.tsx | 3 +-- src/transaction/TraceInput.tsx | 3 +-- src/transaction/decoder/DecodedParamRow.tsx | 5 ----- src/transaction/decoder/DecodedParamsTable.tsx | 4 ---- src/types.ts | 16 ---------------- 6 files changed, 3 insertions(+), 35 deletions(-) diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 51b8a63..8cf46f1 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -24,11 +24,7 @@ import USDValue from "../components/USDValue"; import FormattedBalance from "../components/FormattedBalance"; import ETH2USDValue from "../components/ETH2USDValue"; import TokenTransferItem from "../TokenTransferItem"; -import { - TransactionData, - InternalOperation, - toTransactionContext, -} from "../types"; +import { TransactionData, InternalOperation } from "../types"; import PercentageBar from "../components/PercentageBar"; import ExternalLink from "../components/ExternalLink"; import RelativePosition from "../components/RelativePosition"; @@ -353,7 +349,6 @@ const Details: React.FC = ({ = ({ diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index 603e619..367a51c 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -6,7 +6,7 @@ import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; import DecodedParamsTable from "./decoder/DecodedParamsTable"; import { TraceEntry } from "../useErigonHooks"; -import { toTransactionContext, TransactionData } from "../types"; +import { TransactionData } from "../types"; import { ResolvedAddresses } from "../api/address-resolver"; import { extract4Bytes, @@ -87,7 +87,6 @@ const TraceInput: React.FC = ({ diff --git a/src/transaction/decoder/DecodedParamRow.tsx b/src/transaction/decoder/DecodedParamRow.tsx index eb31b91..9bd64b6 100644 --- a/src/transaction/decoder/DecodedParamRow.tsx +++ b/src/transaction/decoder/DecodedParamRow.tsx @@ -8,7 +8,6 @@ import Uint256Decoder from "./Uint256Decoder"; import AddressDecoder from "./AddressDecoder"; import BooleanDecoder from "./BooleanDecoder"; import BytesDecoder from "./BytesDecoder"; -import { SelectedTransactionContext } from "../../types"; import { ResolvedAddresses } from "../../api/address-resolver"; type DecodedParamRowProps = { @@ -16,7 +15,6 @@ type DecodedParamRowProps = { i?: number | undefined; r: any; paramType: ParamType; - txContext: SelectedTransactionContext; arrayElem?: number | undefined; help?: string | undefined; resolvedAddresses?: ResolvedAddresses | undefined; @@ -27,7 +25,6 @@ const DecodedParamRow: React.FC = ({ i, r, paramType, - txContext, arrayElem, help, resolvedAddresses, @@ -105,7 +102,6 @@ const DecodedParamRow: React.FC = ({ i={idx} r={e} paramType={paramType.components[idx]} - txContext={txContext} /> ))} {paramType.baseType === "array" && @@ -115,7 +111,6 @@ const DecodedParamRow: React.FC = ({ prefix={paramType.name ?? param_{i}} r={e} paramType={paramType.arrayChildren} - txContext={txContext} arrayElem={idx} /> ))} diff --git a/src/transaction/decoder/DecodedParamsTable.tsx b/src/transaction/decoder/DecodedParamsTable.tsx index 136b169..376eee2 100644 --- a/src/transaction/decoder/DecodedParamsTable.tsx +++ b/src/transaction/decoder/DecodedParamsTable.tsx @@ -1,14 +1,12 @@ import React from "react"; import { ParamType, Result } from "@ethersproject/abi"; import DecodedParamRow from "./DecodedParamRow"; -import { SelectedTransactionContext } from "../../types"; import { DevMethod, UserMethod } from "../../useSourcify"; import { ResolvedAddresses } from "../../api/address-resolver"; type DecodedParamsTableProps = { args: Result; paramTypes: ParamType[]; - txContext: SelectedTransactionContext; hasParamNames?: boolean; userMethod?: UserMethod | undefined; devMethod?: DevMethod | undefined; @@ -18,7 +16,6 @@ type DecodedParamsTableProps = { const DecodedParamsTable: React.FC = ({ args, paramTypes, - txContext, hasParamNames = true, devMethod, resolvedAddresses, @@ -49,7 +46,6 @@ const DecodedParamsTable: React.FC = ({ i={i} r={r} paramType={paramTypes[i]} - txContext={txContext} help={devMethod?.params?.[paramTypes[i].name]} resolvedAddresses={resolvedAddresses} /> diff --git a/src/types.ts b/src/types.ts index 947aa51..f54f94a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -64,22 +64,6 @@ export type ConfirmedTransactionData = { logs: Log[]; }; -export type SelectedTransactionContext = { - from: string; - to: string | undefined; - miner: string | undefined; -}; - -export const toTransactionContext = ( - txData: TransactionData -): SelectedTransactionContext => { - return { - from: txData.from, - to: txData.to, - miner: txData.confirmedData?.miner, - }; -}; - // The VOID... export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; From 45bfe9718a494a6bca8b075f345d6cdafd181a59 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 17:35:17 -0300 Subject: [PATCH 36/54] Fix staticcall display ot traces --- src/use4Bytes.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/use4Bytes.ts b/src/use4Bytes.ts index d68bedf..20cb6d6 100644 --- a/src/use4Bytes.ts +++ b/src/use4Bytes.ts @@ -159,7 +159,11 @@ export const useTransactionDescription = ( if (!fourBytesEntry) { return fourBytesEntry; } - if (!fourBytesEntry.signature || !data || !value) { + if ( + !fourBytesEntry.signature || + data === undefined || + value === undefined + ) { return undefined; } From bf7117c1ebf4b4962083c460c850edb3de549b14 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 17:42:10 -0300 Subject: [PATCH 37/54] Add hover coloring --- src/transaction/Trace.tsx | 2 +- src/transaction/TraceInput.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index be7c9b9..36be350 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -37,7 +37,7 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { return (
-
+
= ({ const [expanded, setExpanded] = useState(false); return ( -
+
{t.type} From fc1f0fe196424617cf880bc1ab846108481e199e Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 17:46:42 -0300 Subject: [PATCH 38/54] Use higher level component --- src/transaction/Trace.tsx | 16 +++++----------- src/transaction/TraceInput.tsx | 16 +++++----------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 36be350..6d3fe71 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -1,7 +1,6 @@ import React, { useContext, useMemo } from "react"; -import AddressHighlighter from "../components/AddressHighlighter"; -import DecoratedAddressLink from "../components/DecoratedAddressLink"; import ContentFrame from "../ContentFrame"; +import TransactionAddress from "../components/TransactionAddress"; import TraceItem from "./TraceItem"; import { TransactionData } from "../types"; import { useBatch4Bytes } from "../use4Bytes"; @@ -38,15 +37,10 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => {
- - - +
diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index c1cd8a8..3ae856f 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -1,7 +1,6 @@ import React, { useState } from "react"; import { Switch } from "@headlessui/react"; -import AddressHighlighter from "../components/AddressHighlighter"; -import DecoratedAddressLink from "../components/DecoratedAddressLink"; +import TransactionAddress from "../components/TransactionAddress"; import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; import DecodedParamsTable from "./decoder/DecodedParamsTable"; @@ -46,15 +45,10 @@ const TraceInput: React.FC = ({
{t.type} - - - + . From 17cb352a1f7c80864e9da28205c455409107a682 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 17:52:29 -0300 Subject: [PATCH 39/54] Remove unnecessary nested divs --- src/transaction/Trace.tsx | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 6d3fe71..d683339 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -42,20 +42,17 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { resolvedAddresses={resolvedAddresses} />
-
-
-
- {traces?.map((t, i, a) => ( - - ))} -
+
+ {traces?.map((t, i, a) => ( + + ))}
From f1fe98965b5127fcf81ed96250e13d46d93bf9a5 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 21:07:20 -0300 Subject: [PATCH 40/54] Tweak spacing --- src/transaction/TraceInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index 3ae856f..840894e 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -77,7 +77,7 @@ const TraceInput: React.FC = ({
{hasParams && expanded && fourBytesTxDesc && ( <> -
+
Date: Mon, 8 Nov 2021 08:20:16 -0300 Subject: [PATCH 41/54] Remove unused parameter --- src/transaction/Trace.tsx | 1 - src/transaction/TraceInput.tsx | 3 --- src/transaction/TraceItem.tsx | 9 +-------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index d683339..86425d6 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -47,7 +47,6 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { ; resolvedAddresses: ResolvedAddresses | undefined; }; const TraceInput: React.FC = ({ t, - txData, fourBytesMap, resolvedAddresses, }) => { diff --git a/src/transaction/TraceItem.tsx b/src/transaction/TraceItem.tsx index aceace4..60e4d85 100644 --- a/src/transaction/TraceItem.tsx +++ b/src/transaction/TraceItem.tsx @@ -3,7 +3,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPlusSquare } from "@fortawesome/free-regular-svg-icons/faPlusSquare"; import { faMinusSquare } from "@fortawesome/free-regular-svg-icons/faMinusSquare"; import { Switch } from "@headlessui/react"; -import { TransactionData } from "../types"; import { FourBytesEntry } from "../use4Bytes"; import { TraceGroup } from "../useErigonHooks"; import { ResolvedAddresses } from "../api/address-resolver"; @@ -11,7 +10,6 @@ import TraceInput from "./TraceInput"; type TraceItemProps = { t: TraceGroup; - txData: TransactionData; last: boolean; fourBytesMap: Record; resolvedAddresses: ResolvedAddresses | undefined; @@ -19,7 +17,6 @@ type TraceItemProps = { const TraceItem: React.FC = ({ t, - txData, last, fourBytesMap, resolvedAddresses, @@ -47,7 +44,6 @@ const TraceItem: React.FC = ({ )} @@ -60,7 +56,6 @@ const TraceItem: React.FC = ({ > @@ -72,20 +67,18 @@ const TraceItem: React.FC = ({ type TraceChildrenProps = { c: TraceGroup[]; - txData: TransactionData; fourBytesMap: Record; resolvedAddresses: ResolvedAddresses | undefined; }; const TraceChildren: React.FC = React.memo( - ({ c, txData, fourBytesMap, resolvedAddresses }) => { + ({ c, fourBytesMap, resolvedAddresses }) => { return ( <> {c.map((tc, i, a) => ( Date: Mon, 8 Nov 2021 08:28:28 -0300 Subject: [PATCH 42/54] Use complete input decoder --- src/transaction/TraceInput.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index bed9090..39184b5 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -3,7 +3,7 @@ import { Switch } from "@headlessui/react"; import TransactionAddress from "../components/TransactionAddress"; import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; -import DecodedParamsTable from "./decoder/DecodedParamsTable"; +import InputDecoder from "./decoder/InputDecoder"; import { TraceEntry } from "../useErigonHooks"; import { ResolvedAddresses } from "../api/address-resolver"; import { @@ -75,10 +75,13 @@ const TraceInput: React.FC = ({ {hasParams && expanded && fourBytesTxDesc && ( <>
-
From b9a9495c61bde6dbcf1a01ab4ce9bfc735694d44 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 8 Nov 2021 09:07:52 -0300 Subject: [PATCH 43/54] Add loading indicator --- src/transaction/Trace.tsx | 42 +++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 86425d6..7e9053c 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -36,23 +36,31 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { return (
-
- -
-
- {traces?.map((t, i, a) => ( - - ))} -
+ {traces ? ( + <> +
+ +
+
+ {traces.map((t, i, a) => ( + + ))} +
+ + ) : ( +
+
+
+ )}
); From d905afd75d384079de8ed0c04ccde6d0b2b92f77 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 8 Nov 2021 14:53:23 -0300 Subject: [PATCH 44/54] Allow raw display of non-decodable inputs --- src/components/ModeTab.tsx | 15 +++++++++++---- src/transaction/TraceInput.tsx | 2 +- src/transaction/decoder/InputDecoder.tsx | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/ModeTab.tsx b/src/components/ModeTab.tsx index 14a33fd..6b7cc01 100644 --- a/src/components/ModeTab.tsx +++ b/src/components/ModeTab.tsx @@ -1,13 +1,20 @@ import React from "react"; import { Tab } from "@headlessui/react"; -const ModeTab: React.FC = ({ children }) => ( +type ModeTabProps = { + disabled?: boolean | undefined; +}; + +const ModeTab: React.FC = ({ disabled, children }) => ( - `border rounded-lg px-2 py-1 bg-gray-100 hover:bg-gray-200 hover:shadow text-xs text-gray-500 hover:text-gray-600 ${ - selected ? "border-blue-300" : "" - }` + `border rounded-lg px-2 py-1 bg-gray-100 ${ + disabled + ? "text-gray-300" + : "hover:bg-gray-200 hover:shadow text-gray-500 hover:text-gray-600" + } text-xs ${selected ? "border-blue-300" : ""}` } + disabled={disabled} > {children} diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index 39184b5..06cdedf 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -72,7 +72,7 @@ const TraceInput: React.FC = ({ {(!hasParams || !expanded) && <>)}
- {hasParams && expanded && fourBytesTxDesc && ( + {hasParams && expanded && ( <>
= ({ return ( - Decoded + Decoded Raw UTF-8 From 05aee02a433530d8fe37af9556e5641ebd702ec6 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 8 Nov 2021 14:55:41 -0300 Subject: [PATCH 45/54] Disable utf8 display when impossible to decode --- src/transaction/decoder/InputDecoder.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/transaction/decoder/InputDecoder.tsx b/src/transaction/decoder/InputDecoder.tsx index 2aee0ba..e3d041c 100644 --- a/src/transaction/decoder/InputDecoder.tsx +++ b/src/transaction/decoder/InputDecoder.tsx @@ -30,9 +30,8 @@ const InputDecoder: React.FC = ({ try { return toUtf8String(data); } catch (err) { - console.warn("Error while converting input data to string"); - console.warn(err); - return ""; + // Silently ignore on purpose + return undefined; } }, [data]); @@ -41,7 +40,7 @@ const InputDecoder: React.FC = ({ Decoded Raw - UTF-8 + UTF-8 From 445cd679d8a732842d15179e5eff65f1cf4a12fb Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 8 Nov 2021 14:57:51 -0300 Subject: [PATCH 46/54] Tweak styling of disabled tabs --- src/components/ModeTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ModeTab.tsx b/src/components/ModeTab.tsx index 6b7cc01..52ec3f9 100644 --- a/src/components/ModeTab.tsx +++ b/src/components/ModeTab.tsx @@ -10,7 +10,7 @@ const ModeTab: React.FC = ({ disabled, children }) => ( className={({ selected }) => `border rounded-lg px-2 py-1 bg-gray-100 ${ disabled - ? "text-gray-300" + ? "border-gray-100 text-gray-300 cursor-default" : "hover:bg-gray-200 hover:shadow text-gray-500 hover:text-gray-600" } text-xs ${selected ? "border-blue-300" : ""}` } From cc652eea5b36cec4c025e557165351e14069f38c Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 8 Nov 2021 15:20:13 -0300 Subject: [PATCH 47/54] Fix width --- src/transaction/Trace.tsx | 2 +- src/transaction/TraceInput.tsx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/transaction/Trace.tsx b/src/transaction/Trace.tsx index 7e9053c..5002391 100644 --- a/src/transaction/Trace.tsx +++ b/src/transaction/Trace.tsx @@ -44,7 +44,7 @@ const Trace: React.FC = ({ txData, resolvedAddresses }) => { resolvedAddresses={resolvedAddresses} />
-
+
{traces.map((t, i, a) => ( = ({ const [expanded, setExpanded] = useState(false); return ( -
+
{t.type} From 8bfe34850d6fe99d85100912c7ae09cceb58ad0c Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Fri, 19 Nov 2021 15:39:53 -0300 Subject: [PATCH 48/54] Dont try to parse method selector for create/create2 traces --- src/transaction/TraceInput.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index 3e6891a..e78ba2b 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -51,8 +51,12 @@ const TraceInput: React.FC = ({ resolvedAddresses={resolvedAddresses} /> - . - + {t.type !== "CREATE" && t.type !== "CREATE2" && ( + <> + . + + + )} {t.value && !t.value.isZero() && ( {"{"}value: ETH{"}"} From a985830c74bf55954fe3e5d39c93933e334a8ce3 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Fri, 19 Nov 2021 17:26:57 -0300 Subject: [PATCH 49/54] Simplified display of create/create2 traces --- src/transaction/TraceInput.tsx | 44 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index e78ba2b..2a502f4 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -55,30 +55,30 @@ const TraceInput: React.FC = ({ <> . + {t.value && !t.value.isZero() && ( + + {"{"}value: ETH{"}"} + + )} + + ( + {hasParams && ( + + {expanded ? ( + [-] + ) : ( + <>[...] + )} + + )} + {(!hasParams || !expanded) && <>)} + )} - {t.value && !t.value.isZero() && ( - - {"{"}value: ETH{"}"} - - )} - - ( - {hasParams && ( - - {expanded ? ( - [-] - ) : ( - <>[...] - )} - - )} - {(!hasParams || !expanded) && <>)} -
{hasParams && expanded && ( <> From 087b5319051aae1940e532ebce43244fb326bf62 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 21 Nov 2021 08:52:37 -0300 Subject: [PATCH 50/54] Add selfdestruct support --- src/transaction/TraceInput.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index 2a502f4..dac3b5d 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -1,5 +1,8 @@ import React, { useState } from "react"; import { Switch } from "@headlessui/react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faBomb } from "@fortawesome/free-solid-svg-icons/faBomb"; +import { faArrowRight } from "@fortawesome/free-solid-svg-icons/faArrowRight"; import TransactionAddress from "../components/TransactionAddress"; import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; @@ -45,6 +48,16 @@ const TraceInput: React.FC = ({ >
{t.type} + {t.type === "SELFDESTRUCT" && ( + <> + + + + + + + + )} Date: Sun, 21 Nov 2021 09:04:08 -0300 Subject: [PATCH 51/54] Fix ERC resolver for tokens with empty name/symbol --- src/api/address-resolver/ERCTokenResolver.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/api/address-resolver/ERCTokenResolver.ts b/src/api/address-resolver/ERCTokenResolver.ts index 02625dc..f087ec6 100644 --- a/src/api/address-resolver/ERCTokenResolver.ts +++ b/src/api/address-resolver/ERCTokenResolver.ts @@ -11,11 +11,17 @@ export class ERCTokenResolver implements IAddressResolver { ): Promise { const erc20Contract = new Contract(address, erc20, provider); try { - const [name, symbol, decimals] = await Promise.all([ + const [name, symbol, decimals] = (await Promise.all([ erc20Contract.name(), erc20Contract.symbol(), erc20Contract.decimals(), - ]); + ])) as [string, string, number]; + + // Prevent faulty tokens with empty name/symbol + if (!name.trim() || !symbol.trim()) { + return undefined; + } + return { name, symbol, From 637ff5c9d859dd111585c8005131acac4562a6ff Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 22 Nov 2021 14:16:33 -0300 Subject: [PATCH 52/54] Fix selfdestruct display --- src/transaction/TraceInput.tsx | 77 ++++++++++++++++------------------ 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index dac3b5d..667977e 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -2,7 +2,6 @@ import React, { useState } from "react"; import { Switch } from "@headlessui/react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBomb } from "@fortawesome/free-solid-svg-icons/faBomb"; -import { faArrowRight } from "@fortawesome/free-solid-svg-icons/faArrowRight"; import TransactionAddress from "../components/TransactionAddress"; import FormattedBalance from "../components/FormattedBalance"; import FunctionSignature from "./FunctionSignature"; @@ -48,48 +47,46 @@ const TraceInput: React.FC = ({ >
{t.type} - {t.type === "SELFDESTRUCT" && ( + {t.type === "SELFDESTRUCT" ? ( + + + + ) : ( <> - - + + - - - - - )} - - - - {t.type !== "CREATE" && t.type !== "CREATE2" && ( - <> - . - - {t.value && !t.value.isZero() && ( - - {"{"}value: ETH{"}"} - - )} - - ( - {hasParams && ( - - {expanded ? ( - [-] - ) : ( - <>[...] + {t.type !== "CREATE" && t.type !== "CREATE2" && ( + <> + . + + {t.value && !t.value.isZero() && ( + + {"{"}value: ETH{"}"} + + )} + + ( + {hasParams && ( + + {expanded ? ( + [-] + ) : ( + <>[...] + )} + )} - - )} - {(!hasParams || !expanded) && <>)} - + {(!hasParams || !expanded) && <>)} + + + )} )}
From ed79a7a72f9d17098f252579cedc6e1e9a9b9f27 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 22 Nov 2021 14:25:18 -0300 Subject: [PATCH 53/54] Normalize function names to lower capital --- src/use4Bytes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/use4Bytes.ts b/src/use4Bytes.ts index 20cb6d6..3cf3f27 100644 --- a/src/use4Bytes.ts +++ b/src/use4Bytes.ts @@ -16,7 +16,7 @@ export type FourBytesEntry = { export type FourBytesMap = Record; const simpleTransfer: FourBytesEntry = { - name: "Transfer", + name: "transfer", signature: undefined, }; From 3c20cf6810155a0c8e5b64fa167a0effc77251d8 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 22 Nov 2021 14:29:31 -0300 Subject: [PATCH 54/54] Increment required API level (because of ots_traceTransaction) --- src/params.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/params.ts b/src/params.ts index 2bfd757..5c95cfa 100644 --- a/src/params.ts +++ b/src/params.ts @@ -1,3 +1,3 @@ -export const MIN_API_LEVEL = 2; +export const MIN_API_LEVEL = 3; export const PAGE_SIZE = 25;