From 1b9f26a3f0b92a1d607f9e574444a8aa12420aa8 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 26 Oct 2021 22:10:37 -0300 Subject: [PATCH 01/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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/94] 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 74a9b05c04e5d524fd0bc07d9220a79c6920cf07 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 1 Nov 2021 15:37:10 -0300 Subject: [PATCH 25/94] Typo fix --- src/url.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/url.ts b/src/url.ts index 4639738..647fc42 100644 --- a/src/url.ts +++ b/src/url.ts @@ -38,7 +38,7 @@ const resolveSourcifySource = (source: SourcifySource) => { return sourcifyHttpRepoPrefix; } - throw new Error(`Unknown Sourcify intergration source code: ${source}`); + throw new Error(`Unknown Sourcify integration source code: ${source}`); }; export const sourcifyMetadata = ( From 2dd4850eb019b5bcc60330243449e66339ba7b96 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 1 Nov 2021 16:17:48 -0300 Subject: [PATCH 26/94] Start using JsonRpcBatchProvider from ethers instead of the regular one to optimize for big txs --- src/useProvider.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/useProvider.ts b/src/useProvider.ts index 7f89f36..b189b7f 100644 --- a/src/useProvider.ts +++ b/src/useProvider.ts @@ -1,5 +1,9 @@ import { useEffect, useState } from "react"; -import { JsonRpcProvider, WebSocketProvider } from "@ethersproject/providers"; +import { + JsonRpcProvider, + JsonRpcBatchProvider, + WebSocketProvider, +} from "@ethersproject/providers"; import { ConnectionStatus } from "./types"; import { MIN_API_LEVEL } from "./params"; @@ -35,7 +39,7 @@ export const useProvider = ( if (erigonURL?.startsWith("ws://") || erigonURL?.startsWith("wss://")) { provider = new WebSocketProvider(erigonURL); } else { - provider = new JsonRpcProvider(erigonURL); + provider = new JsonRpcBatchProvider(erigonURL); } // Check if it is at least a regular ETH node From c4615e47bf11ac66290fce900f55a1102fbcf689 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 1 Nov 2021 17:09:47 -0300 Subject: [PATCH 27/94] 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 28/94] 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 f2fbab36a6b1f5c72623d47201d7ef432baa36ea Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 2 Nov 2021 03:30:16 -0300 Subject: [PATCH 29/94] Initial implementation of hardcoded address resolver with Uniswap V1/2/3 main contracts as a bootstrap test --- .../HardcodedAddressResolver.ts | 22 ++++++++ .../hardcoded-addresses/1.json | 7 +++ src/api/address-resolver/index.ts | 5 ++ src/components/PlainString.tsx | 53 +++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 src/api/address-resolver/HardcodedAddressResolver.ts create mode 100644 src/api/address-resolver/hardcoded-addresses/1.json create mode 100644 src/components/PlainString.tsx diff --git a/src/api/address-resolver/HardcodedAddressResolver.ts b/src/api/address-resolver/HardcodedAddressResolver.ts new file mode 100644 index 0000000..42d1102 --- /dev/null +++ b/src/api/address-resolver/HardcodedAddressResolver.ts @@ -0,0 +1,22 @@ +import { BaseProvider } from "@ethersproject/providers"; +import { IAddressResolver } from "./address-resolver"; + +type HardcodedAddressMap = Record; + +export class HardcodedAddressResolver implements IAddressResolver { + async resolveAddress( + provider: BaseProvider, + address: string + ): Promise { + try { + const addressMap: HardcodedAddressMap = await import( + `./hardcoded-addresses/${provider.network.chainId}.json` + ); + + return addressMap[address]; + } catch (err) { + // Ignore on purpose + return undefined; + } + } +} diff --git a/src/api/address-resolver/hardcoded-addresses/1.json b/src/api/address-resolver/hardcoded-addresses/1.json new file mode 100644 index 0000000..73c949d --- /dev/null +++ b/src/api/address-resolver/hardcoded-addresses/1.json @@ -0,0 +1,7 @@ +{ + "0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95": "Uniswap V1: Factory", + "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f": "Uniswap V2: Factory", + "0xf164fC0Ec4E93095b804a4795bBe1e041497b92a": "Uniswap V2: Router 1", + "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D": "Uniswap V2: Router 2", + "0x1F98431c8aD98523631AE4a59f267346ea31F984": "Uniswap V3: Router" +} \ No newline at end of file diff --git a/src/api/address-resolver/index.ts b/src/api/address-resolver/index.ts index dc72a9f..f1514be 100644 --- a/src/api/address-resolver/index.ts +++ b/src/api/address-resolver/index.ts @@ -1,5 +1,6 @@ import { BaseProvider } from "@ethersproject/providers"; import { ensRenderer } from "../../components/ENSName"; +import { plainStringRenderer } from "../../components/PlainString"; import { tokenRenderer } from "../../components/TokenName"; import { IAddressResolver, ResolvedAddressRenderer } from "./address-resolver"; import { @@ -8,16 +9,19 @@ import { } from "./CompositeAddressResolver"; import { ENSAddressResolver } from "./ENSAddressResolver"; import { ERCTokenResolver } from "./ERCTokenResolver"; +import { HardcodedAddressResolver } from "./HardcodedAddressResolver"; export type ResolvedAddresses = Record>; // Create and configure the main resolver export const ensResolver = new ENSAddressResolver(); export const ercTokenResolver = new ERCTokenResolver(); +export const hardcodedResolver = new HardcodedAddressResolver(); const _mainResolver = new CompositeAddressResolver(); _mainResolver.addResolver(ensResolver); _mainResolver.addResolver(ercTokenResolver); +_mainResolver.addResolver(hardcodedResolver); export const mainResolver: IAddressResolver> = _mainResolver; @@ -28,6 +32,7 @@ export const resolverRendererRegistry = new Map< >(); resolverRendererRegistry.set(ensResolver, ensRenderer); resolverRendererRegistry.set(ercTokenResolver, tokenRenderer); +resolverRendererRegistry.set(hardcodedResolver, plainStringRenderer); // TODO: implement progressive resolving export const batchPopulate = async ( diff --git a/src/components/PlainString.tsx b/src/components/PlainString.tsx new file mode 100644 index 0000000..5b891bf --- /dev/null +++ b/src/components/PlainString.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { NavLink } from "react-router-dom"; +import { ResolvedAddressRenderer } from "../api/address-resolver/address-resolver"; + +type PlainStringProps = { + address: string; + name: string; + linkable: boolean; + dontOverrideColors: boolean | undefined; +}; + +const PlainString: React.FC = ({ + address, + name, + linkable, + dontOverrideColors, +}) => { + if (linkable) { + return ( + + {name} + + ); + } + + return ( + + {name} + + ); +}; + +export const plainStringRenderer: ResolvedAddressRenderer = ( + address, + resolvedAddress, + linkable, + dontOverrideColors +) => ( + +); + +export default PlainString; From 7daffbca263c2e30576cc64109c0bafbf0ecc11e Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 2 Nov 2021 03:36:30 -0300 Subject: [PATCH 30/94] Add tornado cash proxy --- src/api/address-resolver/hardcoded-addresses/1.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/address-resolver/hardcoded-addresses/1.json b/src/api/address-resolver/hardcoded-addresses/1.json index 73c949d..1eb4ec0 100644 --- a/src/api/address-resolver/hardcoded-addresses/1.json +++ b/src/api/address-resolver/hardcoded-addresses/1.json @@ -1,4 +1,5 @@ { + "0x722122dF12D4e14e13Ac3b6895a86e84145b6967": "Tornado Cash: Proxy", "0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95": "Uniswap V1: Factory", "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f": "Uniswap V2: Factory", "0xf164fC0Ec4E93095b804a4795bBe1e041497b92a": "Uniswap V2: Router 1", From 2dd055755efdf2d59b615246878ae406e4519828 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 2 Nov 2021 03:48:42 -0300 Subject: [PATCH 31/94] Add gitcoin donation checkout address --- src/api/address-resolver/hardcoded-addresses/1.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/address-resolver/hardcoded-addresses/1.json b/src/api/address-resolver/hardcoded-addresses/1.json index 1eb4ec0..7ae2f9b 100644 --- a/src/api/address-resolver/hardcoded-addresses/1.json +++ b/src/api/address-resolver/hardcoded-addresses/1.json @@ -1,4 +1,5 @@ { + "0x7d655c57f71464B6f83811C55D84009Cd9f5221C": "Gitcoin: Bulk Checkout", "0x722122dF12D4e14e13Ac3b6895a86e84145b6967": "Tornado Cash: Proxy", "0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95": "Uniswap V1: Factory", "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f": "Uniswap V2: Factory", From fd5b884caa674b9ee354cd8acab54bdc0de28831 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 2 Nov 2021 21:24:19 -0300 Subject: [PATCH 32/94] 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 33/94] 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 34/94] 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 d773a442a43a879ef3892203569746c1c2f48b24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Nov 2021 11:55:27 +0000 Subject: [PATCH 35/94] Bump @testing-library/jest-dom from 5.14.1 to 5.15.0 (#111) --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index ef51571..ce287b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/react-fontawesome": "^0.1.16", "@headlessui/react": "^1.4.1", - "@testing-library/jest-dom": "^5.14.1", + "@testing-library/jest-dom": "^5.15.0", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "@types/jest": "^26.0.24", @@ -2887,9 +2887,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", - "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.15.0.tgz", + "integrity": "sha512-lOMuQidnL1tWHLEWIhL6UvSZC1Qt3OkNe1khvi2h6xFiqpe5O8arYs46OU0qyUGq0cSTbroQyMktYNXu3a7sAA==", "dependencies": { "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", @@ -21609,9 +21609,9 @@ } }, "@testing-library/jest-dom": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", - "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.15.0.tgz", + "integrity": "sha512-lOMuQidnL1tWHLEWIhL6UvSZC1Qt3OkNe1khvi2h6xFiqpe5O8arYs46OU0qyUGq0cSTbroQyMktYNXu3a7sAA==", "requires": { "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", diff --git a/package.json b/package.json index d301e67..ab9241d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/react-fontawesome": "^0.1.16", "@headlessui/react": "^1.4.1", - "@testing-library/jest-dom": "^5.14.1", + "@testing-library/jest-dom": "^5.15.0", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "@types/jest": "^26.0.24", From d99a9a24c16eef228d1edd6266876046c4d01b28 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 3 Nov 2021 09:01:22 -0300 Subject: [PATCH 36/94] Add GR11 matching payout address to the hardcoded list --- src/api/address-resolver/hardcoded-addresses/1.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/address-resolver/hardcoded-addresses/1.json b/src/api/address-resolver/hardcoded-addresses/1.json index 7ae2f9b..a9ae33d 100644 --- a/src/api/address-resolver/hardcoded-addresses/1.json +++ b/src/api/address-resolver/hardcoded-addresses/1.json @@ -1,5 +1,6 @@ { "0x7d655c57f71464B6f83811C55D84009Cd9f5221C": "Gitcoin: Bulk Checkout", + "0x0EbD2E2130b73107d0C45fF2E16c93E7e2e10e3a": "Gitcoin: GR11 Matching Payout", "0x722122dF12D4e14e13Ac3b6895a86e84145b6967": "Tornado Cash: Proxy", "0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95": "Uniswap V1: Factory", "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f": "Uniswap V2: Factory", From 03e48f678cac95b83b1d52085d34fbf9cf5de8f2 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 3 Nov 2021 09:07:38 -0300 Subject: [PATCH 37/94] Add missing resolvers on token transferred section --- src/TokenTransferItem.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TokenTransferItem.tsx b/src/TokenTransferItem.tsx index 03fa198..e7c65c4 100644 --- a/src/TokenTransferItem.tsx +++ b/src/TokenTransferItem.tsx @@ -40,6 +40,7 @@ const TokenTransferItem: React.FC = ({ addressCtx={AddressContext.FROM} txFrom={t.from === txData.from} txTo={t.from === txData.to} + resolvedAddresses={resolvedAddresses} />
@@ -51,6 +52,7 @@ const TokenTransferItem: React.FC = ({ addressCtx={AddressContext.TO} txFrom={t.to === txData.from} txTo={t.to === txData.to} + resolvedAddresses={resolvedAddresses} />
From 8efe230bc8e4529d6dfdd2fc0fc7ccacef12b39a Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 3 Nov 2021 09:14:52 -0300 Subject: [PATCH 38/94] Add missing resolvers support on decoded inputs and logs table --- src/transaction/Details.tsx | 1 + src/transaction/LogEntry.tsx | 1 + src/transaction/decoder/AddressDecoder.tsx | 9 ++++++++- src/transaction/decoder/DecodedParamRow.tsx | 9 ++++++++- src/transaction/decoder/DecodedParamsTable.tsx | 4 ++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 9c9e29d..85cb2fc 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -375,6 +375,7 @@ const Details: React.FC = ({ hasParamNames={resolvedTxDesc === txDesc} userMethod={userMethod} devMethod={devMethod} + resolvedAddresses={resolvedAddresses} /> )} diff --git a/src/transaction/LogEntry.tsx b/src/transaction/LogEntry.tsx index 2993e16..4e89ffd 100644 --- a/src/transaction/LogEntry.tsx +++ b/src/transaction/LogEntry.tsx @@ -114,6 +114,7 @@ const LogEntry: React.FC = ({ paramTypes={resolvedLogDesc.eventFragment.inputs} txData={txData} hasParamNames={resolvedLogDesc === logDesc} + resolvedAddresses={resolvedAddresses} />
diff --git a/src/transaction/decoder/AddressDecoder.tsx b/src/transaction/decoder/AddressDecoder.tsx index ee6369a..45fb30c 100644 --- a/src/transaction/decoder/AddressDecoder.tsx +++ b/src/transaction/decoder/AddressDecoder.tsx @@ -3,13 +3,19 @@ import AddressHighlighter from "../../components/AddressHighlighter"; import DecoratedAddressLink from "../../components/DecoratedAddressLink"; import Copy from "../../components/Copy"; import { TransactionData } from "../../types"; +import { ResolvedAddresses } from "../../api/address-resolver"; type AddressDecoderProps = { r: any; txData: TransactionData; + resolvedAddresses?: ResolvedAddresses | undefined; }; -const AddressDecoder: React.FC = ({ r, txData }) => ( +const AddressDecoder: React.FC = ({ + r, + txData, + resolvedAddresses, +}) => (
= ({ r, txData }) => ( miner={r.toString() === txData.confirmedData?.miner} txFrom={r.toString() === txData.from} txTo={r.toString() === txData.to} + resolvedAddresses={resolvedAddresses} /> diff --git a/src/transaction/decoder/DecodedParamRow.tsx b/src/transaction/decoder/DecodedParamRow.tsx index fed9ecb..b2b0baf 100644 --- a/src/transaction/decoder/DecodedParamRow.tsx +++ b/src/transaction/decoder/DecodedParamRow.tsx @@ -9,6 +9,7 @@ import AddressDecoder from "./AddressDecoder"; import BooleanDecoder from "./BooleanDecoder"; import BytesDecoder from "./BytesDecoder"; import { TransactionData } from "../../types"; +import { ResolvedAddresses } from "../../api/address-resolver"; type DecodedParamRowProps = { prefix?: ReactNode; @@ -18,6 +19,7 @@ type DecodedParamRowProps = { txData: TransactionData; arrayElem?: number | undefined; help?: string | undefined; + resolvedAddresses?: ResolvedAddresses | undefined; }; const DecodedParamRow: React.FC = ({ @@ -28,6 +30,7 @@ const DecodedParamRow: React.FC = ({ txData, arrayElem, help, + resolvedAddresses, }) => { const [showHelp, setShowHelp] = useState(false); @@ -72,7 +75,11 @@ const DecodedParamRow: React.FC = ({ {paramType.baseType === "uint256" ? ( ) : paramType.baseType === "address" ? ( - + ) : paramType.baseType === "bool" ? ( ) : paramType.baseType === "bytes" ? ( diff --git a/src/transaction/decoder/DecodedParamsTable.tsx b/src/transaction/decoder/DecodedParamsTable.tsx index f7daee5..8f4a562 100644 --- a/src/transaction/decoder/DecodedParamsTable.tsx +++ b/src/transaction/decoder/DecodedParamsTable.tsx @@ -3,6 +3,7 @@ import { ParamType, Result } from "@ethersproject/abi"; import DecodedParamRow from "./DecodedParamRow"; import { TransactionData } from "../../types"; import { DevMethod, UserMethod } from "../../useSourcify"; +import { ResolvedAddresses } from "../../api/address-resolver"; type DecodedParamsTableProps = { args: Result; @@ -11,6 +12,7 @@ type DecodedParamsTableProps = { hasParamNames?: boolean; userMethod?: UserMethod | undefined; devMethod?: DevMethod | undefined; + resolvedAddresses?: ResolvedAddresses | undefined; }; const DecodedParamsTable: React.FC = ({ @@ -19,6 +21,7 @@ const DecodedParamsTable: React.FC = ({ txData, hasParamNames = true, devMethod, + resolvedAddresses, }) => ( @@ -48,6 +51,7 @@ const DecodedParamsTable: React.FC = ({ paramType={paramTypes[i]} txData={txData} help={devMethod?.params?.[paramTypes[i].name]} + resolvedAddresses={resolvedAddresses} /> ))} From e2ba28b64e4d48a5996a9365fd12b3cbdca6d54f Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 4 Nov 2021 15:59:17 -0300 Subject: [PATCH 39/94] Add previous GR round payout addresses --- src/api/address-resolver/hardcoded-addresses/1.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/address-resolver/hardcoded-addresses/1.json b/src/api/address-resolver/hardcoded-addresses/1.json index a9ae33d..072a2c0 100644 --- a/src/api/address-resolver/hardcoded-addresses/1.json +++ b/src/api/address-resolver/hardcoded-addresses/1.json @@ -1,5 +1,8 @@ { "0x7d655c57f71464B6f83811C55D84009Cd9f5221C": "Gitcoin: Bulk Checkout", + "0xf2354570bE2fB420832Fb7Ff6ff0AE0dF80CF2c6": "Gitcoin: GR8 Matching Payout", + "0x3342E3737732D879743f2682A3953a730ae4F47C": "Gitcoin: GR9 Matching Payout", + "0x3ebAFfe01513164e638480404c651E885cCA0AA4": "Gitcoin: GR10 Matching Payout", "0x0EbD2E2130b73107d0C45fF2E16c93E7e2e10e3a": "Gitcoin: GR11 Matching Payout", "0x722122dF12D4e14e13Ac3b6895a86e84145b6967": "Tornado Cash: Proxy", "0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95": "Uniswap V1: Factory", From fd3173c3a6f88f0e12d532730fbf61d11cc19e91 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sat, 6 Nov 2021 02:12:37 -0300 Subject: [PATCH 40/94] 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 41/94] 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 42/94] 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 43/94] 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 44/94] 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 b723182ad3d6face2b9ec3596e62083d41c44980 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 08:21:56 -0300 Subject: [PATCH 45/94] Extract utility component TransactionAddress --- src/Transaction.tsx | 99 +++++++++++---------- src/components/TransactionAddress.tsx | 34 +++++++ src/transaction/Details.tsx | 39 +++----- src/transaction/LogEntry.tsx | 16 ++-- src/transaction/decoder/AddressDecoder.tsx | 19 ++-- src/transaction/decoder/DecodedParamRow.tsx | 6 +- src/useSelectedTransaction.ts | 9 ++ 7 files changed, 117 insertions(+), 105 deletions(-) create mode 100644 src/components/TransactionAddress.tsx create mode 100644 src/useSelectedTransaction.ts diff --git a/src/Transaction.tsx b/src/Transaction.tsx index 7107b32..bd4cbaa 100644 --- a/src/Transaction.tsx +++ b/src/Transaction.tsx @@ -15,6 +15,7 @@ import { transactionDataCollector, useResolvedAddresses, } from "./useResolvedAddresses"; +import { SelectedTransactionContext } from "./useSelectedTransaction"; const Details = React.lazy( () => @@ -76,54 +77,56 @@ const Transaction: React.FC = () => { const txDesc = useTransactionDescription(metadata, txData); return ( - - Transaction Details - {txData === null && ( - -
- Transaction {txhash} not found. -
-
- )} - {txData && ( - - - - Overview - {txData.confirmedData?.blockNumber !== undefined && ( - - Logs - {txData && ` (${txData.confirmedData?.logs?.length ?? 0})`} - - )} - - - - - -
- - - - - - - - )} - + + + Transaction Details + {txData === null && ( + +
+ Transaction {txhash} not found. +
+
+ )} + {txData && ( + + + + Overview + {txData.confirmedData?.blockNumber !== undefined && ( + + Logs + {txData && ` (${txData.confirmedData?.logs?.length ?? 0})`} + + )} + + + + + +
+ + + + + + + + )} + + ); }; diff --git a/src/components/TransactionAddress.tsx b/src/components/TransactionAddress.tsx new file mode 100644 index 0000000..8db3df4 --- /dev/null +++ b/src/components/TransactionAddress.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import AddressHighlighter from "./AddressHighlighter"; +import DecoratedAddressLink from "./DecoratedAddressLink"; +import { ResolvedAddresses } from "../api/address-resolver"; +import { useSelectedTransaction } from "../useSelectedTransaction"; + +type TransactionAddressProps = { + address: string; + resolvedAddresses: ResolvedAddresses | undefined; +}; + +const TransactionAddress: React.FC = ({ + address, + resolvedAddresses, +}) => { + const txData = useSelectedTransaction(); + // TODO: push down creation coloring logic into DecoratedAddressLink + const creation = address === txData?.confirmedData?.createdContractAddress; + + return ( + + + + ); +}; + +export default TransactionAddress; diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 85cb2fc..3df374a 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -15,8 +15,7 @@ import ContentFrame from "../ContentFrame"; import InfoRow from "../components/InfoRow"; import BlockLink from "../components/BlockLink"; import BlockConfirmations from "../components/BlockConfirmations"; -import AddressHighlighter from "../components/AddressHighlighter"; -import DecoratedAddressLink from "../components/DecoratedAddressLink"; +import TransactionAddress from "../components/TransactionAddress"; import Copy from "../components/Copy"; import Nonce from "../components/Nonce"; import Timestamp from "../components/Timestamp"; @@ -152,14 +151,10 @@ const Details: React.FC = ({
- - - +
@@ -170,14 +165,10 @@ const Details: React.FC = ({ {txData.to ? (
- - - +
) : txData.confirmedData === undefined ? ( @@ -186,16 +177,10 @@ const Details: React.FC = ({ ) : (
- - - + resolvedAddresses={resolvedAddresses} + />
)} diff --git a/src/transaction/LogEntry.tsx b/src/transaction/LogEntry.tsx index 4e89ffd..d8bf1ea 100644 --- a/src/transaction/LogEntry.tsx +++ b/src/transaction/LogEntry.tsx @@ -2,8 +2,7 @@ import React, { useMemo } from "react"; import { Log } from "@ethersproject/abstract-provider"; import { Fragment, Interface, LogDescription } from "@ethersproject/abi"; import { Tab } from "@headlessui/react"; -import AddressHighlighter from "../components/AddressHighlighter"; -import DecoratedAddressLink from "../components/DecoratedAddressLink"; +import TransactionAddress from "../components/TransactionAddress"; import Copy from "../components/Copy"; import ModeTab from "../components/ModeTab"; import DecodedParamsTable from "./decoder/DecodedParamsTable"; @@ -63,15 +62,10 @@ const LogEntry: React.FC = ({
Address
- - - +
diff --git a/src/transaction/decoder/AddressDecoder.tsx b/src/transaction/decoder/AddressDecoder.tsx index 45fb30c..ae43ee1 100644 --- a/src/transaction/decoder/AddressDecoder.tsx +++ b/src/transaction/decoder/AddressDecoder.tsx @@ -1,31 +1,22 @@ import React from "react"; -import AddressHighlighter from "../../components/AddressHighlighter"; -import DecoratedAddressLink from "../../components/DecoratedAddressLink"; import Copy from "../../components/Copy"; -import { TransactionData } from "../../types"; import { ResolvedAddresses } from "../../api/address-resolver"; +import TransactionAddress from "../../components/TransactionAddress"; type AddressDecoderProps = { r: any; - txData: TransactionData; resolvedAddresses?: ResolvedAddresses | undefined; }; const AddressDecoder: React.FC = ({ r, - txData, resolvedAddresses, }) => (
- - - +
); diff --git a/src/transaction/decoder/DecodedParamRow.tsx b/src/transaction/decoder/DecodedParamRow.tsx index b2b0baf..677ceab 100644 --- a/src/transaction/decoder/DecodedParamRow.tsx +++ b/src/transaction/decoder/DecodedParamRow.tsx @@ -75,11 +75,7 @@ const DecodedParamRow: React.FC = ({ {paramType.baseType === "uint256" ? ( ) : paramType.baseType === "address" ? ( - + ) : paramType.baseType === "bool" ? ( ) : paramType.baseType === "bytes" ? ( diff --git a/src/useSelectedTransaction.ts b/src/useSelectedTransaction.ts new file mode 100644 index 0000000..8676a53 --- /dev/null +++ b/src/useSelectedTransaction.ts @@ -0,0 +1,9 @@ +import { createContext, useContext } from "react"; +import { TransactionData } from "./types"; + +export const SelectedTransactionContext = createContext< + TransactionData | null | undefined +>(undefined); + +export const useSelectedTransaction = () => + useContext(SelectedTransactionContext); From 128c70b972cb60136428a428f0793fbb0fcef304 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sun, 7 Nov 2021 08:56:12 -0300 Subject: [PATCH 46/94] Replace component --- src/TokenTransferItem.tsx | 41 ++++++++++----------------- src/components/TransactionAddress.tsx | 4 +++ 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/TokenTransferItem.tsx b/src/TokenTransferItem.tsx index e7c65c4..d28a538 100644 --- a/src/TokenTransferItem.tsx +++ b/src/TokenTransferItem.tsx @@ -1,9 +1,8 @@ import React from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCaretRight } from "@fortawesome/free-solid-svg-icons/faCaretRight"; -import AddressHighlighter from "./components/AddressHighlighter"; +import TransactionAddress from "./components/TransactionAddress"; import ValueHighlighter from "./components/ValueHighlighter"; -import DecoratedAddressLink from "./components/DecoratedAddressLink"; import FormattedBalance from "./components/FormattedBalance"; import { AddressContext, @@ -34,27 +33,19 @@ const TokenTransferItem: React.FC = ({
From - - - +
To - - - +
For @@ -66,12 +57,10 @@ const TokenTransferItem: React.FC = ({ /> - - - +
diff --git a/src/components/TransactionAddress.tsx b/src/components/TransactionAddress.tsx index 8db3df4..1595ef0 100644 --- a/src/components/TransactionAddress.tsx +++ b/src/components/TransactionAddress.tsx @@ -3,14 +3,17 @@ import AddressHighlighter from "./AddressHighlighter"; import DecoratedAddressLink from "./DecoratedAddressLink"; import { ResolvedAddresses } from "../api/address-resolver"; import { useSelectedTransaction } from "../useSelectedTransaction"; +import { AddressContext } from "../types"; type TransactionAddressProps = { address: string; + addressCtx?: AddressContext | undefined; resolvedAddresses: ResolvedAddresses | undefined; }; const TransactionAddress: React.FC = ({ address, + addressCtx, resolvedAddresses, }) => { const txData = useSelectedTransaction(); @@ -21,6 +24,7 @@ const TransactionAddress: React.FC = ({ Date: Sun, 7 Nov 2021 09:21:02 -0300 Subject: [PATCH 47/94] 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 48/94] 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 49/94] 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 50/94] 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 51/94] 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 52/94] 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 07:49:30 -0300 Subject: [PATCH 53/94] Extract InputDecoder component --- src/transaction/Details.tsx | 56 ++++-------------- src/transaction/decoder/InputDecoder.tsx | 75 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 src/transaction/decoder/InputDecoder.tsx diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 3df374a..b6246b2 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -6,7 +6,6 @@ import { } from "@ethersproject/abi"; import { BigNumber } from "@ethersproject/bignumber"; import { toUtf8String } from "@ethersproject/strings"; -import { Tab } from "@headlessui/react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCheckCircle } from "@fortawesome/free-solid-svg-icons/faCheckCircle"; import { faCube } from "@fortawesome/free-solid-svg-icons/faCube"; @@ -33,8 +32,7 @@ import PercentageBar from "../components/PercentageBar"; import ExternalLink from "../components/ExternalLink"; import RelativePosition from "../components/RelativePosition"; import PercentagePosition from "../components/PercentagePosition"; -import ModeTab from "../components/ModeTab"; -import DecodedParamsTable from "./decoder/DecodedParamsTable"; +import InputDecoder from "./decoder/InputDecoder"; import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes"; import { DevDoc, UserDoc } from "../useSourcify"; import { ResolvedAddresses } from "../api/address-resolver"; @@ -338,48 +336,16 @@ const Details: React.FC = ({ )} - - - Decoded - Raw - UTF-8 - - - - {fourBytes === "0x" ? ( - <>No parameters - ) : resolvedTxDesc === undefined ? ( - <>Waiting for data... - ) : resolvedTxDesc === null ? ( - <>Can't decode data - ) : ( - - )} - - -