Merge branch 'feature/sourcify-decoration' into develop
This commit is contained in:
commit
626133d9e0
|
@ -118,7 +118,7 @@ server {
|
||||||
index index.html;
|
index index.html;
|
||||||
try_files $uri /index.html;
|
try_files $uri /index.html;
|
||||||
|
|
||||||
brotli_static on;
|
# brotli_static on;
|
||||||
}
|
}
|
||||||
|
|
||||||
#error_page 404 /404.html;
|
#error_page 404 /404.html;
|
||||||
|
|
|
@ -4,7 +4,7 @@ worker_processes auto;
|
||||||
error_log /var/log/nginx/error.log notice;
|
error_log /var/log/nginx/error.log notice;
|
||||||
pid /var/run/nginx.pid;
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
load_module modules/ngx_http_brotli_static_module.so;
|
#load_module modules/ngx_http_brotli_static_module.so;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
|
|
|
@ -31,7 +31,8 @@ import { useFeeToggler } from "./search/useFeeToggler";
|
||||||
import { SelectionContext, useSelection } from "./useSelection";
|
import { SelectionContext, useSelection } from "./useSelection";
|
||||||
import { useMultipleETHUSDOracle } from "./usePriceOracle";
|
import { useMultipleETHUSDOracle } from "./usePriceOracle";
|
||||||
import { useAppConfigContext } from "./useAppConfig";
|
import { useAppConfigContext } from "./useAppConfig";
|
||||||
import { useSourcify } from "./useSourcify";
|
import { useMultipleMetadata } from "./useSourcify";
|
||||||
|
import { ChecksummedAddress } from "./types";
|
||||||
import SourcifyLogo from "./sourcify.svg";
|
import SourcifyLogo from "./sourcify.svg";
|
||||||
|
|
||||||
type BlockParams = {
|
type BlockParams = {
|
||||||
|
@ -181,12 +182,31 @@ const AddressTransactions: React.FC = () => {
|
||||||
const [feeDisplay, feeDisplayToggler] = useFeeToggler();
|
const [feeDisplay, feeDisplayToggler] = useFeeToggler();
|
||||||
|
|
||||||
const selectionCtx = useSelection();
|
const selectionCtx = useSelection();
|
||||||
|
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 rawMetadata = useSourcify(
|
const metadatas = useMultipleMetadata(
|
||||||
checksummedAddress,
|
undefined,
|
||||||
|
addresses,
|
||||||
provider?.network.chainId,
|
provider?.network.chainId,
|
||||||
sourcifySource
|
sourcifySource
|
||||||
);
|
);
|
||||||
|
const addressMetadata =
|
||||||
|
checksummedAddress !== undefined
|
||||||
|
? metadatas[checksummedAddress]
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StandardFrame>
|
<StandardFrame>
|
||||||
|
@ -224,18 +244,18 @@ const AddressTransactions: React.FC = () => {
|
||||||
<NavTab href={`/address/${checksummedAddress}/contract`}>
|
<NavTab href={`/address/${checksummedAddress}/contract`}>
|
||||||
<span
|
<span
|
||||||
className={`flex items-baseline space-x-2 ${
|
className={`flex items-baseline space-x-2 ${
|
||||||
rawMetadata === undefined ? "italic opacity-50" : ""
|
addressMetadata === undefined ? "italic opacity-50" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span>Contract</span>
|
<span>Contract</span>
|
||||||
{rawMetadata === undefined ? (
|
{addressMetadata === undefined ? (
|
||||||
<span className="self-center">
|
<span className="self-center">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
className="animate-spin"
|
className="animate-spin"
|
||||||
icon={faCircleNotch}
|
icon={faCircleNotch}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
) : rawMetadata === null ? (
|
) : addressMetadata === null ? (
|
||||||
<span className="self-center text-red-500">
|
<span className="self-center text-red-500">
|
||||||
<FontAwesomeIcon icon={faQuestionCircle} />
|
<FontAwesomeIcon icon={faQuestionCircle} />
|
||||||
</span>
|
</span>
|
||||||
|
@ -288,6 +308,7 @@ const AddressTransactions: React.FC = () => {
|
||||||
selectedAddress={checksummedAddress}
|
selectedAddress={checksummedAddress}
|
||||||
feeDisplay={feeDisplay}
|
feeDisplay={feeDisplay}
|
||||||
priceMap={priceMap}
|
priceMap={priceMap}
|
||||||
|
metadatas={metadatas}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<div className="flex justify-between items-baseline py-3">
|
<div className="flex justify-between items-baseline py-3">
|
||||||
|
@ -316,7 +337,7 @@ const AddressTransactions: React.FC = () => {
|
||||||
<Route path="/address/:addressOrName/contract" exact>
|
<Route path="/address/:addressOrName/contract" exact>
|
||||||
<Contracts
|
<Contracts
|
||||||
checksummedAddress={checksummedAddress}
|
checksummedAddress={checksummedAddress}
|
||||||
rawMetadata={rawMetadata}
|
rawMetadata={addressMetadata}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
|
@ -9,9 +9,11 @@ import { useFeeToggler } from "../search/useFeeToggler";
|
||||||
import { RuntimeContext } from "../useRuntime";
|
import { RuntimeContext } from "../useRuntime";
|
||||||
import { SelectionContext, useSelection } from "../useSelection";
|
import { SelectionContext, useSelection } from "../useSelection";
|
||||||
import { pageCollector, useResolvedAddresses } from "../useResolvedAddresses";
|
import { pageCollector, useResolvedAddresses } from "../useResolvedAddresses";
|
||||||
import { ProcessedTransaction } from "../types";
|
import { ChecksummedAddress, ProcessedTransaction } from "../types";
|
||||||
import { PAGE_SIZE } from "../params";
|
import { PAGE_SIZE } from "../params";
|
||||||
import { useMultipleETHUSDOracle } from "../usePriceOracle";
|
import { useMultipleETHUSDOracle } from "../usePriceOracle";
|
||||||
|
import { useAppConfigContext } from "../useAppConfig";
|
||||||
|
import { useMultipleMetadata } from "../useSourcify";
|
||||||
|
|
||||||
type BlockTransactionResultsProps = {
|
type BlockTransactionResultsProps = {
|
||||||
blockTag: BlockTag;
|
blockTag: BlockTag;
|
||||||
|
@ -34,6 +36,21 @@ const BlockTransactionResults: React.FC<BlockTransactionResultsProps> = ({
|
||||||
const blockTags = useMemo(() => [blockTag], [blockTag]);
|
const blockTags = useMemo(() => [blockTag], [blockTag]);
|
||||||
const priceMap = useMultipleETHUSDOracle(provider, blockTags);
|
const priceMap = useMultipleETHUSDOracle(provider, blockTags);
|
||||||
|
|
||||||
|
const addresses = useMemo((): ChecksummedAddress[] => {
|
||||||
|
if (!page) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return page.map((t) => t.to).filter((to): to is string => to !== undefined);
|
||||||
|
}, [page]);
|
||||||
|
const { sourcifySource } = useAppConfigContext();
|
||||||
|
const metadatas = useMultipleMetadata(
|
||||||
|
undefined,
|
||||||
|
addresses,
|
||||||
|
provider?.network.chainId,
|
||||||
|
sourcifySource
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentFrame>
|
<ContentFrame>
|
||||||
<div className="flex justify-between items-baseline py-3">
|
<div className="flex justify-between items-baseline py-3">
|
||||||
|
@ -63,6 +80,7 @@ const BlockTransactionResults: React.FC<BlockTransactionResultsProps> = ({
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
feeDisplay={feeDisplay}
|
feeDisplay={feeDisplay}
|
||||||
priceMap={priceMap}
|
priceMap={priceMap}
|
||||||
|
metadatas={metadatas}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<div className="flex justify-between items-baseline py-3">
|
<div className="flex justify-between items-baseline py-3">
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { faCoins } from "@fortawesome/free-solid-svg-icons/faCoins";
|
||||||
import AddressOrENSName from "./AddressOrENSName";
|
import AddressOrENSName from "./AddressOrENSName";
|
||||||
import { AddressContext, ZERO_ADDRESS } from "../types";
|
import { AddressContext, ZERO_ADDRESS } from "../types";
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
|
import { Metadata } from "../useSourcify";
|
||||||
|
import SourcifyLogo from "../sourcify.svg";
|
||||||
|
|
||||||
type DecoratedAddressLinkProps = {
|
type DecoratedAddressLinkProps = {
|
||||||
address: string;
|
address: string;
|
||||||
|
@ -19,6 +21,7 @@ type DecoratedAddressLinkProps = {
|
||||||
txFrom?: boolean;
|
txFrom?: boolean;
|
||||||
txTo?: boolean;
|
txTo?: boolean;
|
||||||
resolvedAddresses?: ResolvedAddresses | undefined;
|
resolvedAddresses?: ResolvedAddresses | undefined;
|
||||||
|
metadata?: Metadata | null | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DecoratedAddressLink: React.FC<DecoratedAddressLinkProps> = ({
|
const DecoratedAddressLink: React.FC<DecoratedAddressLinkProps> = ({
|
||||||
|
@ -31,6 +34,7 @@ const DecoratedAddressLink: React.FC<DecoratedAddressLinkProps> = ({
|
||||||
txFrom,
|
txFrom,
|
||||||
txTo,
|
txTo,
|
||||||
resolvedAddresses,
|
resolvedAddresses,
|
||||||
|
metadata,
|
||||||
}) => {
|
}) => {
|
||||||
const mint = addressCtx === AddressContext.FROM && address === ZERO_ADDRESS;
|
const mint = addressCtx === AddressContext.FROM && address === ZERO_ADDRESS;
|
||||||
const burn = addressCtx === AddressContext.TO && address === ZERO_ADDRESS;
|
const burn = addressCtx === AddressContext.TO && address === ZERO_ADDRESS;
|
||||||
|
@ -70,6 +74,17 @@ const DecoratedAddressLink: React.FC<DecoratedAddressLinkProps> = ({
|
||||||
<FontAwesomeIcon icon={faCoins} size="1x" />
|
<FontAwesomeIcon icon={faCoins} size="1x" />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
{metadata && (
|
||||||
|
<span className="self-center flex-shrink-0 flex items-center">
|
||||||
|
<img
|
||||||
|
src={SourcifyLogo}
|
||||||
|
alt="Sourcify logo"
|
||||||
|
title="Verified by Sourcify"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
<AddressOrENSName
|
<AddressOrENSName
|
||||||
address={address}
|
address={address}
|
||||||
selectedAddress={selectedAddress}
|
selectedAddress={selectedAddress}
|
||||||
|
|
|
@ -4,17 +4,20 @@ import DecoratedAddressLink from "./DecoratedAddressLink";
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
import { useSelectedTransaction } from "../useSelectedTransaction";
|
import { useSelectedTransaction } from "../useSelectedTransaction";
|
||||||
import { AddressContext } from "../types";
|
import { AddressContext } from "../types";
|
||||||
|
import { Metadata } from "../useSourcify";
|
||||||
|
|
||||||
type TransactionAddressProps = {
|
type TransactionAddressProps = {
|
||||||
address: string;
|
address: string;
|
||||||
addressCtx?: AddressContext | undefined;
|
addressCtx?: AddressContext | undefined;
|
||||||
resolvedAddresses: ResolvedAddresses | undefined;
|
resolvedAddresses: ResolvedAddresses | undefined;
|
||||||
|
metadata?: Metadata | null | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TransactionAddress: React.FC<TransactionAddressProps> = ({
|
const TransactionAddress: React.FC<TransactionAddressProps> = ({
|
||||||
address,
|
address,
|
||||||
addressCtx,
|
addressCtx,
|
||||||
resolvedAddresses,
|
resolvedAddresses,
|
||||||
|
metadata,
|
||||||
}) => {
|
}) => {
|
||||||
const txData = useSelectedTransaction();
|
const txData = useSelectedTransaction();
|
||||||
// TODO: push down creation coloring logic into DecoratedAddressLink
|
// TODO: push down creation coloring logic into DecoratedAddressLink
|
||||||
|
@ -30,6 +33,7 @@ const TransactionAddress: React.FC<TransactionAddressProps> = ({
|
||||||
txTo={address === txData?.to || creation}
|
txTo={address === txData?.to || creation}
|
||||||
creation={creation}
|
creation={creation}
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
metadata={metadata}
|
||||||
/>
|
/>
|
||||||
</AddressHighlighter>
|
</AddressHighlighter>
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,11 +14,12 @@ import TransactionDirection, {
|
||||||
Flags,
|
Flags,
|
||||||
} from "../components/TransactionDirection";
|
} from "../components/TransactionDirection";
|
||||||
import TransactionValue from "../components/TransactionValue";
|
import TransactionValue from "../components/TransactionValue";
|
||||||
import { ProcessedTransaction } from "../types";
|
import { ChecksummedAddress, ProcessedTransaction } from "../types";
|
||||||
import { FeeDisplay } from "./useFeeToggler";
|
import { FeeDisplay } from "./useFeeToggler";
|
||||||
import { formatValue } from "../components/formatter";
|
import { formatValue } from "../components/formatter";
|
||||||
import ETH2USDValue from "../components/ETH2USDValue";
|
import ETH2USDValue from "../components/ETH2USDValue";
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
|
import { Metadata } from "../useSourcify";
|
||||||
|
|
||||||
type TransactionItemProps = {
|
type TransactionItemProps = {
|
||||||
tx: ProcessedTransaction;
|
tx: ProcessedTransaction;
|
||||||
|
@ -26,6 +27,7 @@ type TransactionItemProps = {
|
||||||
selectedAddress?: string;
|
selectedAddress?: string;
|
||||||
feeDisplay: FeeDisplay;
|
feeDisplay: FeeDisplay;
|
||||||
priceMap: Record<BlockTag, BigNumber>;
|
priceMap: Record<BlockTag, BigNumber>;
|
||||||
|
metadatas: Record<ChecksummedAddress, Metadata | null | undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TransactionItem: React.FC<TransactionItemProps> = ({
|
const TransactionItem: React.FC<TransactionItemProps> = ({
|
||||||
|
@ -34,6 +36,7 @@ const TransactionItem: React.FC<TransactionItemProps> = ({
|
||||||
selectedAddress,
|
selectedAddress,
|
||||||
feeDisplay,
|
feeDisplay,
|
||||||
priceMap,
|
priceMap,
|
||||||
|
metadatas,
|
||||||
}) => {
|
}) => {
|
||||||
let direction: Direction | undefined;
|
let direction: Direction | undefined;
|
||||||
if (selectedAddress) {
|
if (selectedAddress) {
|
||||||
|
@ -105,6 +108,7 @@ const TransactionItem: React.FC<TransactionItemProps> = ({
|
||||||
selectedAddress={selectedAddress}
|
selectedAddress={selectedAddress}
|
||||||
miner={tx.miner === tx.to}
|
miner={tx.miner === tx.to}
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
metadata={metadatas[tx.to]}
|
||||||
/>
|
/>
|
||||||
</AddressHighlighter>
|
</AddressHighlighter>
|
||||||
) : (
|
) : (
|
||||||
|
@ -114,6 +118,7 @@ const TransactionItem: React.FC<TransactionItemProps> = ({
|
||||||
selectedAddress={selectedAddress}
|
selectedAddress={selectedAddress}
|
||||||
creation
|
creation
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
metadata={metadatas[tx.createdContractAddress!]}
|
||||||
/>
|
/>
|
||||||
</AddressHighlighter>
|
</AddressHighlighter>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useMemo } from "react";
|
import React, { useContext, useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
TransactionDescription,
|
TransactionDescription,
|
||||||
Fragment,
|
Fragment,
|
||||||
|
@ -26,15 +26,21 @@ import USDValue from "../components/USDValue";
|
||||||
import FormattedBalance from "../components/FormattedBalance";
|
import FormattedBalance from "../components/FormattedBalance";
|
||||||
import ETH2USDValue from "../components/ETH2USDValue";
|
import ETH2USDValue from "../components/ETH2USDValue";
|
||||||
import TokenTransferItem from "../TokenTransferItem";
|
import TokenTransferItem from "../TokenTransferItem";
|
||||||
import { TransactionData, InternalOperation } from "../types";
|
import {
|
||||||
|
TransactionData,
|
||||||
|
InternalOperation,
|
||||||
|
ChecksummedAddress,
|
||||||
|
} from "../types";
|
||||||
import PercentageBar from "../components/PercentageBar";
|
import PercentageBar from "../components/PercentageBar";
|
||||||
import ExternalLink from "../components/ExternalLink";
|
import ExternalLink from "../components/ExternalLink";
|
||||||
import RelativePosition from "../components/RelativePosition";
|
import RelativePosition from "../components/RelativePosition";
|
||||||
import PercentagePosition from "../components/PercentagePosition";
|
import PercentagePosition from "../components/PercentagePosition";
|
||||||
import InputDecoder from "./decoder/InputDecoder";
|
import InputDecoder from "./decoder/InputDecoder";
|
||||||
import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes";
|
import { rawInputTo4Bytes, use4Bytes } from "../use4Bytes";
|
||||||
import { DevDoc, UserDoc } from "../useSourcify";
|
import { DevDoc, useMultipleMetadata, UserDoc } from "../useSourcify";
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
|
import { RuntimeContext } from "../useRuntime";
|
||||||
|
import { useAppConfigContext } from "../useAppConfig";
|
||||||
|
|
||||||
type DetailsProps = {
|
type DetailsProps = {
|
||||||
txData: TransactionData;
|
txData: TransactionData;
|
||||||
|
@ -80,6 +86,25 @@ const Details: React.FC<DetailsProps> = ({
|
||||||
const userMethod = txDesc ? userDoc?.methods[txDesc.signature] : undefined;
|
const userMethod = txDesc ? userDoc?.methods[txDesc.signature] : undefined;
|
||||||
const devMethod = txDesc ? devDoc?.methods[txDesc.signature] : undefined;
|
const devMethod = txDesc ? devDoc?.methods[txDesc.signature] : undefined;
|
||||||
|
|
||||||
|
const { provider } = useContext(RuntimeContext);
|
||||||
|
const addresses = useMemo(() => {
|
||||||
|
const _addresses: ChecksummedAddress[] = [];
|
||||||
|
if (txData.to) {
|
||||||
|
_addresses.push(txData.to);
|
||||||
|
}
|
||||||
|
if (txData.confirmedData?.createdContractAddress) {
|
||||||
|
_addresses.push(txData.confirmedData.createdContractAddress);
|
||||||
|
}
|
||||||
|
return _addresses;
|
||||||
|
}, [txData]);
|
||||||
|
const { sourcifySource } = useAppConfigContext();
|
||||||
|
const metadatas = useMultipleMetadata(
|
||||||
|
undefined,
|
||||||
|
addresses,
|
||||||
|
provider?.network.chainId,
|
||||||
|
sourcifySource
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentFrame tabs>
|
<ContentFrame tabs>
|
||||||
<InfoRow title="Transaction Hash">
|
<InfoRow title="Transaction Hash">
|
||||||
|
@ -155,6 +180,7 @@ const Details: React.FC<DetailsProps> = ({
|
||||||
<TransactionAddress
|
<TransactionAddress
|
||||||
address={txData.to}
|
address={txData.to}
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
metadata={metadatas?.[txData.to]}
|
||||||
/>
|
/>
|
||||||
<Copy value={txData.to} />
|
<Copy value={txData.to} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -167,6 +193,9 @@ const Details: React.FC<DetailsProps> = ({
|
||||||
<TransactionAddress
|
<TransactionAddress
|
||||||
address={txData.confirmedData?.createdContractAddress!}
|
address={txData.confirmedData?.createdContractAddress!}
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
metadata={
|
||||||
|
metadatas?.[txData.confirmedData?.createdContractAddress!]
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Copy value={txData.confirmedData.createdContractAddress!} />
|
<Copy value={txData.confirmedData.createdContractAddress!} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,17 +9,21 @@ import DecodedParamsTable from "./decoder/DecodedParamsTable";
|
||||||
import DecodedLogSignature from "./decoder/DecodedLogSignature";
|
import DecodedLogSignature from "./decoder/DecodedLogSignature";
|
||||||
import { useTopic0 } from "../useTopic0";
|
import { useTopic0 } from "../useTopic0";
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
|
import { ChecksummedAddress } from "../types";
|
||||||
|
import { Metadata } from "../useSourcify";
|
||||||
|
|
||||||
type LogEntryProps = {
|
type LogEntryProps = {
|
||||||
log: Log;
|
log: Log;
|
||||||
logDesc: LogDescription | null | undefined;
|
logDesc: LogDescription | null | undefined;
|
||||||
resolvedAddresses: ResolvedAddresses | undefined;
|
resolvedAddresses: ResolvedAddresses | undefined;
|
||||||
|
metadatas: Record<ChecksummedAddress, Metadata | null | undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LogEntry: React.FC<LogEntryProps> = ({
|
const LogEntry: React.FC<LogEntryProps> = ({
|
||||||
log,
|
log,
|
||||||
logDesc,
|
logDesc,
|
||||||
resolvedAddresses,
|
resolvedAddresses,
|
||||||
|
metadatas,
|
||||||
}) => {
|
}) => {
|
||||||
const rawTopic0 = log.topics[0];
|
const rawTopic0 = log.topics[0];
|
||||||
const topic0 = useTopic0(rawTopic0);
|
const topic0 = useTopic0(rawTopic0);
|
||||||
|
@ -62,6 +66,7 @@ const LogEntry: React.FC<LogEntryProps> = ({
|
||||||
<TransactionAddress
|
<TransactionAddress
|
||||||
address={log.address}
|
address={log.address}
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
metadata={metadatas[log.address]}
|
||||||
/>
|
/>
|
||||||
<Copy value={log.address} />
|
<Copy value={log.address} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useMemo } from "react";
|
import React, { useContext, useMemo } from "react";
|
||||||
import { Interface } from "@ethersproject/abi";
|
import { Interface } from "@ethersproject/abi";
|
||||||
import ContentFrame from "../ContentFrame";
|
import ContentFrame from "../ContentFrame";
|
||||||
import LogEntry from "./LogEntry";
|
import LogEntry from "./LogEntry";
|
||||||
|
@ -6,6 +6,7 @@ import { TransactionData } from "../types";
|
||||||
import { useAppConfigContext } from "../useAppConfig";
|
import { useAppConfigContext } from "../useAppConfig";
|
||||||
import { Metadata, useMultipleMetadata } from "../useSourcify";
|
import { Metadata, useMultipleMetadata } from "../useSourcify";
|
||||||
import { ResolvedAddresses } from "../api/address-resolver";
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
|
import { RuntimeContext } from "../useRuntime";
|
||||||
|
|
||||||
type LogsProps = {
|
type LogsProps = {
|
||||||
txData: TransactionData;
|
txData: TransactionData;
|
||||||
|
@ -24,15 +25,16 @@ const Logs: React.FC<LogsProps> = ({ txData, metadata, resolvedAddresses }) => {
|
||||||
return md;
|
return md;
|
||||||
}, [txData.to, metadata]);
|
}, [txData.to, metadata]);
|
||||||
|
|
||||||
const { sourcifySource } = useAppConfigContext();
|
|
||||||
const logAddresses = useMemo(
|
const logAddresses = useMemo(
|
||||||
() => txData.confirmedData?.logs.map((l) => l.address) ?? [],
|
() => txData.confirmedData?.logs.map((l) => l.address) ?? [],
|
||||||
[txData]
|
[txData]
|
||||||
);
|
);
|
||||||
|
const { provider } = useContext(RuntimeContext);
|
||||||
|
const { sourcifySource } = useAppConfigContext();
|
||||||
const metadatas = useMultipleMetadata(
|
const metadatas = useMultipleMetadata(
|
||||||
baseMetadatas,
|
baseMetadatas,
|
||||||
logAddresses,
|
logAddresses,
|
||||||
1,
|
provider?.network.chainId,
|
||||||
sourcifySource
|
sourcifySource
|
||||||
);
|
);
|
||||||
const logDescs = useMemo(() => {
|
const logDescs = useMemo(() => {
|
||||||
|
@ -72,6 +74,7 @@ const Logs: React.FC<LogsProps> = ({ txData, metadata, resolvedAddresses }) => {
|
||||||
log={l}
|
log={l}
|
||||||
logDesc={logDescs?.[i]}
|
logDesc={logDescs?.[i]}
|
||||||
resolvedAddresses={resolvedAddresses}
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
metadatas={metadatas}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -67,6 +67,9 @@ export type ConfirmedTransactionData = {
|
||||||
// The VOID...
|
// The VOID...
|
||||||
export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
||||||
|
|
||||||
|
// TODO: replace all occurrences of plain string
|
||||||
|
export type ChecksummedAddress = string;
|
||||||
|
|
||||||
export enum AddressContext {
|
export enum AddressContext {
|
||||||
FROM,
|
FROM,
|
||||||
TO,
|
TO,
|
||||||
|
|
13
src/url.ts
13
src/url.ts
|
@ -1,4 +1,5 @@
|
||||||
import { BlockTag } from "@ethersproject/abstract-provider";
|
import { BlockTag } from "@ethersproject/abstract-provider";
|
||||||
|
import { ChecksummedAddress } from "./types";
|
||||||
|
|
||||||
export const fourBytesURL = (
|
export const fourBytesURL = (
|
||||||
assetsURLPrefix: string,
|
assetsURLPrefix: string,
|
||||||
|
@ -42,23 +43,23 @@ const resolveSourcifySource = (source: SourcifySource) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sourcifyMetadata = (
|
export const sourcifyMetadata = (
|
||||||
checksummedAddress: string,
|
address: ChecksummedAddress,
|
||||||
networkId: number,
|
chainId: number,
|
||||||
source: SourcifySource
|
source: SourcifySource
|
||||||
) =>
|
) =>
|
||||||
`${resolveSourcifySource(
|
`${resolveSourcifySource(
|
||||||
source
|
source
|
||||||
)}/contracts/full_match/${networkId}/${checksummedAddress}/metadata.json`;
|
)}/contracts/full_match/${chainId}/${address}/metadata.json`;
|
||||||
|
|
||||||
export const sourcifySourceFile = (
|
export const sourcifySourceFile = (
|
||||||
checksummedAddress: string,
|
address: ChecksummedAddress,
|
||||||
networkId: number,
|
chainId: number,
|
||||||
filepath: string,
|
filepath: string,
|
||||||
source: SourcifySource
|
source: SourcifySource
|
||||||
) =>
|
) =>
|
||||||
`${resolveSourcifySource(
|
`${resolveSourcifySource(
|
||||||
source
|
source
|
||||||
)}/contracts/full_match/${networkId}/${checksummedAddress}/sources/${filepath}`;
|
)}/contracts/full_match/${chainId}/${address}/sources/${filepath}`;
|
||||||
|
|
||||||
export const openInRemixURL = (checksummedAddress: string, networkId: number) =>
|
export const openInRemixURL = (checksummedAddress: string, networkId: number) =>
|
||||||
`https://remix.ethereum.org/#call=source-verification//fetchAndSave//${checksummedAddress}//${networkId}`;
|
`https://remix.ethereum.org/#call=source-verification//fetchAndSave//${checksummedAddress}//${networkId}`;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState, useEffect, useMemo } from "react";
|
import { useState, useEffect, useMemo } from "react";
|
||||||
import { Interface } from "@ethersproject/abi";
|
import { Interface } from "@ethersproject/abi";
|
||||||
import { TransactionData } from "./types";
|
import { ChecksummedAddress, TransactionData } from "./types";
|
||||||
import { sourcifyMetadata, SourcifySource, sourcifySourceFile } from "./url";
|
import { sourcifyMetadata, SourcifySource, sourcifySourceFile } from "./url";
|
||||||
|
|
||||||
export type UserMethod = {
|
export type UserMethod = {
|
||||||
|
@ -65,24 +65,19 @@ export type Metadata = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchSourcifyMetadata = async (
|
const fetchSourcifyMetadata = async (
|
||||||
checksummedAddress: string,
|
address: ChecksummedAddress,
|
||||||
chainId: number,
|
chainId: number,
|
||||||
source: SourcifySource,
|
source: SourcifySource,
|
||||||
abortController: AbortController
|
abortController: AbortController
|
||||||
): Promise<Metadata | null> => {
|
): Promise<Metadata | null> => {
|
||||||
try {
|
try {
|
||||||
const contractMetadataURL = sourcifyMetadata(
|
const metadataURL = sourcifyMetadata(address, chainId, source);
|
||||||
checksummedAddress,
|
const result = await fetch(metadataURL, {
|
||||||
chainId,
|
|
||||||
source
|
|
||||||
);
|
|
||||||
const result = await fetch(contractMetadataURL, {
|
|
||||||
signal: abortController.signal,
|
signal: abortController.signal,
|
||||||
});
|
});
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
const _metadata = await result.json();
|
return await result.json();
|
||||||
return _metadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -92,15 +87,16 @@ export const fetchSourcifyMetadata = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: replace every occurrence with the multiple version one
|
||||||
export const useSourcify = (
|
export const useSourcify = (
|
||||||
checksummedAddress: string | undefined,
|
address: ChecksummedAddress | undefined,
|
||||||
chainId: number | undefined,
|
chainId: number | undefined,
|
||||||
source: SourcifySource
|
source: SourcifySource
|
||||||
): Metadata | null | undefined => {
|
): Metadata | null | undefined => {
|
||||||
const [rawMetadata, setRawMetadata] = useState<Metadata | null | undefined>();
|
const [rawMetadata, setRawMetadata] = useState<Metadata | null | undefined>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!checksummedAddress || chainId === undefined) {
|
if (!address || chainId === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setRawMetadata(undefined);
|
setRawMetadata(undefined);
|
||||||
|
@ -108,7 +104,7 @@ export const useSourcify = (
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const fetchMetadata = async () => {
|
const fetchMetadata = async () => {
|
||||||
const _metadata = await fetchSourcifyMetadata(
|
const _metadata = await fetchSourcifyMetadata(
|
||||||
checksummedAddress,
|
address,
|
||||||
chainId,
|
chainId,
|
||||||
source,
|
source,
|
||||||
abortController
|
abortController
|
||||||
|
@ -120,47 +116,53 @@ export const useSourcify = (
|
||||||
return () => {
|
return () => {
|
||||||
abortController.abort();
|
abortController.abort();
|
||||||
};
|
};
|
||||||
}, [checksummedAddress, chainId, source]);
|
}, [address, chainId, source]);
|
||||||
|
|
||||||
return rawMetadata;
|
return rawMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useMultipleMetadata = (
|
export const useMultipleMetadata = (
|
||||||
baseMetadatas: Record<string, Metadata | null>,
|
baseMetadatas: Record<string, Metadata | null> | undefined,
|
||||||
checksummedAddress: (string | undefined)[],
|
addresses: (ChecksummedAddress | undefined)[],
|
||||||
chainId: number | undefined,
|
chainId: number | undefined,
|
||||||
source: SourcifySource
|
source: SourcifySource
|
||||||
): Record<string, Metadata | null | undefined> => {
|
): Record<ChecksummedAddress, Metadata | null | undefined> => {
|
||||||
const [rawMetadata, setRawMetadata] = useState<
|
const [rawMetadata, setRawMetadata] = useState<
|
||||||
Record<string, Metadata | null | undefined>
|
Record<string, Metadata | null | undefined>
|
||||||
>({});
|
>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!checksummedAddress || chainId === undefined) {
|
if (!addresses || chainId === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setRawMetadata({});
|
setRawMetadata({});
|
||||||
|
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const fetchMetadata = async (addresses: string[]) => {
|
const fetchMetadata = async (dedupedAddresses: string[]) => {
|
||||||
const promises: Promise<Metadata | null>[] = [];
|
const promises: Promise<Metadata | null>[] = [];
|
||||||
for (const addr of addresses) {
|
for (const address of dedupedAddresses) {
|
||||||
promises.push(
|
promises.push(
|
||||||
fetchSourcifyMetadata(addr, chainId, source, abortController)
|
fetchSourcifyMetadata(address, chainId, source, abortController)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await Promise.all(promises);
|
const results = await Promise.all(promises);
|
||||||
const metadatas: Record<string, Metadata | null> = { ...baseMetadatas };
|
if (abortController.signal.aborted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const metadatas: Record<string, Metadata | null> = baseMetadatas
|
||||||
|
? { ...baseMetadatas }
|
||||||
|
: {};
|
||||||
for (let i = 0; i < results.length; i++) {
|
for (let i = 0; i < results.length; i++) {
|
||||||
metadatas[addresses[i]] = results[i];
|
metadatas[dedupedAddresses[i]] = results[i];
|
||||||
}
|
}
|
||||||
setRawMetadata(metadatas);
|
setRawMetadata(metadatas);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deduped = new Set(
|
const deduped = new Set(
|
||||||
checksummedAddress.filter(
|
addresses.filter(
|
||||||
(a): a is string => a !== undefined && baseMetadatas[a] === undefined
|
(a): a is ChecksummedAddress =>
|
||||||
|
a !== undefined && baseMetadatas?.[a] === undefined
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
fetchMetadata(Array.from(deduped));
|
fetchMetadata(Array.from(deduped));
|
||||||
|
@ -168,7 +170,7 @@ export const useMultipleMetadata = (
|
||||||
return () => {
|
return () => {
|
||||||
abortController.abort();
|
abortController.abort();
|
||||||
};
|
};
|
||||||
}, [baseMetadatas, checksummedAddress, chainId, source]);
|
}, [baseMetadatas, addresses, chainId, source]);
|
||||||
|
|
||||||
return rawMetadata;
|
return rawMetadata;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue