Push down address search-specific computations

This commit is contained in:
Willian Mitsuda 2021-11-25 15:03:00 -03:00
parent 97611ca0a1
commit 843781c8ba
3 changed files with 122 additions and 136 deletions

View File

@ -6,7 +6,6 @@ import {
Route, Route,
useSearchParams, useSearchParams,
} from "react-router-dom"; } from "react-router-dom";
import { BlockTag } from "@ethersproject/abstract-provider";
import { getAddress, isAddress } from "@ethersproject/address"; import { getAddress, isAddress } from "@ethersproject/address";
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
import Blockies from "react-blockies"; import Blockies from "react-blockies";
@ -19,14 +18,9 @@ import Copy from "./components/Copy";
import NavTab from "./components/NavTab"; import NavTab from "./components/NavTab";
import AddressTransactionResults from "./address/AddressTransactionResults"; import AddressTransactionResults from "./address/AddressTransactionResults";
import Contracts from "./address/Contracts"; import Contracts from "./address/Contracts";
import { SearchController } from "./search/search";
import { RuntimeContext } from "./useRuntime"; import { RuntimeContext } from "./useRuntime";
import { pageCollector, useResolvedAddresses } from "./useResolvedAddresses";
import { useFeeToggler } from "./search/useFeeToggler";
import { useMultipleETHUSDOracle } from "./usePriceOracle";
import { useAppConfigContext } from "./useAppConfig"; import { useAppConfigContext } from "./useAppConfig";
import { useMultipleMetadata } from "./useSourcify"; import { useMultipleMetadata } from "./useSourcify";
import { ChecksummedAddress } from "./types";
import SourcifyLogo from "./sourcify.svg"; import SourcifyLogo from "./sourcify.svg";
const AddressTransactions: React.FC = () => { const AddressTransactions: React.FC = () => {
@ -37,13 +31,7 @@ const AddressTransactions: React.FC = () => {
} }
const navigate = useNavigate(); const navigate = useNavigate();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const h = searchParams.get("h");
let hash: string | undefined;
if (h) {
hash = h;
}
const [checksummedAddress, setChecksummedAddress] = useState< const [checksummedAddress, setChecksummedAddress] = useState<
string | undefined string | undefined
@ -95,96 +83,10 @@ const AddressTransactions: React.FC = () => {
resolveName(); resolveName();
}, [provider, addressOrName, navigate, direction, searchParams]); }, [provider, addressOrName, navigate, direction, searchParams]);
const [controller, setController] = useState<SearchController>(); const addresses = useMemo(
useEffect(() => { () => (checksummedAddress ? [checksummedAddress] : []),
if (!provider || !checksummedAddress) { [checksummedAddress]
return;
}
const readFirstPage = async () => {
const _controller = await SearchController.firstPage(
provider,
checksummedAddress
); );
setController(_controller);
};
const readMiddlePage = async (next: boolean) => {
const _controller = await SearchController.middlePage(
provider,
checksummedAddress,
hash!,
next
);
setController(_controller);
};
const readLastPage = async () => {
const _controller = await SearchController.lastPage(
provider,
checksummedAddress
);
setController(_controller);
};
const prevPage = async () => {
const _controller = await controller!.prevPage(provider, hash!);
setController(_controller);
};
const nextPage = async () => {
const _controller = await controller!.nextPage(provider, hash!);
setController(_controller);
};
// Page load from scratch
if (direction === "first" || direction === undefined) {
if (!controller?.isFirst || controller.address !== checksummedAddress) {
readFirstPage();
}
} else if (direction === "prev") {
if (controller && controller.address === checksummedAddress) {
prevPage();
} else {
readMiddlePage(false);
}
} else if (direction === "next") {
if (controller && controller.address === checksummedAddress) {
nextPage();
} else {
readMiddlePage(true);
}
} else if (direction === "last") {
if (!controller?.isLast || controller.address !== checksummedAddress) {
readLastPage();
}
}
}, [provider, checksummedAddress, direction, hash, controller]);
const page = useMemo(() => controller?.getPage(), [controller]);
const addrCollector = useMemo(() => pageCollector(page), [page]);
const resolvedAddresses = useResolvedAddresses(provider, addrCollector);
const blockTags: BlockTag[] = useMemo(() => {
if (!page) {
return [];
}
return page.map((p) => p.blockNumber);
}, [page]);
const priceMap = useMultipleETHUSDOracle(provider, blockTags);
const [feeDisplay, feeDisplayToggler] = useFeeToggler();
const addresses = useMemo(() => {
const _addresses: ChecksummedAddress[] = [];
if (checksummedAddress) {
_addresses.push(checksummedAddress);
}
if (page) {
for (const t of page) {
if (t.to) {
_addresses.push(t.to);
}
}
}
return _addresses;
}, [checksummedAddress, page]);
const { sourcifySource } = useAppConfigContext(); const { sourcifySource } = useAppConfigContext();
const metadatas = useMultipleMetadata( const metadatas = useMultipleMetadata(
undefined, undefined,
@ -268,14 +170,7 @@ const AddressTransactions: React.FC = () => {
path="*" path="*"
element={ element={
<AddressTransactionResults <AddressTransactionResults
page={page} address={checksummedAddress}
checksummedAddress={checksummedAddress}
controller={controller}
feeDisplay={feeDisplay}
feeDisplayToggler={feeDisplayToggler}
resolvedAddresses={resolvedAddresses}
priceMap={priceMap}
metadatas={metadatas}
/> />
} }
/> />

View File

@ -1,40 +1,131 @@
import React from "react"; import React, { useContext, useEffect, useMemo, useState } from "react";
import { BlockTag } from "@ethersproject/providers"; import { BlockTag } from "@ethersproject/providers";
import { BigNumber } from "@ethersproject/bignumber";
import { ResolvedAddresses } from "../api/address-resolver";
import ContentFrame from "../ContentFrame"; import ContentFrame from "../ContentFrame";
import PendingResults from "../search/PendingResults"; import PendingResults from "../search/PendingResults";
import ResultHeader from "../search/ResultHeader"; import ResultHeader from "../search/ResultHeader";
import { SearchController } from "../search/search"; import { SearchController } from "../search/search";
import TransactionItem from "../search/TransactionItem"; import TransactionItem from "../search/TransactionItem";
import UndefinedPageControl from "../search/UndefinedPageControl"; import UndefinedPageControl from "../search/UndefinedPageControl";
import { FeeDisplay } from "../search/useFeeToggler"; import { useFeeToggler } from "../search/useFeeToggler";
import { ProcessedTransaction } from "../types";
import { SelectionContext, useSelection } from "../useSelection"; import { SelectionContext, useSelection } from "../useSelection";
import { Metadata } from "../useSourcify"; import { useMultipleMetadata } from "../useSourcify";
import { useMultipleETHUSDOracle } from "../usePriceOracle";
import { RuntimeContext } from "../useRuntime";
import { pageCollector, useResolvedAddresses } from "../useResolvedAddresses";
import { useAppConfigContext } from "../useAppConfig";
import { useParams, useSearchParams } from "react-router-dom";
import { ChecksummedAddress } from "../types";
type AddressTransactionResultsProps = { type AddressTransactionResultsProps = {
page: ProcessedTransaction[] | undefined; address: ChecksummedAddress;
checksummedAddress: string;
controller: SearchController | undefined;
feeDisplay: FeeDisplay;
feeDisplayToggler: () => void;
resolvedAddresses: ResolvedAddresses | undefined;
priceMap: Record<BlockTag, BigNumber>;
metadatas: Record<string, Metadata | null | undefined>;
}; };
const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
page, address,
checksummedAddress,
controller,
feeDisplay,
feeDisplayToggler,
resolvedAddresses,
priceMap,
metadatas,
}) => { }) => {
const { provider } = useContext(RuntimeContext);
const selectionCtx = useSelection(); const selectionCtx = useSelection();
const [feeDisplay, feeDisplayToggler] = useFeeToggler();
const { addressOrName, direction } = useParams();
if (addressOrName === undefined) {
throw new Error("addressOrName couldn't be undefined here");
}
const [searchParams] = useSearchParams();
const hash = searchParams.get("h");
const [controller, setController] = useState<SearchController>();
useEffect(() => {
if (!provider || !address) {
return;
}
const readFirstPage = async () => {
const _controller = await SearchController.firstPage(provider, address);
setController(_controller);
};
const readMiddlePage = async (next: boolean) => {
const _controller = await SearchController.middlePage(
provider,
address,
hash!,
next
);
setController(_controller);
};
const readLastPage = async () => {
const _controller = await SearchController.lastPage(provider, address);
setController(_controller);
};
const prevPage = async () => {
const _controller = await controller!.prevPage(provider, hash!);
setController(_controller);
};
const nextPage = async () => {
const _controller = await controller!.nextPage(provider, hash!);
setController(_controller);
};
// Page load from scratch
if (direction === "first" || direction === undefined) {
if (!controller?.isFirst || controller.address !== address) {
readFirstPage();
}
} else if (direction === "prev") {
if (controller && controller.address === address) {
prevPage();
} else {
readMiddlePage(false);
}
} else if (direction === "next") {
if (controller && controller.address === address) {
nextPage();
} else {
readMiddlePage(true);
}
} else if (direction === "last") {
if (!controller?.isLast || controller.address !== address) {
readLastPage();
}
}
}, [provider, address, direction, hash, controller]);
const page = useMemo(() => controller?.getPage(), [controller]);
// Extract block number from all txs on current page
// TODO: dedup blockTags
const blockTags: BlockTag[] = useMemo(() => {
if (!page) {
return [];
}
return page.map((t) => t.blockNumber);
}, [page]);
const priceMap = useMultipleETHUSDOracle(provider, blockTags);
// Resolve all addresses that appear on this page results
const addrCollector = useMemo(() => pageCollector(page), [page]);
const resolvedAddresses = useResolvedAddresses(provider, addrCollector);
// Calculate Sourcify metadata for all addresses that appear on this page results
const addresses = useMemo(() => {
const _addresses = [address];
if (page) {
for (const t of page) {
if (t.to) {
_addresses.push(t.to);
}
}
}
return _addresses;
}, [address, page]);
const { sourcifySource } = useAppConfigContext();
const metadatas = useMultipleMetadata(
undefined,
addresses,
provider?.network.chainId,
sourcifySource
);
return ( return (
<ContentFrame tabs> <ContentFrame tabs>
@ -47,7 +138,7 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
)} )}
</div> </div>
<UndefinedPageControl <UndefinedPageControl
address={checksummedAddress} address={address}
isFirst={controller?.isFirst} isFirst={controller?.isFirst}
isLast={controller?.isLast} isLast={controller?.isLast}
prevHash={page ? page[0].hash : ""} prevHash={page ? page[0].hash : ""}
@ -66,7 +157,7 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
key={tx.hash} key={tx.hash}
tx={tx} tx={tx}
resolvedAddresses={resolvedAddresses} resolvedAddresses={resolvedAddresses}
selectedAddress={checksummedAddress} selectedAddress={address}
feeDisplay={feeDisplay} feeDisplay={feeDisplay}
priceMap={priceMap} priceMap={priceMap}
metadatas={metadatas} metadatas={metadatas}
@ -81,7 +172,7 @@ const AddressTransactionResults: React.FC<AddressTransactionResultsProps> = ({
)} )}
</div> </div>
<UndefinedPageControl <UndefinedPageControl
address={checksummedAddress} address={address}
isFirst={controller?.isFirst} isFirst={controller?.isFirst}
isLast={controller?.isLast} isLast={controller?.isLast}
prevHash={page ? page[0].hash : ""} prevHash={page ? page[0].hash : ""}

View File

@ -28,9 +28,9 @@ const BlockTransactionResults: React.FC<BlockTransactionResultsProps> = ({
total, total,
pageNumber, pageNumber,
}) => { }) => {
const { provider } = useContext(RuntimeContext);
const selectionCtx = useSelection(); const selectionCtx = useSelection();
const [feeDisplay, feeDisplayToggler] = useFeeToggler(); const [feeDisplay, feeDisplayToggler] = useFeeToggler();
const { provider } = useContext(RuntimeContext);
const addrCollector = useMemo(() => pageCollector(page), [page]); const addrCollector = useMemo(() => pageCollector(page), [page]);
const resolvedAddresses = useResolvedAddresses(provider, addrCollector); const resolvedAddresses = useResolvedAddresses(provider, addrCollector);
const blockTags = useMemo(() => [blockTag], [blockTag]); const blockTags = useMemo(() => [blockTag], [blockTag]);