From 46edf8ae929a5bdfbec5eb1e9a39792bf6f039d4 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Fri, 2 Jul 2021 21:40:02 -0300 Subject: [PATCH] Add reverse ENS resolution on block transactions list --- src/BlockTransactions.tsx | 47 +++++++++++++++++++++++++++-- src/components/Address.tsx | 12 +++++--- src/components/AddressOrENSName.tsx | 37 +++++++++++++++++++++++ src/components/ENSName.tsx | 25 +++++++++++++++ src/components/ENSNameLink.tsx | 27 +++++++++++++++++ src/components/ensLogo.svg | 1 + src/search/TransactionItem.tsx | 36 +++++++++++++--------- src/types.ts | 4 +++ tsconfig.json | 10 ++---- 9 files changed, 170 insertions(+), 29 deletions(-) create mode 100644 src/components/AddressOrENSName.tsx create mode 100644 src/components/ENSName.tsx create mode 100644 src/components/ENSNameLink.tsx create mode 100644 src/components/ensLogo.svg diff --git a/src/BlockTransactions.tsx b/src/BlockTransactions.tsx index 060b937..7370db6 100644 --- a/src/BlockTransactions.tsx +++ b/src/BlockTransactions.tsx @@ -11,7 +11,7 @@ import ResultHeader from "./search/ResultHeader"; import PendingResults from "./search/PendingResults"; import TransactionItem from "./search/TransactionItem"; import BlockLink from "./components/BlockLink"; -import { ProcessedTransaction } from "./types"; +import { ProcessedTransaction, ENSReverseCache } from "./types"; import { PAGE_SIZE } from "./params"; import { useFeeToggler } from "./search/useFeeToggler"; @@ -80,6 +80,44 @@ const BlockTransactions: React.FC = () => { }, [txs, pageNumber]); const total = useMemo(() => txs?.length ?? 0, [txs]); + const [reverseCache, setReverseCache] = useState(); + useEffect(() => { + if (!page) { + return; + } + + const addrSet = new Set(); + for (const tx of page) { + if (tx.from) { + addrSet.add(tx.from); + } + if (tx.to) { + addrSet.add(tx.to); + } + } + const addresses = Array.from(addrSet); + + const reverseResolve = async () => { + const solvers: Promise[] = []; + for (const a of addresses) { + solvers.push(provider.lookupAddress(a)); + } + + const results = await Promise.all(solvers); + const cache: ENSReverseCache = {}; + for (let i = 0; i < results.length; i++) { + if (results[i] === null) { + continue; + } + cache[addresses[i]] = results[i]; + } + console.log("RESOLVED"); + console.log(cache); + setReverseCache(cache); + }; + reverseResolve(); + }, [page]); + document.title = `Block #${blockNumber} Txns | Otterscan`; const [feeDisplay, feeDisplayToggler] = useFeeToggler(); @@ -112,7 +150,12 @@ const BlockTransactions: React.FC = () => { {page ? ( <> {page.map((tx) => ( - + ))}
diff --git a/src/components/Address.tsx b/src/components/Address.tsx index fb9f6c1..d757ed3 100644 --- a/src/components/Address.tsx +++ b/src/components/Address.tsx @@ -1,9 +1,13 @@ import React from "react"; -const Address: React.FC = ({ children }) => ( - -

{children}

+type AddressProps = { + address: string; +}; + +const Address: React.FC = ({ address }) => ( + +

{address}

); -export default Address; +export default React.memo(Address); diff --git a/src/components/AddressOrENSName.tsx b/src/components/AddressOrENSName.tsx new file mode 100644 index 0000000..e3cfdb9 --- /dev/null +++ b/src/components/AddressOrENSName.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import Address from "./Address"; +import AddressLink from "./AddressLink"; +import ENSName from "./ENSName"; +import ENSNameLink from "./ENSNameLink"; + +type AddressOrENSNameProps = { + address: string; + ensName?: string; + selectedAddress?: string; +}; + +const AddressOrENSName: React.FC = ({ + address, + ensName, + selectedAddress, +}) => { + return address === selectedAddress ? ( + <> + {ensName ? ( + + ) : ( +
+ )} + + ) : ( + <> + {ensName ? ( + + ) : ( + + )} + + ); +}; + +export default React.memo(AddressOrENSName); diff --git a/src/components/ENSName.tsx b/src/components/ENSName.tsx new file mode 100644 index 0000000..f5750fa --- /dev/null +++ b/src/components/ENSName.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import ENSLogo from "./ensLogo.svg"; + +type ENSNameProps = { + name: string; + address: string; +}; + +const ENSName: React.FC = ({ name, address }) => ( +
+ ENS Logo +

{name}

+
+); + +export default React.memo(ENSName); diff --git a/src/components/ENSNameLink.tsx b/src/components/ENSNameLink.tsx new file mode 100644 index 0000000..a111139 --- /dev/null +++ b/src/components/ENSNameLink.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import { NavLink } from "react-router-dom"; +import ENSLogo from "./ensLogo.svg"; + +type ENSNameLinkProps = { + name: string; + address: string; +}; + +const ENSNameLink: React.FC = ({ name, address }) => ( + + ENS Logo +

{name}

+
+); + +export default React.memo(ENSNameLink); diff --git a/src/components/ensLogo.svg b/src/components/ensLogo.svg new file mode 100644 index 0000000..20d94c0 --- /dev/null +++ b/src/components/ensLogo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/search/TransactionItem.tsx b/src/search/TransactionItem.tsx index abe9e8c..4e74b35 100644 --- a/src/search/TransactionItem.tsx +++ b/src/search/TransactionItem.tsx @@ -4,25 +4,26 @@ import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons"; import MethodName from "../components/MethodName"; import BlockLink from "../components/BlockLink"; import TransactionLink from "../components/TransactionLink"; -import Address from "../components/Address"; -import AddressLink from "../components/AddressLink"; +import AddressOrENSName from "../components/AddressOrENSName"; import TimestampAge from "../components/TimestampAge"; import TransactionDirection, { Direction, } from "../components/TransactionDirection"; import TransactionValue from "../components/TransactionValue"; -import { ProcessedTransaction } from "../types"; +import { ENSReverseCache, ProcessedTransaction } from "../types"; import { FeeDisplay } from "./useFeeToggler"; import { formatValue } from "../components/formatter"; type TransactionItemProps = { tx: ProcessedTransaction; + ensCache?: ENSReverseCache; selectedAddress?: string; feeDisplay: FeeDisplay; }; const TransactionItem: React.FC = ({ tx, + ensCache, selectedAddress, feeDisplay, }) => { @@ -39,6 +40,9 @@ const TransactionItem: React.FC = ({ } } + const ensFrom = ensCache && tx.from && ensCache[tx.from]; + const ensTo = ensCache && tx.to && ensCache[tx.to]; + return (
@@ -58,24 +62,26 @@ const TransactionItem: React.FC = ({ - {tx.from && - (tx.from === selectedAddress ? ( -
{tx.from}
- ) : ( - - ))} + {tx.from && ( + + )}
- {tx.to && - (tx.to === selectedAddress ? ( -
{tx.to}
- ) : ( - - ))} + {tx.to && ( + + )}
diff --git a/src/types.ts b/src/types.ts index 9677652..170fe58 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,3 +19,7 @@ export type TransactionChunk = { firstPage: boolean; lastPage: boolean; }; + +export type ENSReverseCache = { + [address: string]: string; +}; diff --git a/tsconfig.json b/tsconfig.json index a273b0c..9d379a3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -20,7 +16,5 @@ "noEmit": true, "jsx": "react-jsx" }, - "include": [ - "src" - ] + "include": ["src"] }