Merge branch 'feature/transaction-context' into develop
This commit is contained in:
commit
c63a25ad6d
|
@ -1,9 +1,8 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faCaretRight } from "@fortawesome/free-solid-svg-icons/faCaretRight";
|
import { faCaretRight } from "@fortawesome/free-solid-svg-icons/faCaretRight";
|
||||||
import AddressHighlighter from "./components/AddressHighlighter";
|
import TransactionAddress from "./components/TransactionAddress";
|
||||||
import ValueHighlighter from "./components/ValueHighlighter";
|
import ValueHighlighter from "./components/ValueHighlighter";
|
||||||
import DecoratedAddressLink from "./components/DecoratedAddressLink";
|
|
||||||
import FormattedBalance from "./components/FormattedBalance";
|
import FormattedBalance from "./components/FormattedBalance";
|
||||||
import {
|
import {
|
||||||
AddressContext,
|
AddressContext,
|
||||||
|
@ -34,27 +33,19 @@ const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
|
||||||
<div className="grid grid-cols-5 gap-x-1">
|
<div className="grid grid-cols-5 gap-x-1">
|
||||||
<div className="flex space-x-1">
|
<div className="flex space-x-1">
|
||||||
<span className="font-bold">From</span>
|
<span className="font-bold">From</span>
|
||||||
<AddressHighlighter address={t.from}>
|
<TransactionAddress
|
||||||
<DecoratedAddressLink
|
address={t.from}
|
||||||
address={t.from}
|
addressCtx={AddressContext.FROM}
|
||||||
addressCtx={AddressContext.FROM}
|
resolvedAddresses={resolvedAddresses}
|
||||||
txFrom={t.from === txData.from}
|
/>
|
||||||
txTo={t.from === txData.to}
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-1">
|
<div className="flex space-x-1">
|
||||||
<span className="font-bold">To</span>
|
<span className="font-bold">To</span>
|
||||||
<AddressHighlighter address={t.to}>
|
<TransactionAddress
|
||||||
<DecoratedAddressLink
|
address={t.to}
|
||||||
address={t.to}
|
addressCtx={AddressContext.TO}
|
||||||
addressCtx={AddressContext.TO}
|
resolvedAddresses={resolvedAddresses}
|
||||||
txFrom={t.to === txData.from}
|
/>
|
||||||
txTo={t.to === txData.to}
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-3 flex space-x-1">
|
<div className="col-span-3 flex space-x-1">
|
||||||
<span className="font-bold">For</span>
|
<span className="font-bold">For</span>
|
||||||
|
@ -66,12 +57,10 @@ const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
|
||||||
/>
|
/>
|
||||||
</ValueHighlighter>
|
</ValueHighlighter>
|
||||||
</span>
|
</span>
|
||||||
<AddressHighlighter address={t.token}>
|
<TransactionAddress
|
||||||
<DecoratedAddressLink
|
address={t.token}
|
||||||
address={t.token}
|
resolvedAddresses={resolvedAddresses}
|
||||||
resolvedAddresses={resolvedAddresses}
|
/>
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
transactionDataCollector,
|
transactionDataCollector,
|
||||||
useResolvedAddresses,
|
useResolvedAddresses,
|
||||||
} from "./useResolvedAddresses";
|
} from "./useResolvedAddresses";
|
||||||
|
import { SelectedTransactionContext } from "./useSelectedTransaction";
|
||||||
|
|
||||||
const Details = React.lazy(
|
const Details = React.lazy(
|
||||||
() =>
|
() =>
|
||||||
|
@ -76,54 +77,56 @@ const Transaction: React.FC = () => {
|
||||||
const txDesc = useTransactionDescription(metadata, txData);
|
const txDesc = useTransactionDescription(metadata, txData);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StandardFrame>
|
<SelectedTransactionContext.Provider value={txData}>
|
||||||
<StandardSubtitle>Transaction Details</StandardSubtitle>
|
<StandardFrame>
|
||||||
{txData === null && (
|
<StandardSubtitle>Transaction Details</StandardSubtitle>
|
||||||
<ContentFrame>
|
{txData === null && (
|
||||||
<div className="py-4 text-sm">
|
<ContentFrame>
|
||||||
Transaction <span className="font-hash">{txhash}</span> not found.
|
<div className="py-4 text-sm">
|
||||||
</div>
|
Transaction <span className="font-hash">{txhash}</span> not found.
|
||||||
</ContentFrame>
|
</div>
|
||||||
)}
|
</ContentFrame>
|
||||||
{txData && (
|
)}
|
||||||
<SelectionContext.Provider value={selectionCtx}>
|
{txData && (
|
||||||
<Tab.Group>
|
<SelectionContext.Provider value={selectionCtx}>
|
||||||
<Tab.List className="flex space-x-2 border-l border-r border-t rounded-t-lg bg-white">
|
<Tab.Group>
|
||||||
<NavTab href={`/tx/${txhash}`}>Overview</NavTab>
|
<Tab.List className="flex space-x-2 border-l border-r border-t rounded-t-lg bg-white">
|
||||||
{txData.confirmedData?.blockNumber !== undefined && (
|
<NavTab href={`/tx/${txhash}`}>Overview</NavTab>
|
||||||
<NavTab href={`/tx/${txhash}/logs`}>
|
{txData.confirmedData?.blockNumber !== undefined && (
|
||||||
Logs
|
<NavTab href={`/tx/${txhash}/logs`}>
|
||||||
{txData && ` (${txData.confirmedData?.logs?.length ?? 0})`}
|
Logs
|
||||||
</NavTab>
|
{txData && ` (${txData.confirmedData?.logs?.length ?? 0})`}
|
||||||
)}
|
</NavTab>
|
||||||
</Tab.List>
|
)}
|
||||||
</Tab.Group>
|
</Tab.List>
|
||||||
<React.Suspense fallback={null}>
|
</Tab.Group>
|
||||||
<Switch>
|
<React.Suspense fallback={null}>
|
||||||
<Route path="/tx/:txhash/" exact>
|
<Switch>
|
||||||
<Details
|
<Route path="/tx/:txhash/" exact>
|
||||||
txData={txData}
|
<Details
|
||||||
txDesc={txDesc}
|
txData={txData}
|
||||||
userDoc={metadata?.output.userdoc}
|
txDesc={txDesc}
|
||||||
devDoc={metadata?.output.devdoc}
|
userDoc={metadata?.output.userdoc}
|
||||||
internalOps={internalOps}
|
devDoc={metadata?.output.devdoc}
|
||||||
sendsEthToMiner={sendsEthToMiner}
|
internalOps={internalOps}
|
||||||
ethUSDPrice={blockETHUSDPrice}
|
sendsEthToMiner={sendsEthToMiner}
|
||||||
resolvedAddresses={resolvedAddresses}
|
ethUSDPrice={blockETHUSDPrice}
|
||||||
/>
|
resolvedAddresses={resolvedAddresses}
|
||||||
</Route>
|
/>
|
||||||
<Route path="/tx/:txhash/logs/" exact>
|
</Route>
|
||||||
<Logs
|
<Route path="/tx/:txhash/logs/" exact>
|
||||||
txData={txData}
|
<Logs
|
||||||
metadata={metadata}
|
txData={txData}
|
||||||
resolvedAddresses={resolvedAddresses}
|
metadata={metadata}
|
||||||
/>
|
resolvedAddresses={resolvedAddresses}
|
||||||
</Route>
|
/>
|
||||||
</Switch>
|
</Route>
|
||||||
</React.Suspense>
|
</Switch>
|
||||||
</SelectionContext.Provider>
|
</React.Suspense>
|
||||||
)}
|
</SelectionContext.Provider>
|
||||||
</StandardFrame>
|
)}
|
||||||
|
</StandardFrame>
|
||||||
|
</SelectedTransactionContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React from "react";
|
||||||
|
import AddressHighlighter from "./AddressHighlighter";
|
||||||
|
import DecoratedAddressLink from "./DecoratedAddressLink";
|
||||||
|
import { ResolvedAddresses } from "../api/address-resolver";
|
||||||
|
import { useSelectedTransaction } from "../useSelectedTransaction";
|
||||||
|
import { AddressContext } from "../types";
|
||||||
|
|
||||||
|
type TransactionAddressProps = {
|
||||||
|
address: string;
|
||||||
|
addressCtx?: AddressContext | undefined;
|
||||||
|
resolvedAddresses: ResolvedAddresses | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TransactionAddress: React.FC<TransactionAddressProps> = ({
|
||||||
|
address,
|
||||||
|
addressCtx,
|
||||||
|
resolvedAddresses,
|
||||||
|
}) => {
|
||||||
|
const txData = useSelectedTransaction();
|
||||||
|
// TODO: push down creation coloring logic into DecoratedAddressLink
|
||||||
|
const creation = address === txData?.confirmedData?.createdContractAddress;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AddressHighlighter address={address}>
|
||||||
|
<DecoratedAddressLink
|
||||||
|
address={address}
|
||||||
|
addressCtx={addressCtx}
|
||||||
|
miner={address === txData?.confirmedData?.miner}
|
||||||
|
txFrom={address === txData?.from}
|
||||||
|
txTo={address === txData?.to || creation}
|
||||||
|
creation={creation}
|
||||||
|
resolvedAddresses={resolvedAddresses}
|
||||||
|
/>
|
||||||
|
</AddressHighlighter>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TransactionAddress;
|
|
@ -15,8 +15,7 @@ import ContentFrame from "../ContentFrame";
|
||||||
import InfoRow from "../components/InfoRow";
|
import InfoRow from "../components/InfoRow";
|
||||||
import BlockLink from "../components/BlockLink";
|
import BlockLink from "../components/BlockLink";
|
||||||
import BlockConfirmations from "../components/BlockConfirmations";
|
import BlockConfirmations from "../components/BlockConfirmations";
|
||||||
import AddressHighlighter from "../components/AddressHighlighter";
|
import TransactionAddress from "../components/TransactionAddress";
|
||||||
import DecoratedAddressLink from "../components/DecoratedAddressLink";
|
|
||||||
import Copy from "../components/Copy";
|
import Copy from "../components/Copy";
|
||||||
import Nonce from "../components/Nonce";
|
import Nonce from "../components/Nonce";
|
||||||
import Timestamp from "../components/Timestamp";
|
import Timestamp from "../components/Timestamp";
|
||||||
|
@ -152,14 +151,10 @@ const Details: React.FC<DetailsProps> = ({
|
||||||
<InfoRow title="From / Nonce">
|
<InfoRow title="From / Nonce">
|
||||||
<div className="flex divide-x-2 divide-dotted divide-gray-300">
|
<div className="flex divide-x-2 divide-dotted divide-gray-300">
|
||||||
<div className="flex items-baseline space-x-2 -ml-1 mr-3">
|
<div className="flex items-baseline space-x-2 -ml-1 mr-3">
|
||||||
<AddressHighlighter address={txData.from}>
|
<TransactionAddress
|
||||||
<DecoratedAddressLink
|
address={txData.from}
|
||||||
address={txData.from}
|
resolvedAddresses={resolvedAddresses}
|
||||||
miner={txData.from === txData.confirmedData?.miner}
|
/>
|
||||||
txFrom
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
<Copy value={txData.from} />
|
<Copy value={txData.from} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-baseline pl-3">
|
<div className="flex items-baseline pl-3">
|
||||||
|
@ -170,14 +165,10 @@ const Details: React.FC<DetailsProps> = ({
|
||||||
<InfoRow title={txData.to ? "Interacted With (To)" : "Contract Created"}>
|
<InfoRow title={txData.to ? "Interacted With (To)" : "Contract Created"}>
|
||||||
{txData.to ? (
|
{txData.to ? (
|
||||||
<div className="flex items-baseline space-x-2 -ml-1">
|
<div className="flex items-baseline space-x-2 -ml-1">
|
||||||
<AddressHighlighter address={txData.to}>
|
<TransactionAddress
|
||||||
<DecoratedAddressLink
|
address={txData.to}
|
||||||
address={txData.to}
|
resolvedAddresses={resolvedAddresses}
|
||||||
miner={txData.to === txData.confirmedData?.miner}
|
/>
|
||||||
txTo
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
<Copy value={txData.to} />
|
<Copy value={txData.to} />
|
||||||
</div>
|
</div>
|
||||||
) : txData.confirmedData === undefined ? (
|
) : txData.confirmedData === undefined ? (
|
||||||
|
@ -186,16 +177,10 @@ const Details: React.FC<DetailsProps> = ({
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex items-baseline space-x-2 -ml-1">
|
<div className="flex items-baseline space-x-2 -ml-1">
|
||||||
<AddressHighlighter
|
<TransactionAddress
|
||||||
address={txData.confirmedData?.createdContractAddress!}
|
address={txData.confirmedData?.createdContractAddress!}
|
||||||
>
|
resolvedAddresses={resolvedAddresses}
|
||||||
<DecoratedAddressLink
|
/>
|
||||||
address={txData.confirmedData.createdContractAddress!}
|
|
||||||
creation
|
|
||||||
txTo
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
<Copy value={txData.confirmedData.createdContractAddress!} />
|
<Copy value={txData.confirmedData.createdContractAddress!} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -2,8 +2,7 @@ import React, { useMemo } from "react";
|
||||||
import { Log } from "@ethersproject/abstract-provider";
|
import { Log } from "@ethersproject/abstract-provider";
|
||||||
import { Fragment, Interface, LogDescription } from "@ethersproject/abi";
|
import { Fragment, Interface, LogDescription } from "@ethersproject/abi";
|
||||||
import { Tab } from "@headlessui/react";
|
import { Tab } from "@headlessui/react";
|
||||||
import AddressHighlighter from "../components/AddressHighlighter";
|
import TransactionAddress from "../components/TransactionAddress";
|
||||||
import DecoratedAddressLink from "../components/DecoratedAddressLink";
|
|
||||||
import Copy from "../components/Copy";
|
import Copy from "../components/Copy";
|
||||||
import ModeTab from "../components/ModeTab";
|
import ModeTab from "../components/ModeTab";
|
||||||
import DecodedParamsTable from "./decoder/DecodedParamsTable";
|
import DecodedParamsTable from "./decoder/DecodedParamsTable";
|
||||||
|
@ -63,15 +62,10 @@ const LogEntry: React.FC<LogEntryProps> = ({
|
||||||
<div className="font-bold text-right">Address</div>
|
<div className="font-bold text-right">Address</div>
|
||||||
<div className="col-span-11 mr-auto">
|
<div className="col-span-11 mr-auto">
|
||||||
<div className="flex items-baseline space-x-2 -ml-1 mr-3">
|
<div className="flex items-baseline space-x-2 -ml-1 mr-3">
|
||||||
<AddressHighlighter address={log.address}>
|
<TransactionAddress
|
||||||
<DecoratedAddressLink
|
address={log.address}
|
||||||
address={log.address}
|
resolvedAddresses={resolvedAddresses}
|
||||||
miner={log.address === txData.confirmedData?.miner}
|
/>
|
||||||
txFrom={log.address === txData.from}
|
|
||||||
txTo={log.address === txData.to}
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
<Copy value={log.address} />
|
<Copy value={log.address} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,31 +1,22 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import AddressHighlighter from "../../components/AddressHighlighter";
|
|
||||||
import DecoratedAddressLink from "../../components/DecoratedAddressLink";
|
|
||||||
import Copy from "../../components/Copy";
|
import Copy from "../../components/Copy";
|
||||||
import { TransactionData } from "../../types";
|
|
||||||
import { ResolvedAddresses } from "../../api/address-resolver";
|
import { ResolvedAddresses } from "../../api/address-resolver";
|
||||||
|
import TransactionAddress from "../../components/TransactionAddress";
|
||||||
|
|
||||||
type AddressDecoderProps = {
|
type AddressDecoderProps = {
|
||||||
r: any;
|
r: any;
|
||||||
txData: TransactionData;
|
|
||||||
resolvedAddresses?: ResolvedAddresses | undefined;
|
resolvedAddresses?: ResolvedAddresses | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AddressDecoder: React.FC<AddressDecoderProps> = ({
|
const AddressDecoder: React.FC<AddressDecoderProps> = ({
|
||||||
r,
|
r,
|
||||||
txData,
|
|
||||||
resolvedAddresses,
|
resolvedAddresses,
|
||||||
}) => (
|
}) => (
|
||||||
<div className="flex items-baseline space-x-2 -ml-1 mr-3">
|
<div className="flex items-baseline space-x-2 -ml-1 mr-3">
|
||||||
<AddressHighlighter address={r.toString()}>
|
<TransactionAddress
|
||||||
<DecoratedAddressLink
|
address={r.toString()}
|
||||||
address={r.toString()}
|
resolvedAddresses={resolvedAddresses}
|
||||||
miner={r.toString() === txData.confirmedData?.miner}
|
/>
|
||||||
txFrom={r.toString() === txData.from}
|
|
||||||
txTo={r.toString() === txData.to}
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
</AddressHighlighter>
|
|
||||||
<Copy value={r.toString()} />
|
<Copy value={r.toString()} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -75,11 +75,7 @@ const DecodedParamRow: React.FC<DecodedParamRowProps> = ({
|
||||||
{paramType.baseType === "uint256" ? (
|
{paramType.baseType === "uint256" ? (
|
||||||
<Uint256Decoder r={r} />
|
<Uint256Decoder r={r} />
|
||||||
) : paramType.baseType === "address" ? (
|
) : paramType.baseType === "address" ? (
|
||||||
<AddressDecoder
|
<AddressDecoder r={r} resolvedAddresses={resolvedAddresses} />
|
||||||
r={r}
|
|
||||||
txData={txData}
|
|
||||||
resolvedAddresses={resolvedAddresses}
|
|
||||||
/>
|
|
||||||
) : paramType.baseType === "bool" ? (
|
) : paramType.baseType === "bool" ? (
|
||||||
<BooleanDecoder r={r} />
|
<BooleanDecoder r={r} />
|
||||||
) : paramType.baseType === "bytes" ? (
|
) : paramType.baseType === "bytes" ? (
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { createContext, useContext } from "react";
|
||||||
|
import { TransactionData } from "./types";
|
||||||
|
|
||||||
|
export const SelectedTransactionContext = createContext<
|
||||||
|
TransactionData | null | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
|
export const useSelectedTransaction = () =>
|
||||||
|
useContext(SelectedTransactionContext);
|
Loading…
Reference in New Issue