Split block confirmation data into its own hook

This commit is contained in:
Willian Mitsuda 2022-08-24 04:34:41 -03:00
parent 34f812aed0
commit e3a21bd4b2
No known key found for this signature in database
7 changed files with 67 additions and 60 deletions

View File

@ -1,10 +1,12 @@
import React from "react"; import React, { useContext } from "react";
import { formatEther } from "@ethersproject/units"; import { formatEther } from "@ethersproject/units";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleRight } from "@fortawesome/free-solid-svg-icons/faAngleRight"; import { faAngleRight } from "@fortawesome/free-solid-svg-icons/faAngleRight";
import AddressHighlighter from "./AddressHighlighter"; import AddressHighlighter from "./AddressHighlighter";
import DecoratedAddressLink from "./DecoratedAddressLink"; import DecoratedAddressLink from "./DecoratedAddressLink";
import TransactionAddress from "./TransactionAddress"; import TransactionAddress from "./TransactionAddress";
import { RuntimeContext } from "../useRuntime";
import { useBlockDataFromTransaction } from "../useErigonHooks";
import { useChainInfo } from "../useChainInfo"; import { useChainInfo } from "../useChainInfo";
import { TransactionData, InternalOperation } from "../types"; import { TransactionData, InternalOperation } from "../types";
@ -17,12 +19,12 @@ const InternalSelfDestruct: React.FC<InternalSelfDestructProps> = ({
txData, txData,
internalOp, internalOp,
}) => { }) => {
const { provider } = useContext(RuntimeContext);
const block = useBlockDataFromTransaction(provider, txData);
const { const {
nativeCurrency: { symbol }, nativeCurrency: { symbol },
} = useChainInfo(); } = useChainInfo();
const toMiner = const toMiner = block?.miner !== undefined && internalOp.to === block.miner;
txData.confirmedData?.miner !== undefined &&
internalOp.to === txData.confirmedData.miner;
return ( return (
<> <>

View File

@ -8,7 +8,7 @@ import AddressHighlighter from "./AddressHighlighter";
import DecoratedAddressLink from "./DecoratedAddressLink"; import DecoratedAddressLink from "./DecoratedAddressLink";
import USDAmount from "./USDAmount"; import USDAmount from "./USDAmount";
import { RuntimeContext } from "../useRuntime"; import { RuntimeContext } from "../useRuntime";
import { useHasCode } from "../useErigonHooks"; import { useBlockDataFromTransaction, useHasCode } from "../useErigonHooks";
import { useChainInfo } from "../useChainInfo"; import { useChainInfo } from "../useChainInfo";
import { useETHUSDOracle } from "../usePriceOracle"; import { useETHUSDOracle } from "../usePriceOracle";
import { TransactionData, InternalOperation } from "../types"; import { TransactionData, InternalOperation } from "../types";
@ -22,17 +22,16 @@ const InternalTransfer: React.FC<InternalTransferProps> = ({
txData, txData,
internalOp, internalOp,
}) => { }) => {
const { provider } = useContext(RuntimeContext);
const block = useBlockDataFromTransaction(provider, txData);
const { const {
nativeCurrency: { symbol, decimals }, nativeCurrency: { symbol, decimals },
} = useChainInfo(); } = useChainInfo();
const fromMiner = const fromMiner =
txData.confirmedData?.miner !== undefined && block?.miner !== undefined && internalOp.from === block.miner;
internalOp.from === txData.confirmedData.miner; const toMiner = block?.miner !== undefined && internalOp.to === block.miner;
const toMiner =
txData.confirmedData?.miner !== undefined &&
internalOp.to === txData.confirmedData.miner;
const { provider } = useContext(RuntimeContext);
const blockETHUSDPrice = useETHUSDOracle( const blockETHUSDPrice = useETHUSDOracle(
provider, provider,
txData.confirmedData?.blockNumber txData.confirmedData?.blockNumber

View File

@ -4,7 +4,7 @@ import DecoratedAddressLink from "./DecoratedAddressLink";
import { useSelectedTransaction } from "../useSelectedTransaction"; import { useSelectedTransaction } from "../useSelectedTransaction";
import { useBlockNumberContext } from "../useBlockTagContext"; import { useBlockNumberContext } from "../useBlockTagContext";
import { RuntimeContext } from "../useRuntime"; import { RuntimeContext } from "../useRuntime";
import { useHasCode } from "../useErigonHooks"; import { useBlockDataFromTransaction, useHasCode } from "../useErigonHooks";
import { AddressContext, ChecksummedAddress } from "../types"; import { AddressContext, ChecksummedAddress } from "../types";
type TransactionAddressProps = { type TransactionAddressProps = {
@ -23,6 +23,8 @@ const TransactionAddress: React.FC<TransactionAddressProps> = ({
const creation = address === txData?.confirmedData?.createdContractAddress; const creation = address === txData?.confirmedData?.createdContractAddress;
const { provider } = useContext(RuntimeContext); const { provider } = useContext(RuntimeContext);
const block = useBlockDataFromTransaction(provider, txData);
const blockNumber = useBlockNumberContext(); const blockNumber = useBlockNumberContext();
const toHasCode = useHasCode( const toHasCode = useHasCode(
provider, provider,
@ -39,7 +41,7 @@ const TransactionAddress: React.FC<TransactionAddressProps> = ({
<DecoratedAddressLink <DecoratedAddressLink
address={address} address={address}
addressCtx={addressCtx} addressCtx={addressCtx}
miner={address === txData?.confirmedData?.miner} miner={address === block?.miner}
txFrom={address === txData?.from} txFrom={address === txData?.from}
txTo={address === txData?.to || creation} txTo={address === txData?.to || creation}
creation={creation} creation={creation}

View File

@ -44,6 +44,7 @@ import {
} from "../sourcify/useSourcify"; } from "../sourcify/useSourcify";
import { RuntimeContext } from "../useRuntime"; import { RuntimeContext } from "../useRuntime";
import { import {
useBlockDataFromTransaction,
useSendsToMiner, useSendsToMiner,
useTokenTransfers, useTokenTransfers,
useTransactionError, useTransactionError,
@ -57,10 +58,10 @@ type DetailsProps = {
const Details: React.FC<DetailsProps> = ({ txData }) => { const Details: React.FC<DetailsProps> = ({ txData }) => {
const { provider } = useContext(RuntimeContext); const { provider } = useContext(RuntimeContext);
const block = useBlockDataFromTransaction(provider, txData);
const hasEIP1559 = const hasEIP1559 =
txData.confirmedData?.blockBaseFeePerGas !== undefined && block?.baseFeePerGas !== undefined && block?.baseFeePerGas !== null;
txData.confirmedData?.blockBaseFeePerGas !== null;
const fourBytes = const fourBytes =
txData.to !== null ? extract4Bytes(txData.data) ?? "0x" : "0x"; txData.to !== null ? extract4Bytes(txData.data) ?? "0x" : "0x";
@ -74,7 +75,7 @@ const Details: React.FC<DetailsProps> = ({ txData }) => {
const [sendsEthToMiner, internalOps] = useSendsToMiner( const [sendsEthToMiner, internalOps] = useSendsToMiner(
provider, provider,
txData.confirmedData ? txData.transactionHash : undefined, txData.confirmedData ? txData.transactionHash : undefined,
txData.confirmedData?.miner block?.miner
); );
const tokenTransfers = useTokenTransfers(txData); const tokenTransfers = useTokenTransfers(txData);
@ -222,22 +223,24 @@ const Details: React.FC<DetailsProps> = ({ txData }) => {
confirmations={txData.confirmedData.confirmations} confirmations={txData.confirmedData.confirmations}
/> />
</div> </div>
{block && (
<div className="flex space-x-2 items-baseline pl-3"> <div className="flex space-x-2 items-baseline pl-3">
<RelativePosition <RelativePosition
pos={txData.confirmedData.transactionIndex} pos={txData.confirmedData.transactionIndex}
total={txData.confirmedData.blockTransactionCount - 1} total={block.transactionCount - 1}
/> />
<PercentagePosition <PercentagePosition
perc={ perc={
txData.confirmedData.transactionIndex / txData.confirmedData.transactionIndex /
(txData.confirmedData.blockTransactionCount - 1) (block.transactionCount - 1)
} }
/> />
</div> </div>
)}
</div> </div>
</InfoRow> </InfoRow>
<InfoRow title="Timestamp"> <InfoRow title="Timestamp">
<Timestamp value={txData.confirmedData.timestamp} /> {block && <Timestamp value={block.timestamp} />}
</InfoRow> </InfoRow>
</> </>
)} )}
@ -366,18 +369,10 @@ const Details: React.FC<DetailsProps> = ({ txData }) => {
</div> </div>
</InfoRow> </InfoRow>
)} )}
{txData.confirmedData && hasEIP1559 && ( {block && hasEIP1559 && (
<InfoRow title="Block Base Fee"> <InfoRow title="Block Base Fee">
<FormattedBalance <FormattedBalance value={block.baseFeePerGas!} decimals={9} /> Gwei (
value={txData.confirmedData.blockBaseFeePerGas!} <FormattedBalance value={block.baseFeePerGas!} decimals={0} /> wei)
decimals={9}
/>{" "}
Gwei (
<FormattedBalance
value={txData.confirmedData.blockBaseFeePerGas!}
decimals={0}
/>{" "}
wei)
</InfoRow> </InfoRow>
)} )}
{txData.confirmedData && ( {txData.confirmedData && (

View File

@ -1,24 +1,30 @@
import React from "react"; import React, { useContext } from "react";
import { BigNumber } from "@ethersproject/bignumber";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBurn } from "@fortawesome/free-solid-svg-icons/faBurn"; import { faBurn } from "@fortawesome/free-solid-svg-icons/faBurn";
import { faCoins } from "@fortawesome/free-solid-svg-icons/faCoins"; import { faCoins } from "@fortawesome/free-solid-svg-icons/faCoins";
import FormattedBalance from "../components/FormattedBalance"; import FormattedBalance from "../components/FormattedBalance";
import PercentageGauge from "../components/PercentageGauge"; import PercentageGauge from "../components/PercentageGauge";
import { TransactionData } from "../types"; import { RuntimeContext } from "../useRuntime";
import { useBlockDataFromTransaction } from "../useErigonHooks";
import { useChainInfo } from "../useChainInfo"; import { useChainInfo } from "../useChainInfo";
import { TransactionData } from "../types";
type RewardSplitProps = { type RewardSplitProps = {
txData: TransactionData; txData: TransactionData;
}; };
const RewardSplit: React.FC<RewardSplitProps> = ({ txData }) => { const RewardSplit: React.FC<RewardSplitProps> = ({ txData }) => {
const { provider } = useContext(RuntimeContext);
const block = useBlockDataFromTransaction(provider, txData);
const { const {
nativeCurrency: { symbol }, nativeCurrency: { symbol },
} = useChainInfo(); } = useChainInfo();
const paidFees = txData.gasPrice.mul(txData.confirmedData!.gasUsed); const paidFees = txData.gasPrice.mul(txData.confirmedData!.gasUsed);
const burntFees = txData.confirmedData!.blockBaseFeePerGas!.mul( const burntFees = block
txData.confirmedData!.gasUsed ? block.baseFeePerGas!.mul(txData.confirmedData!.gasUsed)
); : BigNumber.from(0);
const minerReward = paidFees.sub(burntFees); const minerReward = paidFees.sub(burntFees);
const burntPerc = const burntPerc =

View File

@ -50,11 +50,7 @@ export type ConfirmedTransactionData = {
status: boolean; status: boolean;
blockNumber: number; blockNumber: number;
transactionIndex: number; transactionIndex: number;
blockBaseFeePerGas?: BigNumber | undefined | null;
blockTransactionCount: number;
confirmations: number; confirmations: number;
timestamp: number;
miner: string;
createdContractAddress?: string; createdContractAddress?: string;
fee: BigNumber; fee: BigNumber;
gasUsed: BigNumber; gasUsed: BigNumber;

View File

@ -155,12 +155,15 @@ const blockDataFetcher = async (
return await readBlock(provider, blockNumberOrHash); return await readBlock(provider, blockNumberOrHash);
}; };
// TODO: some callers may use only block headers?
export const useBlockData = ( export const useBlockData = (
provider: JsonRpcProvider | undefined, provider: JsonRpcProvider | undefined,
blockNumberOrHash: string blockNumberOrHash: string | undefined
): ExtendedBlock | null | undefined => { ): ExtendedBlock | null | undefined => {
const { data, error } = useSWRImmutable( const { data, error } = useSWRImmutable(
provider !== undefined ? [provider, blockNumberOrHash] : null, provider !== undefined && blockNumberOrHash !== undefined
? [provider, blockNumberOrHash]
: null,
blockDataFetcher blockDataFetcher
); );
if (error) { if (error) {
@ -169,6 +172,19 @@ export const useBlockData = (
return data; return data;
}; };
export const useBlockDataFromTransaction = (
provider: JsonRpcProvider | undefined,
txData: TransactionData | null | undefined
): ExtendedBlock | null | undefined => {
const block = useBlockData(
provider,
txData?.confirmedData
? txData.confirmedData.blockNumber.toString()
: undefined
);
return block;
};
export const useTxData = ( export const useTxData = (
provider: JsonRpcProvider | undefined, provider: JsonRpcProvider | undefined,
txhash: string txhash: string
@ -191,11 +207,6 @@ export const useTxData = (
return; return;
} }
let _block: ExtendedBlock | null | undefined;
if (_response.blockNumber) {
_block = await readBlock(provider, _response.blockNumber.toString());
}
document.title = `Transaction ${_response.hash} | Otterscan`; document.title = `Transaction ${_response.hash} | Otterscan`;
setTxData({ setTxData({
@ -217,11 +228,7 @@ export const useTxData = (
status: _receipt.status === 1, status: _receipt.status === 1,
blockNumber: _receipt.blockNumber, blockNumber: _receipt.blockNumber,
transactionIndex: _receipt.transactionIndex, transactionIndex: _receipt.transactionIndex,
blockBaseFeePerGas: _block!.baseFeePerGas,
blockTransactionCount: _block!.transactionCount,
confirmations: _receipt.confirmations, confirmations: _receipt.confirmations,
timestamp: _block!.timestamp,
miner: _block!.miner,
createdContractAddress: _receipt.contractAddress, createdContractAddress: _receipt.contractAddress,
fee: _response.gasPrice!.mul(_receipt.gasUsed), fee: _response.gasPrice!.mul(_receipt.gasUsed),
gasUsed: _receipt.gasUsed, gasUsed: _receipt.gasUsed,