From 57334f1f8fc7ccd92032fc8e49e22d0634a0a197 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Mon, 22 Aug 2022 04:50:49 -0300 Subject: [PATCH] Get rid of price maps --- src/Block.tsx | 24 +-------- src/BlockReward.tsx | 47 ++++++++++++++++ src/BlockTransactions.tsx | 1 - src/address/AddressBalance.tsx | 32 +++++++++++ src/address/AddressTransactionResults.tsx | 29 +--------- src/block/BlockTransactionResults.tsx | 17 +----- src/components/ETH2USDValue.tsx | 33 ------------ src/components/FiatValue.tsx | 25 +++++++++ src/components/TransactionDetailsValue.tsx | 41 ++++++++++++++ src/search/TransactionItem.tsx | 18 ++----- src/search/TransactionItemFiatFee.tsx | 25 +++++++++ src/transaction/Details.tsx | 26 +++------ src/transaction/TransactionFee.tsx | 36 +++++++++++++ src/usePriceOracle.ts | 63 ---------------------- 14 files changed, 223 insertions(+), 194 deletions(-) create mode 100644 src/BlockReward.tsx create mode 100644 src/address/AddressBalance.tsx delete mode 100644 src/components/ETH2USDValue.tsx create mode 100644 src/components/FiatValue.tsx create mode 100644 src/components/TransactionDetailsValue.tsx create mode 100644 src/search/TransactionItemFiatFee.tsx create mode 100644 src/transaction/TransactionFee.tsx diff --git a/src/Block.tsx b/src/Block.tsx index e8a6c92..9a7e4e7 100644 --- a/src/Block.tsx +++ b/src/Block.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useMemo, useContext } from "react"; import { useParams, NavLink } from "react-router-dom"; -import { BigNumber } from "@ethersproject/bignumber"; import { commify } from "@ethersproject/units"; import { toUtf8String } from "@ethersproject/strings"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -12,13 +11,13 @@ import ContentFrame from "./ContentFrame"; import BlockNotFound from "./components/BlockNotFound"; import InfoRow from "./components/InfoRow"; import Timestamp from "./components/Timestamp"; +import BlockReward from "./BlockReward"; import GasValue from "./components/GasValue"; import PercentageBar from "./components/PercentageBar"; import BlockLink from "./components/BlockLink"; import DecoratedAddressLink from "./components/DecoratedAddressLink"; import TransactionValue from "./components/TransactionValue"; import FormattedBalance from "./components/FormattedBalance"; -import ETH2USDValue from "./components/ETH2USDValue"; import USDValue from "./components/USDValue"; import HexValue from "./components/HexValue"; import { RuntimeContext } from "./useRuntime"; @@ -55,7 +54,6 @@ const Block: React.FC = () => { }, [block]); const burntFees = block?.baseFeePerGas && block.baseFeePerGas.mul(block.gasUsed); - const netFeeReward = block?.feeReward ?? BigNumber.from(0); const gasUsedPerc = block && block.gasUsed.mul(10000).div(block.gasLimit).toNumber() / 100; @@ -100,25 +98,7 @@ const Block: React.FC = () => { - - {!netFeeReward.isZero() && ( - <> - {" "} - ( +{" "} - ) - - )} - {blockETHUSDPrice && ( - <> - {" "} - - - - - )} + diff --git a/src/BlockReward.tsx b/src/BlockReward.tsx new file mode 100644 index 0000000..2d8c64a --- /dev/null +++ b/src/BlockReward.tsx @@ -0,0 +1,47 @@ +import React, { useContext } from "react"; +import { BigNumber } from "@ethersproject/bignumber"; +import TransactionValue from "./components/TransactionValue"; +import FiatValue from "./components/FiatValue"; +import { RuntimeContext } from "./useRuntime"; +import { ExtendedBlock } from "./useErigonHooks"; +import { useETHUSDOracle } from "./usePriceOracle"; + +type BlockRewardProps = { + block: ExtendedBlock; +}; + +const BlockReward: React.FC = ({ block }) => { + const { provider } = useContext(RuntimeContext); + const eth2USDValue = useETHUSDOracle(provider, block.number); + + const netFeeReward = block?.feeReward ?? BigNumber.from(0); + const value = eth2USDValue + ? block.blockReward + .add(netFeeReward) + .mul(eth2USDValue) + .div(10 ** 8) + : undefined; + + return ( + <> + + {!netFeeReward.isZero() && ( + <> + {" "} + ( +{" "} + ) + + )} + {value && ( + <> + {" "} + + + + + )} + + ); +}; + +export default BlockReward; diff --git a/src/BlockTransactions.tsx b/src/BlockTransactions.tsx index b1fe5af..5396593 100644 --- a/src/BlockTransactions.tsx +++ b/src/BlockTransactions.tsx @@ -40,7 +40,6 @@ const BlockTransactions: React.FC = () => { = ({ balance }) => { + const { provider } = useContext(RuntimeContext); + const eth2USDValue = useETHUSDOracle(provider, "latest"); + const fiatValue = + !balance.isZero() && eth2USDValue !== undefined + ? balance.mul(eth2USDValue).div(10 ** 8) + : undefined; + + return ( + <> + + {fiatValue && ( + + + + )} + + ); +}; + +export default AddressBalance; diff --git a/src/address/AddressTransactionResults.tsx b/src/address/AddressTransactionResults.tsx index a6e1fc3..8e9ff39 100644 --- a/src/address/AddressTransactionResults.tsx +++ b/src/address/AddressTransactionResults.tsx @@ -1,9 +1,7 @@ import React, { useContext, useEffect, useMemo, useState } from "react"; -import { BlockTag } from "@ethersproject/providers"; import ContentFrame from "../ContentFrame"; import InfoRow from "../components/InfoRow"; -import TransactionValue from "../components/TransactionValue"; -import ETH2USDValue from "../components/ETH2USDValue"; +import AddressBalance from "./AddressBalance"; import TransactionAddress from "../components/TransactionAddress"; import Copy from "../components/Copy"; import TransactionLink from "../components/TransactionLink"; @@ -14,7 +12,6 @@ import TransactionItem from "../search/TransactionItem"; import UndefinedPageControl from "../search/UndefinedPageControl"; import { useFeeToggler } from "../search/useFeeToggler"; import { SelectionContext, useSelection } from "../useSelection"; -import { useMultipleETHUSDOracle } from "../usePriceOracle"; import { RuntimeContext } from "../useRuntime"; import { useParams, useSearchParams } from "react-router-dom"; import { ChecksummedAddress, ProcessedTransaction } from "../types"; @@ -98,19 +95,6 @@ const AddressTransactionResults: React.FC = ({ const page = useMemo(() => controller?.getPage(), [controller]); - // Extract block number from all txs on current page - // TODO: dedup blockTags - const blockTags: BlockTag[] = useMemo(() => { - if (!page) { - return ["latest"]; - } - - const blockTags: BlockTag[] = page.map((t) => t.blockNumber); - blockTags.push("latest"); - return blockTags; - }, [page]); - const priceMap = useMultipleETHUSDOracle(provider, blockTags); - const balance = useAddressBalance(provider, address); const creator = useContractCreator(provider, address); @@ -121,15 +105,7 @@ const AddressTransactionResults: React.FC = ({ {balance && (
- - {!balance.isZero() && priceMap["latest"] !== undefined && ( - - - - )} +
)} @@ -163,7 +139,6 @@ const AddressTransactionResults: React.FC = ({ tx={tx} selectedAddress={address} feeDisplay={feeDisplay} - priceMap={priceMap} /> ))} diff --git a/src/block/BlockTransactionResults.tsx b/src/block/BlockTransactionResults.tsx index 5c1824f..14821ea 100644 --- a/src/block/BlockTransactionResults.tsx +++ b/src/block/BlockTransactionResults.tsx @@ -1,35 +1,27 @@ -import React, { useContext, useMemo } from "react"; -import { BlockTag } from "@ethersproject/abstract-provider"; +import React from "react"; import ContentFrame from "../ContentFrame"; import PageControl from "../search/PageControl"; import ResultHeader from "../search/ResultHeader"; import PendingResults from "../search/PendingResults"; import TransactionItem from "../search/TransactionItem"; import { useFeeToggler } from "../search/useFeeToggler"; -import { RuntimeContext } from "../useRuntime"; import { SelectionContext, useSelection } from "../useSelection"; import { ProcessedTransaction } from "../types"; import { PAGE_SIZE } from "../params"; -import { useMultipleETHUSDOracle } from "../usePriceOracle"; type BlockTransactionResultsProps = { - blockTag: BlockTag; page?: ProcessedTransaction[]; total: number; pageNumber: number; }; const BlockTransactionResults: React.FC = ({ - blockTag, page, total, pageNumber, }) => { - const { provider } = useContext(RuntimeContext); const selectionCtx = useSelection(); const [feeDisplay, feeDisplayToggler] = useFeeToggler(); - const blockTags = useMemo(() => [blockTag], [blockTag]); - const priceMap = useMultipleETHUSDOracle(provider, blockTags); return ( @@ -54,12 +46,7 @@ const BlockTransactionResults: React.FC = ({ {page ? ( {page.map((tx) => ( - + ))}
diff --git a/src/components/ETH2USDValue.tsx b/src/components/ETH2USDValue.tsx deleted file mode 100644 index 53ece53..0000000 --- a/src/components/ETH2USDValue.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react"; -import { BigNumber, FixedNumber } from "@ethersproject/bignumber"; -import { commify } from "@ethersproject/units"; - -type ETH2USDValueProps = { - ethAmount: BigNumber; - eth2USDValue: BigNumber; -}; - -/** - * Basic display of ETH -> USD values WITHOUT box decoration, only - * text formatting. - * - * USD amounts are displayed commified with 2 decimals places and $ prefix, - * i.e., "$1,000.00". - */ -const ETH2USDValue: React.FC = ({ - ethAmount, - eth2USDValue, -}) => { - const value = ethAmount.mul(eth2USDValue).div(10 ** 8); - - return ( - - $ - - {commify(FixedNumber.fromValue(value, 18).round(2).toString())} - - - ); -}; - -export default React.memo(ETH2USDValue); diff --git a/src/components/FiatValue.tsx b/src/components/FiatValue.tsx new file mode 100644 index 0000000..ae950c9 --- /dev/null +++ b/src/components/FiatValue.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { BigNumber, FixedNumber } from "@ethersproject/bignumber"; +import { commify } from "@ethersproject/units"; + +type FiatValueProps = { + value: BigNumber; +}; + +/** + * Basic display of ETH -> USD values WITHOUT box decoration, only + * text formatting. + * + * USD amounts are displayed commified with 2 decimals places and $ prefix, + * i.e., "$1,000.00". + */ +const FiatValue: React.FC = ({ value }) => ( + + $ + + {commify(FixedNumber.fromValue(value, 18).round(2).toString())} + + +); + +export default FiatValue; diff --git a/src/components/TransactionDetailsValue.tsx b/src/components/TransactionDetailsValue.tsx new file mode 100644 index 0000000..4d09e25 --- /dev/null +++ b/src/components/TransactionDetailsValue.tsx @@ -0,0 +1,41 @@ +import React, { useContext } from "react"; +import { BlockTag } from "@ethersproject/providers"; +import { BigNumber } from "@ethersproject/bignumber"; +import FormattedBalance from "./FormattedBalance"; +import { RuntimeContext } from "../useRuntime"; +import { useChainInfo } from "../useChainInfo"; +import { useETHUSDOracle } from "../usePriceOracle"; +import FiatValue from "./FiatValue"; + +type TransactionDetailsValueProps = { + blockTag: BlockTag | undefined; + value: BigNumber; +}; + +const TransactionDetailsValue: React.FC = ({ + blockTag, + value, +}) => { + const { provider } = useContext(RuntimeContext); + const blockETHUSDPrice = useETHUSDOracle(provider, blockTag); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); + const fiatValue = + !value.isZero() && blockETHUSDPrice !== undefined + ? value.mul(blockETHUSDPrice).div(10 ** 8) + : undefined; + + return ( + <> + {symbol}{" "} + {fiatValue && ( + + + + )} + + ); +}; + +export default TransactionDetailsValue; diff --git a/src/search/TransactionItem.tsx b/src/search/TransactionItem.tsx index 3fee32c..94e4820 100644 --- a/src/search/TransactionItem.tsx +++ b/src/search/TransactionItem.tsx @@ -1,6 +1,4 @@ import React, { useContext } from "react"; -import { BlockTag } from "@ethersproject/abstract-provider"; -import { BigNumber } from "@ethersproject/bignumber"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclamationCircle"; import MethodName from "../components/MethodName"; @@ -14,25 +12,23 @@ import TransactionDirection, { Flags, } from "../components/TransactionDirection"; import TransactionValue from "../components/TransactionValue"; +import TransactionItemFiatFee from "./TransactionItemFiatFee"; import { ProcessedTransaction } from "../types"; import { FeeDisplay } from "./useFeeToggler"; import { RuntimeContext } from "../useRuntime"; import { useHasCode } from "../useErigonHooks"; import { formatValue } from "../components/formatter"; -import ETH2USDValue from "../components/ETH2USDValue"; type TransactionItemProps = { tx: ProcessedTransaction; selectedAddress?: string; feeDisplay: FeeDisplay; - priceMap: Record; }; const TransactionItem: React.FC = ({ tx, selectedAddress, feeDisplay, - priceMap, }) => { const { provider } = useContext(RuntimeContext); const toHasCode = useHasCode( @@ -130,15 +126,9 @@ const TransactionItem: React.FC = ({ {feeDisplay === FeeDisplay.TX_FEE && formatValue(tx.fee, 18)} - {feeDisplay === FeeDisplay.TX_FEE_USD && - (priceMap[tx.blockNumber] ? ( - - ) : ( - "N/A" - ))} + {feeDisplay === FeeDisplay.TX_FEE_USD && ( + + )} {feeDisplay === FeeDisplay.GAS_PRICE && formatValue(tx.gasPrice, 9)}
diff --git a/src/search/TransactionItemFiatFee.tsx b/src/search/TransactionItemFiatFee.tsx new file mode 100644 index 0000000..813bd22 --- /dev/null +++ b/src/search/TransactionItemFiatFee.tsx @@ -0,0 +1,25 @@ +import React, { useContext } from "react"; +import { BlockTag } from "@ethersproject/providers"; +import { BigNumber } from "@ethersproject/bignumber"; +import FiatValue from "../components/FiatValue"; +import { RuntimeContext } from "../useRuntime"; +import { useETHUSDOracle } from "../usePriceOracle"; + +type TransactionItemFiatFeeProps = { + blockTag: BlockTag; + fee: BigNumber; +}; + +const TransactionItemFiatFee: React.FC = ({ + blockTag, + fee, +}) => { + const { provider } = useContext(RuntimeContext); + const eth2USDValue = useETHUSDOracle(provider, blockTag); + const fiatValue = + eth2USDValue !== undefined ? fee.mul(eth2USDValue).div(10 ** 8) : undefined; + + return fiatValue ? : <>N/A; +}; + +export default TransactionItemFiatFee; diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index a34a212..5b6e972 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -17,12 +17,13 @@ import NavNonce from "./NavNonce"; import Timestamp from "../components/Timestamp"; import InternalTransactionOperation from "../components/InternalTransactionOperation"; import MethodName from "../components/MethodName"; +import TransactionDetailsValue from "../components/TransactionDetailsValue"; import TransactionType from "../components/TransactionType"; +import TransactionFee from "./TransactionFee"; import RewardSplit from "./RewardSplit"; import GasValue from "../components/GasValue"; import USDValue from "../components/USDValue"; import FormattedBalance from "../components/FormattedBalance"; -import ETH2USDValue from "../components/ETH2USDValue"; import TokenTransferItem from "../TokenTransferItem"; import { TransactionData } from "../types"; import PercentageBar from "../components/PercentageBar"; @@ -308,15 +309,10 @@ const Details: React.FC = ({ txData }) => { )} - {symbol}{" "} - {!txData.value.isZero() && blockETHUSDPrice && ( - - - - )} + = ({ txData }) => {
- {symbol}{" "} - {blockETHUSDPrice && ( - - - - )} +
{hasEIP1559 && }
diff --git a/src/transaction/TransactionFee.tsx b/src/transaction/TransactionFee.tsx new file mode 100644 index 0000000..7324b46 --- /dev/null +++ b/src/transaction/TransactionFee.tsx @@ -0,0 +1,36 @@ +import React, { useContext } from "react"; +import FormattedBalance from "../components/FormattedBalance"; +import FiatValue from "../components/FiatValue"; +import { RuntimeContext } from "../useRuntime"; +import { useETHUSDOracle } from "../usePriceOracle"; +import { useChainInfo } from "../useChainInfo"; +import { ConfirmedTransactionData } from "../types"; + +type TransactionFeeProps = { + confirmedData: ConfirmedTransactionData; +}; + +const TransactionFee: React.FC = ({ confirmedData }) => { + const { provider } = useContext(RuntimeContext); + const blockETHUSDPrice = useETHUSDOracle(provider, confirmedData.blockNumber); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); + const fiatValue = + blockETHUSDPrice !== undefined + ? confirmedData.fee.mul(blockETHUSDPrice).div(10 ** 8) + : undefined; + + return ( + <> + {symbol}{" "} + {fiatValue && ( + + + + )} + + ); +}; + +export default TransactionFee; diff --git a/src/usePriceOracle.ts b/src/usePriceOracle.ts index 2780e5a..783d76e 100644 --- a/src/usePriceOracle.ts +++ b/src/usePriceOracle.ts @@ -1,4 +1,3 @@ -import { useEffect, useMemo, useState } from "react"; import { JsonRpcProvider, BlockTag } from "@ethersproject/providers"; import { Contract } from "@ethersproject/contracts"; import { BigNumber } from "@ethersproject/bignumber"; @@ -101,65 +100,3 @@ export const useETHUSDOracle = ( } return data; }; - -export const useMultipleETHUSDOracle = ( - provider: JsonRpcProvider | undefined, - blockTags: (BlockTag | undefined)[] -) => { - const ethFeed = useMemo(() => { - // TODO: it currently is hardcoded to support only mainnet - 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< - Record - >({}); - useEffect(() => { - if (!ethFeed) { - return; - } - - const priceReaders: Promise[] = []; - for (const blockTag of blockTags) { - priceReaders.push( - (async () => { - try { - const priceData = await ethFeed.latestRoundData({ blockTag }); - return BigNumber.from(priceData.answer); - } catch (err) { - // Silently ignore on purpose; it means the network or block number does - // not contain the chainlink feed contract - return undefined; - } - })() - ); - } - const readData = async () => { - const results = await Promise.all(priceReaders); - const priceMap: Record = {}; - for (let i = 0; i < blockTags.length; i++) { - const blockTag = blockTags[i]; - const result = results[i]; - if (blockTag === undefined || result === undefined) { - continue; - } - - priceMap[blockTag] = result; - } - - setLatestPriceData(priceMap); - }; - readData(); - }, [ethFeed, blockTags]); - - return latestPriceData; -};