Initial tracking ot self-destructs

This commit is contained in:
Willian Mitsuda 2021-07-17 15:58:33 -03:00
parent 1ab77bb819
commit 683da61778
7 changed files with 152 additions and 23 deletions

View File

@ -105,19 +105,24 @@ const Transaction: React.FC = () => {
readBlock(); readBlock();
}, [provider, txhash]); }, [provider, txhash]);
const transfers = useInternalTransfers(provider, txData); const intTransfers = useInternalTransfers(provider, txData);
const sendsEthToMiner = useMemo(() => { const sendsEthToMiner = useMemo(() => {
if (!txData || !transfers) { if (!txData || !intTransfers) {
return false; return false;
} }
for (const t of transfers) { for (const t of intTransfers.transfers) {
if (t.to === txData.miner) {
return true;
}
}
for (const t of intTransfers.selfDestructs) {
if (t.to === txData.miner) { if (t.to === txData.miner) {
return true; return true;
} }
} }
return false; return false;
}, [txData, transfers]); }, [txData, intTransfers]);
const selectionCtx = useSelection(); const selectionCtx = useSelection();
@ -136,7 +141,7 @@ const Transaction: React.FC = () => {
<Route path="/tx/:txhash/" exact> <Route path="/tx/:txhash/" exact>
<Details <Details
txData={txData} txData={txData}
transfers={transfers} internalTransfers={intTransfers}
sendsEthToMiner={sendsEthToMiner} sendsEthToMiner={sendsEthToMiner}
/> />
</Route> </Route>

View File

@ -0,0 +1,82 @@
import React from "react";
import { ethers } from "ethers";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faAngleRight,
faBomb,
faCoins,
} from "@fortawesome/free-solid-svg-icons";
import AddressHighlighter from "./AddressHighlighter";
import AddressLink from "./AddressLink";
import { TransactionData, Transfer } from "../types";
type InternalSelfDestructProps = {
txData: TransactionData;
transfer: Transfer;
};
const InternalSelfDestruct: React.FC<InternalSelfDestructProps> = ({
txData,
transfer,
}) => {
const fromMiner =
txData.miner !== undefined && transfer.from === txData.miner;
const toMiner = txData.miner !== undefined && transfer.to === txData.miner;
return (
<>
<div className="flex items-baseline space-x-1 text-xs">
<span className="text-gray-500">
<span className="text-red-900">
<FontAwesomeIcon icon={faBomb} size="1x" />
</span>{" "}
SELF DESTRUCT
</span>
<span>Contract</span>
<div className="flex items-baseline">
<AddressHighlighter address={transfer.from}>
<div
className={`flex items-baseline space-x-1 ${
fromMiner ? "rounded px-2 py-1 bg-yellow-100" : ""
}`}
>
{fromMiner && (
<span className="text-yellow-400" title="Miner address">
<FontAwesomeIcon icon={faCoins} size="1x" />
</span>
)}
<AddressLink address={transfer.from} />
</div>
</AddressHighlighter>
</div>
</div>
{!transfer.value.isZero() && (
<div className="ml-5 flex items-baseline space-x-1 text-xs">
<span className="text-gray-500">
<FontAwesomeIcon icon={faAngleRight} size="1x" /> TRANSFER
</span>
<span>{ethers.utils.formatEther(transfer.value)} Ether</span>
<div className="flex items-baseline">
<span className="text-gray-500">To</span>
<AddressHighlighter address={transfer.to}>
<div
className={`flex items-baseline space-x-1 ${
toMiner ? "rounded px-2 py-1 bg-yellow-100" : ""
}`}
>
{toMiner && (
<span className="text-yellow-400" title="Miner address">
<FontAwesomeIcon icon={faCoins} size="1x" />
</span>
)}
<AddressLink address={transfer.to} />
</div>
</AddressHighlighter>
</div>
</div>
)}
</>
);
};
export default React.memo(InternalSelfDestruct);

View File

@ -5,12 +5,31 @@ export const getTransactionTransfers = async (
provider: ethers.providers.JsonRpcProvider, provider: ethers.providers.JsonRpcProvider,
txData: TransactionData txData: TransactionData
) => { ) => {
const r = await provider.send("ots_getTransactionTransfers", [ const rawTransfers = await provider.send("ots_getTransactionTransfers", [
txData.transactionHash, txData.transactionHash,
]); ]);
const _transfers: Transfer[] = []; const _transfers: Transfer[] = [];
for (const t of r) { for (const t of rawTransfers) {
_transfers.push({
from: ethers.utils.getAddress(t.from),
to: ethers.utils.getAddress(t.to),
value: t.value,
});
}
return _transfers;
};
export const getTransactionSelfDestructs = async (
provider: ethers.providers.JsonRpcProvider,
txData: TransactionData
) => {
const rawTransfers = await provider.send("ots_getTransactionSelfDestructs", [
txData.transactionHash,
]);
const _transfers: Transfer[] = [];
for (const t of rawTransfers) {
_transfers.push({ _transfers.push({
from: ethers.utils.getAddress(t.from), from: ethers.utils.getAddress(t.from),
to: ethers.utils.getAddress(t.to), to: ethers.utils.getAddress(t.to),

View File

@ -1,3 +1,3 @@
export const MIN_API_LEVEL = 1; export const MIN_API_LEVEL = 2;
export const PAGE_SIZE = 25; export const PAGE_SIZE = 25;

View File

@ -13,21 +13,22 @@ import AddressOrENSName from "../components/AddressOrENSName";
import Copy from "../components/Copy"; import Copy from "../components/Copy";
import Timestamp from "../components/Timestamp"; import Timestamp from "../components/Timestamp";
import InternalTransfer from "../components/InternalTransfer"; import InternalTransfer from "../components/InternalTransfer";
import InternalSelfDestruct from "../components/InternalSelfDestruct";
import MethodName from "../components/MethodName"; import MethodName from "../components/MethodName";
import GasValue from "../components/GasValue"; import GasValue from "../components/GasValue";
import FormattedBalance from "../components/FormattedBalance"; import FormattedBalance from "../components/FormattedBalance";
import TokenTransferItem from "../TokenTransferItem"; import TokenTransferItem from "../TokenTransferItem";
import { TransactionData, Transfer } from "../types"; import { InternalTransfers, TransactionData } from "../types";
type DetailsProps = { type DetailsProps = {
txData: TransactionData; txData: TransactionData;
transfers?: Transfer[]; internalTransfers?: InternalTransfers;
sendsEthToMiner: boolean; sendsEthToMiner: boolean;
}; };
const Details: React.FC<DetailsProps> = ({ const Details: React.FC<DetailsProps> = ({
txData, txData,
transfers, internalTransfers,
sendsEthToMiner, sendsEthToMiner,
}) => ( }) => (
<ContentFrame tabs> <ContentFrame tabs>
@ -76,12 +77,19 @@ const Details: React.FC<DetailsProps> = ({
</AddressHighlighter> </AddressHighlighter>
<Copy value={txData.to} /> <Copy value={txData.to} />
</div> </div>
{transfers && ( {internalTransfers && (
<>
<div className="mt-2 space-y-1"> <div className="mt-2 space-y-1">
{transfers.map((t, i) => ( {internalTransfers.transfers.map((t, i) => (
<InternalTransfer key={i} txData={txData} transfer={t} /> <InternalTransfer key={i} txData={txData} transfer={t} />
))} ))}
</div> </div>
<div className="mt-2 space-y-1">
{internalTransfers.selfDestructs.map((t, i) => (
<InternalSelfDestruct key={i} txData={txData} transfer={t} />
))}
</div>
</>
)} )}
</InfoRow> </InfoRow>
<InfoRow title="Transaction Action"> <InfoRow title="Transaction Action">

View File

@ -68,6 +68,11 @@ export type Transfer = {
value: BigNumber; value: BigNumber;
}; };
export type InternalTransfers = {
transfers: Transfer[];
selfDestructs: Transfer[];
};
export type TokenTransfer = { export type TokenTransfer = {
token: string; token: string;
from: string; from: string;

View File

@ -1,13 +1,16 @@
import { ethers } from "ethers"; import { ethers } from "ethers";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { getTransactionTransfers } from "./nodeFunctions"; import {
import { TransactionData, Transfer } from "./types"; getTransactionSelfDestructs,
getTransactionTransfers,
} from "./nodeFunctions";
import { InternalTransfers, TransactionData } from "./types";
export const useInternalTransfers = ( export const useInternalTransfers = (
provider: ethers.providers.JsonRpcProvider | undefined, provider: ethers.providers.JsonRpcProvider | undefined,
txData: TransactionData | undefined txData: TransactionData | undefined
) => { ): InternalTransfers | undefined => {
const [transfers, setTransfers] = useState<Transfer[]>(); const [intTransfers, setIntTransfers] = useState<InternalTransfers>();
useEffect(() => { useEffect(() => {
const traceTransfers = async () => { const traceTransfers = async () => {
@ -16,10 +19,17 @@ export const useInternalTransfers = (
} }
const _transfers = await getTransactionTransfers(provider, txData); const _transfers = await getTransactionTransfers(provider, txData);
setTransfers(_transfers); const _selfDestructs = await getTransactionSelfDestructs(
provider,
txData
);
for (const s of _selfDestructs) {
s.value = provider.formatter.bigNumber(s.value);
}
setIntTransfers({ transfers: _transfers, selfDestructs: _selfDestructs });
}; };
traceTransfers(); traceTransfers();
}, [provider, txData]); }, [provider, txData]);
return transfers; return intTransfers;
}; };