diff --git a/src/Transaction.tsx b/src/Transaction.tsx index ad940fe..cb5a4e1 100644 --- a/src/Transaction.tsx +++ b/src/Transaction.tsx @@ -1,19 +1,13 @@ -import React, { useState, useEffect, useMemo, useContext } from "react"; +import React, { useMemo, useContext } from "react"; import { Route, Switch, useParams } from "react-router-dom"; -import { BigNumber, ethers } from "ethers"; import StandardFrame from "./StandardFrame"; import StandardSubtitle from "./StandardSubtitle"; import Tab from "./components/Tab"; import Details from "./transaction/Details"; import Logs from "./transaction/Logs"; -import erc20 from "./erc20.json"; -import { TokenMetas, TokenTransfer, TransactionData } from "./types"; import { RuntimeContext } from "./useRuntime"; import { SelectionContext, useSelection } from "./useSelection"; -import { useInternalOperations } from "./useErigonHooks"; - -const TRANSFER_TOPIC = - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; +import { useInternalOperations, useTxData } from "./useErigonHooks"; type TransactionParams = { txhash: string; @@ -24,89 +18,7 @@ const Transaction: React.FC = () => { const params = useParams(); const { txhash } = params; - const [txData, setTxData] = useState(); - useEffect(() => { - if (!provider) { - return; - } - - const readBlock = async () => { - const [_response, _receipt] = await Promise.all([ - provider.getTransaction(txhash), - provider.getTransactionReceipt(txhash), - ]); - const _block = await provider.getBlock(_receipt.blockNumber); - document.title = `Transaction ${_response.hash} | Otterscan`; - - // Extract token transfers - const tokenTransfers: TokenTransfer[] = []; - for (const l of _receipt.logs) { - if (l.topics.length !== 3) { - continue; - } - if (l.topics[0] !== TRANSFER_TOPIC) { - continue; - } - tokenTransfers.push({ - token: l.address, - from: ethers.utils.getAddress( - ethers.utils.hexDataSlice(ethers.utils.arrayify(l.topics[1]), 12) - ), - to: ethers.utils.getAddress( - ethers.utils.hexDataSlice(ethers.utils.arrayify(l.topics[2]), 12) - ), - value: BigNumber.from(l.data), - }); - } - - // Extract token meta - const tokenMetas: TokenMetas = {}; - for (const t of tokenTransfers) { - if (tokenMetas[t.token]) { - continue; - } - const erc20Contract = new ethers.Contract(t.token, erc20, provider); - const [name, symbol, decimals] = await Promise.all([ - erc20Contract.name(), - erc20Contract.symbol(), - erc20Contract.decimals(), - ]); - tokenMetas[t.token] = { - name, - symbol, - decimals, - }; - } - - setTxData({ - transactionHash: _receipt.transactionHash, - status: _receipt.status === 1, - blockNumber: _receipt.blockNumber, - transactionIndex: _receipt.transactionIndex, - confirmations: _receipt.confirmations, - timestamp: _block.timestamp, - miner: _block.miner, - from: _receipt.from, - to: _receipt.to, - createdContractAddress: _receipt.contractAddress, - value: _response.value, - tokenTransfers, - tokenMetas, - type: _response.type ?? 0, - fee: _response.gasPrice!.mul(_receipt.gasUsed), - blockBaseFeePerGas: _block.baseFeePerGas, - maxFeePerGas: _response.maxFeePerGas, - maxPriorityFeePerGas: _response.maxPriorityFeePerGas, - gasPrice: _response.gasPrice!, - gasUsed: _receipt.gasUsed, - gasLimit: _response.gasLimit, - nonce: _response.nonce, - data: _response.data, - logs: _receipt.logs, - }); - }; - readBlock(); - }, [provider, txhash]); + const txData = useTxData(provider, txhash); const internalOps = useInternalOperations(provider, txData); const sendsEthToMiner = useMemo(() => { diff --git a/src/components/Nonce.tsx b/src/components/Nonce.tsx new file mode 100644 index 0000000..69f1c17 --- /dev/null +++ b/src/components/Nonce.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faArrowUp } from "@fortawesome/free-solid-svg-icons"; + +type NonceProps = { + value: number; +}; + +const Nonce: React.FC = ({ value }) => ( + + + + + {value} + +); + +export default React.memo(Nonce); diff --git a/src/components/PercentagePosition.tsx b/src/components/PercentagePosition.tsx new file mode 100644 index 0000000..c3efe8e --- /dev/null +++ b/src/components/PercentagePosition.tsx @@ -0,0 +1,23 @@ +import React from "react"; + +type PercentagePositionProps = { + perc: number; +}; + +const PercentagePosition: React.FC = ({ perc }) => ( +
+
+
+
+
+
+
+
+
+
+); + +export default React.memo(PercentagePosition); diff --git a/src/components/RelativePosition.tsx b/src/components/RelativePosition.tsx new file mode 100644 index 0000000..e952463 --- /dev/null +++ b/src/components/RelativePosition.tsx @@ -0,0 +1,15 @@ +import React from "react"; + +type RelativePositionProps = { + pos: React.ReactNode; + total: React.ReactNode; +}; + +const RelativePosition: React.FC = ({ pos, total }) => ( + + {pos} + / {total} + +); + +export default React.memo(RelativePosition); diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index 7346b0c..69e40fe 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -3,6 +3,7 @@ import { ethers } from "ethers"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCheckCircle, + faCube, faTimesCircle, } from "@fortawesome/free-solid-svg-icons"; import ContentFrame from "../ContentFrame"; @@ -12,6 +13,7 @@ import BlockConfirmations from "../components/BlockConfirmations"; import AddressHighlighter from "../components/AddressHighlighter"; import DecoratedAddressLink from "../components/DecoratedAddressLink"; import Copy from "../components/Copy"; +import Nonce from "../components/Nonce"; import Timestamp from "../components/Timestamp"; import InternalTransactionOperation from "../components/InternalTransactionOperation"; import MethodName from "../components/MethodName"; @@ -23,6 +25,8 @@ import TokenTransferItem from "../TokenTransferItem"; import { TransactionData, InternalOperation } from "../types"; import PercentageBar from "../components/PercentageBar"; import ExternalLink from "../components/ExternalLink"; +import RelativePosition from "../components/RelativePosition"; +import PercentagePosition from "../components/PercentagePosition"; type DetailsProps = { txData: TransactionData; @@ -60,25 +64,46 @@ const Details: React.FC = ({ )} - -
- - + +
+
+ + + + + +
+
+ + +
- -
- - - - + +
+
+ + + + +
+
+ +
@@ -189,11 +214,13 @@ const Details: React.FC = ({ )}
- +
- /{" "} - + } + total={} + />
= ({
N/A - {txData.nonce} - - - {txData.transactionIndex} - -