Add support for eoa/contract indicator on address input decoders; generalized indicator support by pushing it down to TransactionAddress component
This commit is contained in:
parent
0e73d4098a
commit
f1a9a2f65d
|
@ -1,4 +1,4 @@
|
|||
import React, { useContext } from "react";
|
||||
import React from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCaretRight } from "@fortawesome/free-solid-svg-icons/faCaretRight";
|
||||
import TransactionAddress from "./components/TransactionAddress";
|
||||
|
@ -9,17 +9,13 @@ import {
|
|||
ChecksummedAddress,
|
||||
TokenMeta,
|
||||
TokenTransfer,
|
||||
TransactionData,
|
||||
} from "./types";
|
||||
import { RuntimeContext } from "./useRuntime";
|
||||
import { useHasCode } from "./useErigonHooks";
|
||||
import { Metadata } from "./sourcify/useSourcify";
|
||||
|
||||
type TokenTransferItemProps = {
|
||||
t: TokenTransfer;
|
||||
tokenMeta?: TokenMeta | null | undefined;
|
||||
metadatas: Record<ChecksummedAddress, Metadata | null | undefined>;
|
||||
txData: TransactionData;
|
||||
};
|
||||
|
||||
// TODO: handle partial
|
||||
|
@ -27,20 +23,7 @@ const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
|
|||
t,
|
||||
tokenMeta,
|
||||
metadatas,
|
||||
txData,
|
||||
}) => {
|
||||
const { provider } = useContext(RuntimeContext);
|
||||
const fromHasCode = useHasCode(
|
||||
provider,
|
||||
t.from,
|
||||
txData.confirmedData ? txData.confirmedData.blockNumber - 1 : undefined
|
||||
);
|
||||
const toHasCode = useHasCode(
|
||||
provider,
|
||||
t.to,
|
||||
txData.confirmedData ? txData.confirmedData.blockNumber - 1 : undefined
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex items-baseline space-x-2 px-2 py-1 truncate hover:bg-gray-100">
|
||||
<span className="text-gray-500">
|
||||
|
@ -53,7 +36,7 @@ const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
|
|||
address={t.from}
|
||||
addressCtx={AddressContext.FROM}
|
||||
metadata={metadatas[t.from]}
|
||||
eoa={fromHasCode === undefined ? undefined : !fromHasCode}
|
||||
showCodeIndicator
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 flex space-x-1">
|
||||
|
@ -62,7 +45,7 @@ const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
|
|||
address={t.to}
|
||||
addressCtx={AddressContext.TO}
|
||||
metadata={metadatas[t.to]}
|
||||
eoa={toHasCode === undefined ? undefined : !toHasCode}
|
||||
showCodeIndicator
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-3 flex space-x-1">
|
||||
|
|
|
@ -9,6 +9,7 @@ import { RuntimeContext } from "./useRuntime";
|
|||
import { useInternalOperations, useTxData } from "./useErigonHooks";
|
||||
import { SelectionContext, useSelection } from "./useSelection";
|
||||
import { SelectedTransactionContext } from "./useSelectedTransaction";
|
||||
import { BlockNumberContext } from "./useBlockTagContext";
|
||||
import { useETHUSDOracle } from "./usePriceOracle";
|
||||
import { useAppConfigContext } from "./useAppConfig";
|
||||
import { useSourcify, useTransactionDescription } from "./sourcify/useSourcify";
|
||||
|
@ -74,56 +75,60 @@ const TransactionPageContent: React.FC<TransactionPageContentProps> = ({
|
|||
|
||||
return (
|
||||
<SelectedTransactionContext.Provider value={txData}>
|
||||
<StandardFrame>
|
||||
<StandardSubtitle>Transaction Details</StandardSubtitle>
|
||||
{txData === null && (
|
||||
<ContentFrame>
|
||||
<div className="py-4 text-sm">
|
||||
Transaction <span className="font-hash">{txHash}</span> not found.
|
||||
</div>
|
||||
</ContentFrame>
|
||||
)}
|
||||
{txData && (
|
||||
<SelectionContext.Provider value={selectionCtx}>
|
||||
<Tab.Group>
|
||||
<Tab.List className="flex space-x-2 border-l border-r border-t rounded-t-lg bg-white">
|
||||
<NavTab href=".">Overview</NavTab>
|
||||
{txData.confirmedData?.blockNumber !== undefined && (
|
||||
<NavTab href="logs">
|
||||
Logs
|
||||
{txData && ` (${txData.confirmedData?.logs?.length ?? 0})`}
|
||||
</NavTab>
|
||||
)}
|
||||
<NavTab href="trace">Trace</NavTab>
|
||||
</Tab.List>
|
||||
</Tab.Group>
|
||||
<React.Suspense fallback={null}>
|
||||
<Routes>
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<Details
|
||||
txData={txData}
|
||||
txDesc={txDesc}
|
||||
toMetadata={metadata}
|
||||
userDoc={metadata?.output.userdoc}
|
||||
devDoc={metadata?.output.devdoc}
|
||||
internalOps={internalOps}
|
||||
sendsEthToMiner={sendsEthToMiner}
|
||||
ethUSDPrice={blockETHUSDPrice}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="logs"
|
||||
element={<Logs txData={txData} metadata={metadata} />}
|
||||
/>
|
||||
<Route path="trace" element={<Trace txData={txData} />} />
|
||||
</Routes>
|
||||
</React.Suspense>
|
||||
</SelectionContext.Provider>
|
||||
)}
|
||||
</StandardFrame>
|
||||
<BlockNumberContext.Provider value={txData?.confirmedData?.blockNumber}>
|
||||
<StandardFrame>
|
||||
<StandardSubtitle>Transaction Details</StandardSubtitle>
|
||||
{txData === null && (
|
||||
<ContentFrame>
|
||||
<div className="py-4 text-sm">
|
||||
Transaction <span className="font-hash">{txHash}</span> not
|
||||
found.
|
||||
</div>
|
||||
</ContentFrame>
|
||||
)}
|
||||
{txData && (
|
||||
<SelectionContext.Provider value={selectionCtx}>
|
||||
<Tab.Group>
|
||||
<Tab.List className="flex space-x-2 border-l border-r border-t rounded-t-lg bg-white">
|
||||
<NavTab href=".">Overview</NavTab>
|
||||
{txData.confirmedData?.blockNumber !== undefined && (
|
||||
<NavTab href="logs">
|
||||
Logs
|
||||
{txData &&
|
||||
` (${txData.confirmedData?.logs?.length ?? 0})`}
|
||||
</NavTab>
|
||||
)}
|
||||
<NavTab href="trace">Trace</NavTab>
|
||||
</Tab.List>
|
||||
</Tab.Group>
|
||||
<React.Suspense fallback={null}>
|
||||
<Routes>
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<Details
|
||||
txData={txData}
|
||||
txDesc={txDesc}
|
||||
toMetadata={metadata}
|
||||
userDoc={metadata?.output.userdoc}
|
||||
devDoc={metadata?.output.devdoc}
|
||||
internalOps={internalOps}
|
||||
sendsEthToMiner={sendsEthToMiner}
|
||||
ethUSDPrice={blockETHUSDPrice}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="logs"
|
||||
element={<Logs txData={txData} metadata={metadata} />}
|
||||
/>
|
||||
<Route path="trace" element={<Trace txData={txData} />} />
|
||||
</Routes>
|
||||
</React.Suspense>
|
||||
</SelectionContext.Provider>
|
||||
)}
|
||||
</StandardFrame>
|
||||
</BlockNumberContext.Provider>
|
||||
</SelectedTransactionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,27 +1,38 @@
|
|||
import React from "react";
|
||||
import React, { useContext } from "react";
|
||||
import AddressHighlighter from "./AddressHighlighter";
|
||||
import DecoratedAddressLink from "./DecoratedAddressLink";
|
||||
import { useSelectedTransaction } from "../useSelectedTransaction";
|
||||
import { AddressContext } from "../types";
|
||||
import { useBlockNumberContext } from "../useBlockTagContext";
|
||||
import { RuntimeContext } from "../useRuntime";
|
||||
import { useHasCode } from "../useErigonHooks";
|
||||
import { Metadata } from "../sourcify/useSourcify";
|
||||
import { AddressContext, ChecksummedAddress } from "../types";
|
||||
|
||||
type TransactionAddressProps = {
|
||||
address: string;
|
||||
address: ChecksummedAddress;
|
||||
addressCtx?: AddressContext | undefined;
|
||||
metadata?: Metadata | null | undefined;
|
||||
eoa?: boolean | undefined;
|
||||
showCodeIndicator?: boolean;
|
||||
};
|
||||
|
||||
const TransactionAddress: React.FC<TransactionAddressProps> = ({
|
||||
address,
|
||||
addressCtx,
|
||||
metadata,
|
||||
eoa,
|
||||
showCodeIndicator = false,
|
||||
}) => {
|
||||
const txData = useSelectedTransaction();
|
||||
// TODO: push down creation coloring logic into DecoratedAddressLink
|
||||
const creation = address === txData?.confirmedData?.createdContractAddress;
|
||||
|
||||
const { provider } = useContext(RuntimeContext);
|
||||
const blockNumber = useBlockNumberContext();
|
||||
const toHasCode = useHasCode(
|
||||
provider,
|
||||
address,
|
||||
blockNumber !== undefined ? blockNumber - 1 : undefined
|
||||
);
|
||||
|
||||
return (
|
||||
<AddressHighlighter address={address}>
|
||||
<DecoratedAddressLink
|
||||
|
@ -32,7 +43,11 @@ const TransactionAddress: React.FC<TransactionAddressProps> = ({
|
|||
txTo={address === txData?.to || creation}
|
||||
creation={creation}
|
||||
metadata={metadata}
|
||||
eoa={eoa}
|
||||
eoa={
|
||||
showCodeIndicator !== undefined && blockNumber !== undefined
|
||||
? !toHasCode
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</AddressHighlighter>
|
||||
);
|
||||
|
|
|
@ -45,7 +45,7 @@ import {
|
|||
import { DevDoc, Metadata, useError, UserDoc } from "../sourcify/useSourcify";
|
||||
import { RuntimeContext } from "../useRuntime";
|
||||
import { useContractsMetadata } from "../hooks";
|
||||
import { useHasCode, useTransactionError } from "../useErigonHooks";
|
||||
import { useTransactionError } from "../useErigonHooks";
|
||||
|
||||
type DetailsProps = {
|
||||
txData: TransactionData;
|
||||
|
@ -118,12 +118,6 @@ const Details: React.FC<DetailsProps> = ({
|
|||
: undefined;
|
||||
const [expanded, setExpanded] = useState<boolean>(false);
|
||||
|
||||
const toHasCode = useHasCode(
|
||||
provider,
|
||||
txData.to,
|
||||
txData.confirmedData ? txData.confirmedData.blockNumber - 1 : undefined
|
||||
);
|
||||
|
||||
return (
|
||||
<ContentFrame tabs>
|
||||
<InfoRow title="Transaction Hash">
|
||||
|
@ -270,7 +264,7 @@ const Details: React.FC<DetailsProps> = ({
|
|||
<TransactionAddress
|
||||
address={txData.to}
|
||||
metadata={metadatas?.[txData.to]}
|
||||
eoa={toHasCode === undefined ? undefined : !toHasCode}
|
||||
showCodeIndicator
|
||||
/>
|
||||
<Copy value={txData.to} />
|
||||
</div>
|
||||
|
@ -314,7 +308,6 @@ const Details: React.FC<DetailsProps> = ({
|
|||
t={t}
|
||||
tokenMeta={txData.tokenMetas[t.token]}
|
||||
metadatas={metadatas}
|
||||
txData={txData}
|
||||
/>
|
||||
))}
|
||||
</InfoRow>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useContext, useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faBomb } from "@fortawesome/free-solid-svg-icons/faBomb";
|
||||
import TransactionAddress from "../components/TransactionAddress";
|
||||
|
@ -6,8 +6,7 @@ import FormattedBalance from "../components/FormattedBalance";
|
|||
import FunctionSignature from "./FunctionSignature";
|
||||
import InputDecoder from "./decoder/InputDecoder";
|
||||
import ExpanderSwitch from "../components/ExpanderSwitch";
|
||||
import { RuntimeContext } from "../useRuntime";
|
||||
import { TraceEntry, useHasCode } from "../useErigonHooks";
|
||||
import { TraceEntry } from "../useErigonHooks";
|
||||
import {
|
||||
extract4Bytes,
|
||||
use4Bytes,
|
||||
|
@ -35,15 +34,6 @@ const TraceInput: React.FC<TraceInputProps> = ({ t, txData }) => {
|
|||
|
||||
const [expanded, setExpanded] = useState<boolean>(false);
|
||||
|
||||
const { provider } = useContext(RuntimeContext);
|
||||
const toHasCode = useHasCode(
|
||||
provider,
|
||||
t.to,
|
||||
txData.confirmedData !== undefined
|
||||
? txData.confirmedData.blockNumber - 1
|
||||
: undefined
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`ml-5 border hover:border-gray-500 rounded px-1 py-0.5 ${
|
||||
|
@ -59,10 +49,7 @@ const TraceInput: React.FC<TraceInputProps> = ({ t, txData }) => {
|
|||
) : (
|
||||
<>
|
||||
<span>
|
||||
<TransactionAddress
|
||||
address={t.to}
|
||||
eoa={toHasCode === undefined ? undefined : !toHasCode}
|
||||
/>
|
||||
<TransactionAddress address={t.to} showCodeIndicator />
|
||||
</span>
|
||||
{t.type !== "CREATE" && t.type !== "CREATE2" && (
|
||||
<>
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import React from "react";
|
||||
import TransactionAddress from "../../components/TransactionAddress";
|
||||
import Copy from "../../components/Copy";
|
||||
import { ChecksummedAddress } from "../../types";
|
||||
|
||||
type AddressDecoderProps = {
|
||||
r: string;
|
||||
r: ChecksummedAddress;
|
||||
};
|
||||
|
||||
const AddressDecoder: React.FC<AddressDecoderProps> = ({ r }) => (
|
||||
<div className="flex items-baseline space-x-2 -ml-1 mr-3">
|
||||
<TransactionAddress address={r} />
|
||||
<TransactionAddress address={r} showCodeIndicator />
|
||||
<Copy value={r} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { createContext, useContext } from "react";
|
||||
|
||||
/**
|
||||
* This context means child components have a temporal context expressed in
|
||||
* terms of BlockTag.
|
||||
*
|
||||
* One obvious example is: child components want to show an UI indicator if
|
||||
* the address is an EOA or contract. But if this address is currently a
|
||||
* contract and it is an UI element of an existing transaction, it may be that
|
||||
* at the time (block) the transaction happened it was still an EOA (create2),
|
||||
* so it should be displayed as an EOA.
|
||||
*/
|
||||
export const BlockNumberContext = createContext<number | undefined>(undefined);
|
||||
|
||||
export const useBlockNumberContext = () => useContext(BlockNumberContext);
|
Loading…
Reference in New Issue