Push down address search-specific computations
This commit is contained in:
parent
97611ca0a1
commit
843781c8ba
|
@ -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}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -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 : ""}
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
Loading…
Reference in New Issue