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-08-02 02:22:55 +00:00
|
|
|
import { 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-08-02 02:22:55 +00:00
|
|
|
import { getInternalOperations } from "./nodeFunctions";
|
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()]),
|
|
|
|
]);
|
|
|
|
|
2021-07-05 03:34:40 +00:00
|
|
|
const responses = _block.transactions
|
2021-08-02 02:48:06 +00:00
|
|
|
.map(
|
|
|
|
(t, i): ProcessedTransaction => ({
|
2021-07-05 03:34:40 +00:00
|
|
|
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,
|
2021-07-30 02:31:28 +00:00
|
|
|
fee:
|
|
|
|
t.type !== 2
|
|
|
|
? provider.formatter
|
|
|
|
.bigNumber(_receipts[i].gasUsed)
|
|
|
|
.mul(t.gasPrice!)
|
|
|
|
: provider.formatter
|
|
|
|
.bigNumber(_receipts[i].gasUsed)
|
|
|
|
.mul(t.maxPriorityFeePerGas!.add(_block.baseFeePerGas!)),
|
|
|
|
gasPrice:
|
|
|
|
t.type !== 2
|
|
|
|
? t.gasPrice!
|
|
|
|
: t.maxPriorityFeePerGas!.add(_block.baseFeePerGas!),
|
2021-07-05 03:34:40 +00:00
|
|
|
data: t.data,
|
|
|
|
status: provider.formatter.number(_receipts[i].status),
|
2021-08-02 02:48:06 +00:00
|
|
|
})
|
|
|
|
)
|
2021-07-05 03:34:40 +00:00
|
|
|
.reverse();
|
2021-07-05 20:52:20 +00:00
|
|
|
setTxs(responses);
|
2021-07-05 03:34:40 +00:00
|
|
|
|
2021-08-02 02:22:55 +00:00
|
|
|
const checkTouchMinerAddr = await Promise.all(
|
2021-07-05 03:34:40 +00:00
|
|
|
responses.map(async (res) => {
|
2021-08-02 02:22:55 +00:00
|
|
|
const ops = await getInternalOperations(provider, res.hash);
|
|
|
|
return (
|
|
|
|
ops.findIndex(
|
|
|
|
(op) =>
|
|
|
|
op.type === OperationType.TRANSFER &&
|
|
|
|
res.miner !== undefined &&
|
|
|
|
res.miner === ethers.utils.getAddress(op.to)
|
|
|
|
) !== -1
|
2021-07-22 02:00:09 +00:00
|
|
|
);
|
2021-07-05 03:34:40 +00:00
|
|
|
})
|
2021-07-01 18:21:40 +00:00
|
|
|
);
|
2021-08-02 02:48:06 +00:00
|
|
|
const processedResponses = responses.map(
|
|
|
|
(r, i): ProcessedTransaction => ({
|
|
|
|
...r,
|
|
|
|
internalMinerInteraction: checkTouchMinerAddr[i],
|
|
|
|
})
|
|
|
|
);
|
2021-07-05 20:52:20 +00:00
|
|
|
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);
|