diff --git a/src/Block.tsx b/src/Block.tsx index 963f2f9..c1578a8 100644 --- a/src/Block.tsx +++ b/src/Block.tsx @@ -13,7 +13,7 @@ import NavButton from "./components/NavButton"; import Timestamp from "./components/Timestamp"; import GasValue from "./components/GasValue"; import BlockLink from "./components/BlockLink"; -import AddressOrENSName from "./components/AddressOrENSName"; +import DecoratedAddressLink from "./components/DecoratedAddressLink"; import TransactionValue from "./components/TransactionValue"; import HexValue from "./components/HexValue"; import { RuntimeContext } from "./useRuntime"; @@ -159,10 +159,7 @@ const Block: React.FC = () => { in this block - + diff --git a/src/TokenTransferItem.tsx b/src/TokenTransferItem.tsx index 4b1fc62..83c5e81 100644 --- a/src/TokenTransferItem.tsx +++ b/src/TokenTransferItem.tsx @@ -2,22 +2,27 @@ import React from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCaretRight } from "@fortawesome/free-solid-svg-icons"; import AddressHighlighter from "./components/AddressHighlighter"; -import AddressOrENSName from "./components/AddressOrENSName"; -import AddressLink from "./components/AddressLink"; -import TokenLogo from "./components/TokenLogo"; +import DecoratedAddressLink from "./components/DecoratedAddressLink"; import FormattedBalance from "./components/FormattedBalance"; -import { TokenMetas, TokenTransfer } from "./types"; +import { + AddressContext, + TokenMetas, + TokenTransfer, + TransactionData, +} from "./types"; type TokenTransferItemProps = { t: TokenTransfer; + txData: TransactionData; tokenMetas: TokenMetas; }; const TokenTransferItem: React.FC = ({ t, + txData, tokenMetas, }) => ( -
+
@@ -25,13 +30,23 @@ const TokenTransferItem: React.FC = ({
From - +
To - +
@@ -42,23 +57,17 @@ const TokenTransferItem: React.FC = ({ decimals={tokenMetas[t.token].decimals} /> - - {tokenMetas[t.token] ? ( - <> -
- -
- - - ) : ( - - )} -
+ + +
diff --git a/src/Transaction.tsx b/src/Transaction.tsx index 3f450e9..ce564f9 100644 --- a/src/Transaction.tsx +++ b/src/Transaction.tsx @@ -1,10 +1,4 @@ -import React, { - useState, - useEffect, - useCallback, - useMemo, - useContext, -} from "react"; +import React, { useState, useEffect, useMemo, useContext } from "react"; import { Route, Switch, useParams } from "react-router-dom"; import { BigNumber, ethers } from "ethers"; import StandardFrame from "./StandardFrame"; @@ -13,9 +7,10 @@ import Tab from "./components/Tab"; import Details from "./transaction/Details"; import Logs from "./transaction/Logs"; import erc20 from "./erc20.json"; -import { TokenMetas, TokenTransfer, TransactionData, Transfer } from "./types"; +import { TokenMetas, TokenTransfer, TransactionData } from "./types"; import { RuntimeContext } from "./useRuntime"; import { SelectionContext, useSelection } from "./useSelection"; +import { useInternalTransfers } from "./useErigonHooks"; const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; @@ -110,42 +105,19 @@ const Transaction: React.FC = () => { readBlock(); }, [provider, txhash]); - const [transfers, setTransfers] = useState(); + const intTransfers = useInternalTransfers(provider, txData); const sendsEthToMiner = useMemo(() => { - if (!txData || !transfers) { + if (!txData || !intTransfers) { return false; } - for (const t of transfers) { + for (const t of intTransfers) { if (t.to === txData.miner) { return true; } } return false; - }, [txData, transfers]); - - const traceTransfers = useCallback(async () => { - if (!provider || !txData) { - return; - } - - const r = await provider.send("ots_getTransactionTransfers", [ - txData.transactionHash, - ]); - const _transfers: Transfer[] = []; - for (const t of r) { - _transfers.push({ - from: ethers.utils.getAddress(t.from), - to: ethers.utils.getAddress(t.to), - value: t.value, - }); - } - - setTransfers(_transfers); - }, [provider, txData]); - useEffect(() => { - traceTransfers(); - }, [traceTransfers]); + }, [txData, intTransfers]); const selectionCtx = useSelection(); @@ -164,7 +136,7 @@ const Transaction: React.FC = () => {
diff --git a/src/components/Address.tsx b/src/components/Address.tsx index d757ed3..d7694e5 100644 --- a/src/components/Address.tsx +++ b/src/components/Address.tsx @@ -6,7 +6,7 @@ type AddressProps = { const Address: React.FC = ({ address }) => ( -

{address}

+ {address}
); diff --git a/src/components/AddressLink.tsx b/src/components/AddressLink.tsx index 36acac6..a8fd5c3 100644 --- a/src/components/AddressLink.tsx +++ b/src/components/AddressLink.tsx @@ -4,16 +4,23 @@ import { NavLink } from "react-router-dom"; type AddressLinkProps = { address: string; text?: string; + dontOverrideColors?: boolean; }; -const AddressLink: React.FC = ({ address, text }) => ( +const AddressLink: React.FC = ({ + address, + text, + dontOverrideColors, +}) => ( -

+ {text ?? address} -

+
); diff --git a/src/components/AddressOrENSName.tsx b/src/components/AddressOrENSName.tsx index ce1ec8a..9cb2f9e 100644 --- a/src/components/AddressOrENSName.tsx +++ b/src/components/AddressOrENSName.tsx @@ -1,6 +1,4 @@ import React from "react"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faCoins } from "@fortawesome/free-solid-svg-icons"; import Address from "./Address"; import AddressLink from "./AddressLink"; import ENSName from "./ENSName"; @@ -10,21 +8,18 @@ type AddressOrENSNameProps = { address: string; ensName?: string; selectedAddress?: string; - minerAddress?: string; + text?: string; + dontOverrideColors?: boolean; }; const AddressOrENSName: React.FC = ({ address, ensName, selectedAddress, - minerAddress, + text, + dontOverrideColors, }) => ( -
- {minerAddress !== undefined && minerAddress === address && ( - - - - )} + <> {address === selectedAddress ? ( <> {ensName ? ( @@ -36,13 +31,21 @@ const AddressOrENSName: React.FC = ({ ) : ( <> {ensName ? ( - + ) : ( - + )} )} -
+ ); export default React.memo(AddressOrENSName); diff --git a/src/components/DecoratedAddressLink.tsx b/src/components/DecoratedAddressLink.tsx new file mode 100644 index 0000000..6d58bf5 --- /dev/null +++ b/src/components/DecoratedAddressLink.tsx @@ -0,0 +1,79 @@ +import React from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { + faMoneyBillAlt, + faBurn, + faCoins, +} from "@fortawesome/free-solid-svg-icons"; +import TokenLogo from "./TokenLogo"; +import AddressOrENSName from "./AddressOrENSName"; +import { AddressContext, TokenMeta, ZERO_ADDRESS } from "../types"; + +type DecoratedAddressLinkProps = { + address: string; + ensName?: string; + selectedAddress?: string; + text?: string; + addressCtx?: AddressContext; + miner?: boolean; + selfDestruct?: boolean; + txFrom?: boolean; + txTo?: boolean; + tokenMeta?: TokenMeta; +}; + +const DecoratedAddresssLink: React.FC = ({ + address, + ensName, + selectedAddress, + text, + addressCtx, + miner, + selfDestruct, + txFrom, + txTo, + tokenMeta, +}) => { + const mint = addressCtx === AddressContext.FROM && address === ZERO_ADDRESS; + const burn = addressCtx === AddressContext.TO && address === ZERO_ADDRESS; + + return ( +
+ {mint && ( + + + + )} + {burn && ( + + + + )} + {miner && ( + + + + )} + {tokenMeta && ( +
+ +
+ )} + +
+ ); +}; + +export default React.memo(DecoratedAddresssLink); diff --git a/src/components/ENSName.tsx b/src/components/ENSName.tsx index 035c4ed..7bc8032 100644 --- a/src/components/ENSName.tsx +++ b/src/components/ENSName.tsx @@ -18,7 +18,7 @@ const ENSName: React.FC = ({ name, address }) => ( width={12} height={12} /> -

{name}

+ {name} ); diff --git a/src/components/ENSNameLink.tsx b/src/components/ENSNameLink.tsx index a111139..c1da646 100644 --- a/src/components/ENSNameLink.tsx +++ b/src/components/ENSNameLink.tsx @@ -5,11 +5,18 @@ import ENSLogo from "./ensLogo.svg"; type ENSNameLinkProps = { name: string; address: string; + dontOverrideColors?: boolean; }; -const ENSNameLink: React.FC = ({ name, address }) => ( +const ENSNameLink: React.FC = ({ + name, + address, + dontOverrideColors, +}) => ( @@ -20,7 +27,7 @@ const ENSNameLink: React.FC = ({ name, address }) => ( width={12} height={12} /> -

{name}

+ {name}
); diff --git a/src/components/InternalOperation.tsx b/src/components/InternalOperation.tsx new file mode 100644 index 0000000..0ae0a38 --- /dev/null +++ b/src/components/InternalOperation.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import InternalTransfer from "./InternalTransfer"; +import InternalSelfDestruct from "./InternalSelfDestruct"; +import { TransactionData, Transfer, TransferType } from "../types"; + +type InternalOperationProps = { + txData: TransactionData; + transfer: Transfer; +}; + +const InternalOperation: React.FC = ({ + txData, + transfer, +}) => ( + <> + {transfer.type === TransferType.TRANSFER && ( + + )} + {transfer.type === TransferType.SELF_DESTRUCT && ( + + )} + +); + +export default React.memo(InternalOperation); diff --git a/src/components/InternalSelfDestruct.tsx b/src/components/InternalSelfDestruct.tsx new file mode 100644 index 0000000..b717d38 --- /dev/null +++ b/src/components/InternalSelfDestruct.tsx @@ -0,0 +1,73 @@ +import React, { useContext } from "react"; +import { ethers } from "ethers"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faAngleRight, faBomb } from "@fortawesome/free-solid-svg-icons"; +import AddressHighlighter from "./AddressHighlighter"; +import DecoratedAddressLink from "./DecoratedAddressLink"; +import { RuntimeContext } from "../useRuntime"; +import { TransactionData, Transfer } from "../types"; + +const CHI_ADDRESS = "0x0000000000004946c0e9F43F4Dee607b0eF1fA1c"; +const GST2_ADDRESS = "0x0000000000b3F879cb30FE243b4Dfee438691c04"; + +type InternalSelfDestructProps = { + txData: TransactionData; + transfer: Transfer; +}; + +const InternalSelfDestruct: React.FC = ({ + txData, + transfer, +}) => { + const { provider } = useContext(RuntimeContext); + const network = provider?.network; + + const toMiner = txData.miner !== undefined && transfer.to === txData.miner; + + return ( + <> +
+ + + + {" "} + SELF DESTRUCT + + Contract +
+ + + +
+ {network?.chainId === 1 && transfer.to === CHI_ADDRESS && ( + (Chi Gastoken) + )} + {network?.chainId === 1 && transfer.to === GST2_ADDRESS && ( + (GST2 Gastoken) + )} +
+ {!transfer.value.isZero() && ( +
+ + TRANSFER + + {ethers.utils.formatEther(transfer.value)} Ether +
+ To + +
+ +
+
+
+
+ )} + + ); +}; + +export default React.memo(InternalSelfDestruct); diff --git a/src/components/InternalTransfer.tsx b/src/components/InternalTransfer.tsx index c135a43..d0ccbf2 100644 --- a/src/components/InternalTransfer.tsx +++ b/src/components/InternalTransfer.tsx @@ -1,9 +1,9 @@ import React from "react"; import { ethers } from "ethers"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faAngleRight, faCoins } from "@fortawesome/free-solid-svg-icons"; +import { faAngleRight } from "@fortawesome/free-solid-svg-icons"; import AddressHighlighter from "./AddressHighlighter"; -import AddressLink from "./AddressLink"; +import DecoratedAddressLink from "./DecoratedAddressLink"; import { TransactionData, Transfer } from "../types"; type InternalTransferProps = { @@ -33,12 +33,12 @@ const InternalTransfer: React.FC = ({ fromMiner ? "rounded px-2 py-1 bg-yellow-100" : "" }`} > - {fromMiner && ( - - - - )} - + @@ -50,12 +50,12 @@ const InternalTransfer: React.FC = ({ toMiner ? "rounded px-2 py-1 bg-yellow-100" : "" }`} > - {toMiner && ( - - - - )} - + diff --git a/src/nodeFunctions.ts b/src/nodeFunctions.ts new file mode 100644 index 0000000..2cb5558 --- /dev/null +++ b/src/nodeFunctions.ts @@ -0,0 +1,22 @@ +import { ethers } from "ethers"; +import { TransactionData, Transfer } from "./types"; + +export const getTransactionTransfers = async ( + provider: ethers.providers.JsonRpcProvider, + txData: TransactionData +) => { + const rawTransfers = await provider.send("ots_getTransactionTransfers", [ + txData.transactionHash, + ]); + + const _transfers: Transfer[] = []; + for (const t of rawTransfers) { + _transfers.push({ + type: t.type, + from: ethers.utils.getAddress(t.from), + to: ethers.utils.getAddress(t.to), + value: t.value, + }); + } + return _transfers; +}; diff --git a/src/params.ts b/src/params.ts index 75d31c3..2bfd757 100644 --- a/src/params.ts +++ b/src/params.ts @@ -1,3 +1,3 @@ -export const MIN_API_LEVEL = 1; +export const MIN_API_LEVEL = 2; export const PAGE_SIZE = 25; diff --git a/src/search/TransactionItem.tsx b/src/search/TransactionItem.tsx index 3829010..6d78f7e 100644 --- a/src/search/TransactionItem.tsx +++ b/src/search/TransactionItem.tsx @@ -4,7 +4,7 @@ import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons"; import MethodName from "../components/MethodName"; import BlockLink from "../components/BlockLink"; import TransactionLink from "../components/TransactionLink"; -import AddressOrENSName from "../components/AddressOrENSName"; +import DecoratedAddressLink from "../components/DecoratedAddressLink"; import TimestampAge from "../components/TimestampAge"; import AddressHighlighter from "../components/AddressHighlighter"; import TransactionDirection, { @@ -71,11 +71,11 @@ const TransactionItem: React.FC = ({ {tx.from && ( - )} @@ -91,11 +91,11 @@ const TransactionItem: React.FC = ({ {tx.to && ( - )} diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index f5022da..7d18098 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -9,10 +9,10 @@ import ContentFrame from "../ContentFrame"; import InfoRow from "../components/InfoRow"; import BlockLink from "../components/BlockLink"; import AddressHighlighter from "../components/AddressHighlighter"; -import AddressOrENSName from "../components/AddressOrENSName"; +import DecoratedAddressLink from "../components/DecoratedAddressLink"; import Copy from "../components/Copy"; import Timestamp from "../components/Timestamp"; -import InternalTransfer from "../components/InternalTransfer"; +import InternalOperation from "../components/InternalOperation"; import MethodName from "../components/MethodName"; import GasValue from "../components/GasValue"; import FormattedBalance from "../components/FormattedBalance"; @@ -21,13 +21,13 @@ import { TransactionData, Transfer } from "../types"; type DetailsProps = { txData: TransactionData; - transfers?: Transfer[]; + internalTransfers?: Transfer[]; sendsEthToMiner: boolean; }; const Details: React.FC = ({ txData, - transfers, + internalTransfers, sendsEthToMiner, }) => ( @@ -64,7 +64,11 @@ const Details: React.FC = ({
- +
@@ -72,14 +76,18 @@ const Details: React.FC = ({
- +
- {transfers && ( + {internalTransfers && (
- {transfers.map((t, i) => ( - + {internalTransfers.map((t, i) => ( + ))}
)} @@ -89,9 +97,14 @@ const Details: React.FC = ({
{txData.tokenTransfers.length > 0 && ( -
+
{txData.tokenTransfers.map((t, i) => ( - + ))}
diff --git a/src/transaction/Logs.tsx b/src/transaction/Logs.tsx index eda12be..f965ecc 100644 --- a/src/transaction/Logs.tsx +++ b/src/transaction/Logs.tsx @@ -1,6 +1,6 @@ import React from "react"; import ContentFrame from "../ContentFrame"; -import AddressLink from "../components/AddressLink"; +import DecoratedAddressLink from "../components/DecoratedAddressLink"; import { TransactionData } from "../types"; type LogsProps = { @@ -22,7 +22,12 @@ const Logs: React.FC = ({ txData }) => (
Address
- +
{l.topics.map((t, i) => ( @@ -45,6 +50,7 @@ const Logs: React.FC = ({ txData }) => (