Squash initial implementation of usd prices
This commit is contained in:
parent
0f6401cc07
commit
859761f2ba
@ -17,11 +17,14 @@ import BlockLink from "./components/BlockLink";
|
|||||||
import DecoratedAddressLink from "./components/DecoratedAddressLink";
|
import DecoratedAddressLink from "./components/DecoratedAddressLink";
|
||||||
import TransactionValue from "./components/TransactionValue";
|
import TransactionValue from "./components/TransactionValue";
|
||||||
import FormattedBalance from "./components/FormattedBalance";
|
import FormattedBalance from "./components/FormattedBalance";
|
||||||
|
import ETH2USDValue from "./components/ETH2USDValue";
|
||||||
|
import USDValue from "./components/USDValue";
|
||||||
import HexValue from "./components/HexValue";
|
import HexValue from "./components/HexValue";
|
||||||
import { RuntimeContext } from "./useRuntime";
|
import { RuntimeContext } from "./useRuntime";
|
||||||
import { useLatestBlockNumber } from "./useLatestBlock";
|
import { useLatestBlockNumber } from "./useLatestBlock";
|
||||||
import { blockTxsURL } from "./url";
|
import { blockTxsURL } from "./url";
|
||||||
import { useBlockData } from "./useErigonHooks";
|
import { useBlockData } from "./useErigonHooks";
|
||||||
|
import { useETHUSDOracle } from "./usePriceOracle";
|
||||||
|
|
||||||
type BlockParams = {
|
type BlockParams = {
|
||||||
blockNumberOrHash: string;
|
blockNumberOrHash: string;
|
||||||
@ -53,6 +56,7 @@ const Block: React.FC = () => {
|
|||||||
block && block.gasUsed.mul(10000).div(block.gasLimit).toNumber() / 100;
|
block && block.gasUsed.mul(10000).div(block.gasLimit).toNumber() / 100;
|
||||||
|
|
||||||
const latestBlockNumber = useLatestBlockNumber(provider);
|
const latestBlockNumber = useLatestBlockNumber(provider);
|
||||||
|
const blockETHUSDPrice = useETHUSDOracle(provider, block?.number);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StandardFrame>
|
<StandardFrame>
|
||||||
@ -99,6 +103,17 @@ const Block: React.FC = () => {
|
|||||||
<TransactionValue value={netFeeReward} hideUnit />)
|
<TransactionValue value={netFeeReward} hideUnit />)
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{blockETHUSDPrice && (
|
||||||
|
<>
|
||||||
|
{" "}
|
||||||
|
<span className="px-2 border-yellow-200 border rounded-lg bg-yellow-100 text-yellow-600">
|
||||||
|
<ETH2USDValue
|
||||||
|
ethAmount={block.blockReward.add(netFeeReward)}
|
||||||
|
eth2USDValue={blockETHUSDPrice}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</InfoRow>
|
</InfoRow>
|
||||||
<InfoRow title="Uncles Reward">
|
<InfoRow title="Uncles Reward">
|
||||||
<TransactionValue value={block.unclesReward} />
|
<TransactionValue value={block.unclesReward} />
|
||||||
@ -147,7 +162,9 @@ const Block: React.FC = () => {
|
|||||||
{extraStr} (Hex:{" "}
|
{extraStr} (Hex:{" "}
|
||||||
<span className="font-data">{block.extraData}</span>)
|
<span className="font-data">{block.extraData}</span>)
|
||||||
</InfoRow>
|
</InfoRow>
|
||||||
<InfoRow title="Ether Price">N/A</InfoRow>
|
<InfoRow title="Ether Price">
|
||||||
|
<USDValue value={blockETHUSDPrice} />
|
||||||
|
</InfoRow>
|
||||||
<InfoRow title="Difficult">{commify(block.difficulty)}</InfoRow>
|
<InfoRow title="Difficult">{commify(block.difficulty)}</InfoRow>
|
||||||
<InfoRow title="Total Difficult">
|
<InfoRow title="Total Difficult">
|
||||||
{commify(block.totalDifficulty.toString())}
|
{commify(block.totalDifficulty.toString())}
|
||||||
|
@ -8,6 +8,7 @@ import Logs from "./transaction/Logs";
|
|||||||
import { RuntimeContext } from "./useRuntime";
|
import { RuntimeContext } from "./useRuntime";
|
||||||
import { SelectionContext, useSelection } from "./useSelection";
|
import { SelectionContext, useSelection } from "./useSelection";
|
||||||
import { useInternalOperations, useTxData } from "./useErigonHooks";
|
import { useInternalOperations, useTxData } from "./useErigonHooks";
|
||||||
|
import { useETHUSDOracle } from "./usePriceOracle";
|
||||||
|
|
||||||
type TransactionParams = {
|
type TransactionParams = {
|
||||||
txhash: string;
|
txhash: string;
|
||||||
@ -36,6 +37,8 @@ const Transaction: React.FC = () => {
|
|||||||
|
|
||||||
const selectionCtx = useSelection();
|
const selectionCtx = useSelection();
|
||||||
|
|
||||||
|
const blockETHUSDPrice = useETHUSDOracle(provider, txData?.blockNumber);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StandardFrame>
|
<StandardFrame>
|
||||||
<StandardSubtitle>Transaction Details</StandardSubtitle>
|
<StandardSubtitle>Transaction Details</StandardSubtitle>
|
||||||
@ -53,6 +56,7 @@ const Transaction: React.FC = () => {
|
|||||||
txData={txData}
|
txData={txData}
|
||||||
internalOps={internalOps}
|
internalOps={internalOps}
|
||||||
sendsEthToMiner={sendsEthToMiner}
|
sendsEthToMiner={sendsEthToMiner}
|
||||||
|
ethUSDPrice={blockETHUSDPrice}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/tx/:txhash/logs/" exact>
|
<Route path="/tx/:txhash/logs/" exact>
|
||||||
|
26
src/components/ETH2USDValue.tsx
Normal file
26
src/components/ETH2USDValue.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { BigNumber, FixedNumber } from "@ethersproject/bignumber";
|
||||||
|
import { commify } from "@ethersproject/units";
|
||||||
|
|
||||||
|
type ETH2USDValueProps = {
|
||||||
|
ethAmount: BigNumber;
|
||||||
|
eth2USDValue: BigNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ETH2USDValue: React.FC<ETH2USDValueProps> = ({
|
||||||
|
ethAmount,
|
||||||
|
eth2USDValue,
|
||||||
|
}) => {
|
||||||
|
const value = ethAmount.mul(eth2USDValue).div(10 ** 8);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="text-xs">
|
||||||
|
$
|
||||||
|
<span className="font-balance">
|
||||||
|
{commify(FixedNumber.fromValue(value, 18).round(2).toString())}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(ETH2USDValue);
|
29
src/components/USDValue.tsx
Normal file
29
src/components/USDValue.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { BigNumber, FixedNumber } from "@ethersproject/bignumber";
|
||||||
|
import { commify } from "@ethersproject/units";
|
||||||
|
|
||||||
|
const ETH_FEED_DECIMALS = 8;
|
||||||
|
|
||||||
|
type USDValueProps = {
|
||||||
|
value: BigNumber | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const USDValue: React.FC<USDValueProps> = ({ value }) => (
|
||||||
|
<span className="text-sm">
|
||||||
|
{value ? (
|
||||||
|
<>
|
||||||
|
$
|
||||||
|
<span className="font-balance">
|
||||||
|
{commify(
|
||||||
|
FixedNumber.fromValue(value, ETH_FEED_DECIMALS).round(2).toString()
|
||||||
|
)}
|
||||||
|
</span>{" "}
|
||||||
|
<span className="text-xs text-gray-500">/ ETH</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
"N/A"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default React.memo(USDValue);
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { formatEther } from "@ethersproject/units";
|
import { BigNumber } from "@ethersproject/bignumber";
|
||||||
import { toUtf8String } from "@ethersproject/strings";
|
import { toUtf8String } from "@ethersproject/strings";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons/faCheckCircle";
|
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons/faCheckCircle";
|
||||||
@ -19,7 +19,9 @@ import MethodName from "../components/MethodName";
|
|||||||
import TransactionType from "../components/TransactionType";
|
import TransactionType from "../components/TransactionType";
|
||||||
import RewardSplit from "./RewardSplit";
|
import RewardSplit from "./RewardSplit";
|
||||||
import GasValue from "../components/GasValue";
|
import GasValue from "../components/GasValue";
|
||||||
|
import USDValue from "../components/USDValue";
|
||||||
import FormattedBalance from "../components/FormattedBalance";
|
import FormattedBalance from "../components/FormattedBalance";
|
||||||
|
import ETH2USDValue from "../components/ETH2USDValue";
|
||||||
import TokenTransferItem from "../TokenTransferItem";
|
import TokenTransferItem from "../TokenTransferItem";
|
||||||
import { TransactionData, InternalOperation } from "../types";
|
import { TransactionData, InternalOperation } from "../types";
|
||||||
import PercentageBar from "../components/PercentageBar";
|
import PercentageBar from "../components/PercentageBar";
|
||||||
@ -31,12 +33,14 @@ type DetailsProps = {
|
|||||||
txData: TransactionData;
|
txData: TransactionData;
|
||||||
internalOps?: InternalOperation[];
|
internalOps?: InternalOperation[];
|
||||||
sendsEthToMiner: boolean;
|
sendsEthToMiner: boolean;
|
||||||
|
ethUSDPrice: BigNumber | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Details: React.FC<DetailsProps> = ({
|
const Details: React.FC<DetailsProps> = ({
|
||||||
txData,
|
txData,
|
||||||
internalOps,
|
internalOps,
|
||||||
sendsEthToMiner,
|
sendsEthToMiner,
|
||||||
|
ethUSDPrice,
|
||||||
}) => {
|
}) => {
|
||||||
const hasEIP1559 =
|
const hasEIP1559 =
|
||||||
txData.blockBaseFeePerGas !== undefined &&
|
txData.blockBaseFeePerGas !== undefined &&
|
||||||
@ -170,9 +174,12 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
</InfoRow>
|
</InfoRow>
|
||||||
)}
|
)}
|
||||||
<InfoRow title="Value">
|
<InfoRow title="Value">
|
||||||
<span className="rounded bg-gray-100 px-2 py-1 text-xs">
|
<FormattedBalance value={txData.value} /> Ether{" "}
|
||||||
{formatEther(txData.value)} Ether
|
{!txData.value.isZero() && ethUSDPrice && (
|
||||||
</span>
|
<span className="px-2 border-red-100 border rounded-lg bg-red-50 text-red-600">
|
||||||
|
<ETH2USDValue ethAmount={txData.value} eth2USDValue={ethUSDPrice} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</InfoRow>
|
</InfoRow>
|
||||||
<InfoRow
|
<InfoRow
|
||||||
title={
|
title={
|
||||||
@ -257,12 +264,22 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
<InfoRow title="Transaction Fee">
|
<InfoRow title="Transaction Fee">
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div>
|
<div>
|
||||||
<FormattedBalance value={txData.fee} /> Ether
|
<FormattedBalance value={txData.fee} /> Ether{" "}
|
||||||
|
{ethUSDPrice && (
|
||||||
|
<span className="px-2 border-red-100 border rounded-lg bg-red-50 text-red-600">
|
||||||
|
<ETH2USDValue
|
||||||
|
ethAmount={txData.fee}
|
||||||
|
eth2USDValue={ethUSDPrice}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{hasEIP1559 && <RewardSplit txData={txData} />}
|
{hasEIP1559 && <RewardSplit txData={txData} />}
|
||||||
</div>
|
</div>
|
||||||
</InfoRow>
|
</InfoRow>
|
||||||
<InfoRow title="Ether Price">N/A</InfoRow>
|
<InfoRow title="Ether Price">
|
||||||
|
<USDValue value={ethUSDPrice} />
|
||||||
|
</InfoRow>
|
||||||
<InfoRow title="Input Data">
|
<InfoRow title="Input Data">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<div className="flex space-x-1">
|
<div className="flex space-x-1">
|
||||||
|
42
src/usePriceOracle.ts
Normal file
42
src/usePriceOracle.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import { JsonRpcProvider, BlockTag } from "@ethersproject/providers";
|
||||||
|
import { Contract } from "@ethersproject/contracts";
|
||||||
|
import { BigNumber } from "@ethersproject/bignumber";
|
||||||
|
import AggregatorV3Interface from "@chainlink/contracts/abi/v0.8/AggregatorV3Interface.json";
|
||||||
|
|
||||||
|
export const useETHUSDOracle = (
|
||||||
|
provider: JsonRpcProvider | undefined,
|
||||||
|
blockTag: BlockTag | undefined
|
||||||
|
) => {
|
||||||
|
const ethFeed = useMemo(() => {
|
||||||
|
if (!provider || provider.network.chainId !== 1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new Contract("eth-usd.data.eth", AggregatorV3Interface, provider);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}, [provider]);
|
||||||
|
|
||||||
|
const [latestPriceData, setLatestPriceData] = useState<BigNumber>();
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ethFeed || !blockTag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const readData = async () => {
|
||||||
|
try {
|
||||||
|
const priceData = await ethFeed.latestRoundData({ blockTag });
|
||||||
|
setLatestPriceData(BigNumber.from(priceData.answer));
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
readData();
|
||||||
|
}, [ethFeed, blockTag]);
|
||||||
|
|
||||||
|
return latestPriceData;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user