diff --git a/src/special/BlockRecord.tsx b/src/special/BlockRecord.tsx new file mode 100644 index 0000000..01a499a --- /dev/null +++ b/src/special/BlockRecord.tsx @@ -0,0 +1,55 @@ +import { ethers } from "ethers"; +import React from "react"; +import BlockLink from "../components/BlockLink"; +import { ExtendedBlock } from "../useErigonHooks"; + +const ELASTICITY_MULTIPLIER = 2; + +type BlockRecordProps = { + block: ExtendedBlock; +}; + +const BlockRecord: React.FC = ({ block }) => { + const gasTarget = block.gasLimit.div(ELASTICITY_MULTIPLIER); + const burntFees = + block?.baseFeePerGas && block.baseFeePerGas.mul(block.gasUsed); + const netFeeReward = block && block.feeReward.sub(burntFees ?? 0); + const totalReward = block.blockReward.add(netFeeReward ?? 0); + + return ( +
+
+ +
+
{block.baseFeePerGas?.toString()} wei
+
+ {ethers.utils.commify(block.gasUsed.toString())} +
+
+ {ethers.utils.commify( + ethers.utils.formatUnits( + block.gasUsed.mul(block.baseFeePerGas!).toString(), + 9 + ) + )}{" "} + Gwei +
+
+ {ethers.utils.commify(gasTarget.toString())} +
+
+ {ethers.utils.commify(ethers.utils.formatEther(totalReward))} Ether +
+
+ ); +}; + +export default React.memo(BlockRecord); diff --git a/src/special/Blocks.tsx b/src/special/Blocks.tsx new file mode 100644 index 0000000..d1cc325 --- /dev/null +++ b/src/special/Blocks.tsx @@ -0,0 +1,65 @@ +import React, { useState, useEffect, useContext } from "react"; +import { ethers } from "ethers"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faBurn, faGasPump } from "@fortawesome/free-solid-svg-icons"; +import BlockRecord from "./BlockRecord"; +import { ExtendedBlock, readBlock } from "../useErigonHooks"; +import { RuntimeContext } from "../useRuntime"; + +const MAX_BLOCK_HISTORY = 10; + +type BlocksProps = { + latestBlock: ethers.providers.Block; +}; + +const Blocks: React.FC = ({ latestBlock }) => { + const { provider } = useContext(RuntimeContext); + const [blocks, setBlock] = useState([]); + + useEffect(() => { + if (!provider) { + return; + } + + const _readBlock = async () => { + const extBlock = await readBlock(provider, latestBlock.number.toString()); + setBlock((_blocks) => { + if (_blocks.length > 0 && latestBlock.number === _blocks[0].number) { + return _blocks; + } + return [extBlock, ..._blocks].slice(0, MAX_BLOCK_HISTORY); + }); + }; + _readBlock(); + }, [provider, latestBlock]); + + return ( +
+
+
+
Block
+
Base fee
+
+ + + + Gas used +
+
+ + + + Burnt fees +
+
Gas target
+
Rewards
+
+ {blocks.map((b) => ( + + ))} +
+
+ ); +}; + +export default React.memo(Blocks); diff --git a/src/special/London.tsx b/src/special/London.tsx index 65e7ba4..b4d211c 100644 --- a/src/special/London.tsx +++ b/src/special/London.tsx @@ -2,6 +2,7 @@ import React, { useContext } from "react"; import { useLatestBlock } from "../useLatestBlock"; import { RuntimeContext } from "../useRuntime"; import Countdown from "./Countdown"; +import Blocks from "./Blocks"; const londonBlockNumber: { [chainId: string]: number } = { "1": 12965000, @@ -30,7 +31,7 @@ const London: React.FC = () => { ); } - return
; + return ; }; export default React.memo(London); diff --git a/src/useErigonHooks.ts b/src/useErigonHooks.ts index ecbda33..d11d2f5 100644 --- a/src/useErigonHooks.ts +++ b/src/useErigonHooks.ts @@ -13,6 +13,49 @@ export interface ExtendedBlock extends ethers.providers.Block { totalDifficulty: BigNumber; } +export const readBlock = async ( + provider: ethers.providers.JsonRpcProvider, + blockNumberOrHash: string +) => { + let blockPromise: Promise; + if (ethers.utils.isHexString(blockNumberOrHash, 32)) { + blockPromise = provider.send("eth_getBlockByHash", [ + blockNumberOrHash, + false, + ]); + } else { + blockPromise = provider.send("eth_getBlockByNumber", [ + blockNumberOrHash, + false, + ]); + } + const [_rawBlock, _rawIssuance, _rawReceipts] = await Promise.all([ + blockPromise, + provider.send("erigon_issuance", [blockNumberOrHash]), + provider.send("eth_getBlockReceipts", [blockNumberOrHash]), + ]); + const receipts = (_rawReceipts as any[]).map((r) => + provider.formatter.receipt(r) + ); + const fees = receipts.reduce( + (acc, r) => acc.add(r.effectiveGasPrice.mul(r.gasUsed)), + BigNumber.from(0) + ); + + const _block = provider.formatter.block(_rawBlock); + const extBlock: ExtendedBlock = { + blockReward: provider.formatter.bigNumber(_rawIssuance.blockReward ?? 0), + unclesReward: provider.formatter.bigNumber(_rawIssuance.uncleReward ?? 0), + feeReward: fees, + size: provider.formatter.number(_rawBlock.size), + sha3Uncles: _rawBlock.sha3Uncles, + stateRoot: _rawBlock.stateRoot, + totalDifficulty: provider.formatter.bigNumber(_rawBlock.totalDifficulty), + ..._block, + }; + return extBlock; +}; + export const useBlockData = ( provider: ethers.providers.JsonRpcProvider | undefined, blockNumberOrHash: string @@ -23,52 +66,11 @@ export const useBlockData = ( return; } - const readBlock = async () => { - let blockPromise: Promise; - if (ethers.utils.isHexString(blockNumberOrHash, 32)) { - blockPromise = provider.send("eth_getBlockByHash", [ - blockNumberOrHash, - false, - ]); - } else { - blockPromise = provider.send("eth_getBlockByNumber", [ - blockNumberOrHash, - false, - ]); - } - const [_rawBlock, _rawIssuance, _rawReceipts] = await Promise.all([ - blockPromise, - provider.send("erigon_issuance", [blockNumberOrHash]), - provider.send("eth_getBlockReceipts", [blockNumberOrHash]), - ]); - const receipts = (_rawReceipts as any[]).map((r) => - provider.formatter.receipt(r) - ); - const fees = receipts.reduce( - (acc, r) => acc.add(r.effectiveGasPrice.mul(r.gasUsed)), - BigNumber.from(0) - ); - - const _block = provider.formatter.block(_rawBlock); - const extBlock: ExtendedBlock = { - blockReward: provider.formatter.bigNumber( - _rawIssuance.blockReward ?? 0 - ), - unclesReward: provider.formatter.bigNumber( - _rawIssuance.uncleReward ?? 0 - ), - feeReward: fees, - size: provider.formatter.number(_rawBlock.size), - sha3Uncles: _rawBlock.sha3Uncles, - stateRoot: _rawBlock.stateRoot, - totalDifficulty: provider.formatter.bigNumber( - _rawBlock.totalDifficulty - ), - ..._block, - }; + const _readBlock = async () => { + const extBlock = await readBlock(provider, blockNumberOrHash); setBlock(extBlock); }; - readBlock(); + _readBlock(); }, [provider, blockNumberOrHash]); return block;