2021-07-08 19:02:42 +00:00
|
|
|
import React, { useEffect, useState, useMemo, useContext } from "react";
|
2021-07-01 18:21:40 +00:00
|
|
|
import { useParams, useLocation } from "react-router";
|
|
|
|
import { ethers } from "ethers";
|
|
|
|
import queryString from "query-string";
|
|
|
|
import StandardFrame from "./StandardFrame";
|
2021-07-23 22:48:34 +00:00
|
|
|
import BlockTransactionHeader from "./block/BlockTransactionHeader";
|
|
|
|
import BlockTransactionResults from "./block/BlockTransactionResults";
|
2021-07-22 02:00:09 +00:00
|
|
|
import {
|
|
|
|
InternalOperation,
|
|
|
|
OperationType,
|
|
|
|
ProcessedTransaction,
|
|
|
|
} from "./types";
|
2021-07-01 18:21:40 +00:00
|
|
|
import { PAGE_SIZE } from "./params";
|
2021-07-09 05:07:20 +00:00
|
|
|
import { RuntimeContext } from "./useRuntime";
|
2021-07-01 18:21:40 +00:00
|
|
|
|
|
|
|
type BlockParams = {
|
|
|
|
blockNumber: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
type PageParams = {
|
|
|
|
p?: number;
|
|
|
|
};
|
|
|
|
|
|
|
|
const BlockTransactions: React.FC = () => {
|
2021-07-09 05:07:20 +00:00
|
|
|
const { provider } = useContext(RuntimeContext);
|
2021-07-01 18:21:40 +00:00
|
|
|
const params = useParams<BlockParams>();
|
|
|
|
const location = useLocation<PageParams>();
|
|
|
|
const qs = queryString.parse(location.search);
|
|
|
|
let pageNumber = 1;
|
|
|
|
if (qs.p) {
|
|
|
|
try {
|
|
|
|
pageNumber = parseInt(qs.p as string);
|
|
|
|
} catch (err) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
const blockNumber = useMemo(
|
|
|
|
() => ethers.BigNumber.from(params.blockNumber),
|
|
|
|
[params.blockNumber]
|
|
|
|
);
|
|
|
|
|
|
|
|
const [txs, setTxs] = useState<ProcessedTransaction[]>();
|
|
|
|
useEffect(() => {
|
2021-07-08 19:02:42 +00:00
|
|
|
if (!provider) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-07-01 18:21:40 +00:00
|
|
|
const readBlock = async () => {
|
|
|
|
const [_block, _receipts] = await Promise.all([
|
|
|
|
provider.getBlockWithTransactions(blockNumber.toNumber()),
|
|
|
|
provider.send("eth_getBlockReceipts", [blockNumber.toNumber()]),
|
|
|
|
]);
|
|
|
|
document.title = `Block #${_block.number} Transactions | Otterscan`;
|
|
|
|
|
2021-07-05 03:34:40 +00:00
|
|
|
const responses = _block.transactions
|
|
|
|
.map((t, i): ProcessedTransaction => {
|
|
|
|
return {
|
|
|
|
blockNumber: blockNumber.toNumber(),
|
|
|
|
timestamp: _block.timestamp,
|
|
|
|
miner: _block.miner,
|
|
|
|
idx: i,
|
|
|
|
hash: t.hash,
|
|
|
|
from: t.from,
|
|
|
|
to: t.to,
|
2021-07-21 04:46:10 +00:00
|
|
|
createdContractAddress: _receipts[i].contractAddress,
|
2021-07-05 03:34:40 +00:00
|
|
|
value: t.value,
|
|
|
|
fee: provider.formatter
|
|
|
|
.bigNumber(_receipts[i].gasUsed)
|
|
|
|
.mul(t.gasPrice!),
|
|
|
|
gasPrice: t.gasPrice!,
|
|
|
|
data: t.data,
|
|
|
|
status: provider.formatter.number(_receipts[i].status),
|
|
|
|
};
|
|
|
|
})
|
|
|
|
.reverse();
|
2021-07-05 20:52:20 +00:00
|
|
|
setTxs(responses);
|
2021-07-05 03:34:40 +00:00
|
|
|
|
|
|
|
const internalChecks = await Promise.all(
|
|
|
|
responses.map(async (res) => {
|
2021-07-22 02:00:09 +00:00
|
|
|
const r: InternalOperation[] = await provider.send(
|
|
|
|
"ots_getInternalOperations",
|
|
|
|
[res.hash]
|
|
|
|
);
|
|
|
|
for (const op of r) {
|
|
|
|
if (op.type !== OperationType.TRANSFER) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-05 03:34:40 +00:00
|
|
|
if (
|
|
|
|
res.miner &&
|
2021-07-22 02:00:09 +00:00
|
|
|
(res.miner === ethers.utils.getAddress(op.from) ||
|
|
|
|
res.miner === ethers.utils.getAddress(op.to))
|
2021-07-05 03:34:40 +00:00
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
})
|
2021-07-01 18:21:40 +00:00
|
|
|
);
|
2021-07-05 20:52:20 +00:00
|
|
|
const processedResponses = responses.map((r, i): ProcessedTransaction => {
|
|
|
|
return { ...r, internalMinerInteraction: internalChecks[i] };
|
|
|
|
});
|
|
|
|
setTxs(processedResponses);
|
2021-07-01 18:21:40 +00:00
|
|
|
};
|
|
|
|
readBlock();
|
2021-07-08 19:02:42 +00:00
|
|
|
}, [provider, blockNumber]);
|
2021-07-01 18:21:40 +00:00
|
|
|
|
|
|
|
const page = useMemo(() => {
|
|
|
|
if (!txs) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
const pageStart = (pageNumber - 1) * PAGE_SIZE;
|
|
|
|
return txs.slice(pageStart, pageStart + PAGE_SIZE);
|
|
|
|
}, [txs, pageNumber]);
|
|
|
|
const total = useMemo(() => txs?.length ?? 0, [txs]);
|
|
|
|
|
|
|
|
document.title = `Block #${blockNumber} Txns | Otterscan`;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<StandardFrame>
|
2021-07-14 19:57:08 +00:00
|
|
|
<BlockTransactionHeader blockTag={blockNumber.toNumber()} />
|
|
|
|
<BlockTransactionResults
|
|
|
|
page={page}
|
|
|
|
total={total}
|
|
|
|
pageNumber={pageNumber}
|
|
|
|
/>
|
2021-07-01 18:21:40 +00:00
|
|
|
</StandardFrame>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default React.memo(BlockTransactions);
|