First iteration at showing incoming blocks
This commit is contained in:
parent
97e46108cc
commit
aba239bf8c
55
src/special/BlockRecord.tsx
Normal file
55
src/special/BlockRecord.tsx
Normal file
@ -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<BlockRecordProps> = ({ 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 (
|
||||||
|
<div className="grid grid-cols-8 px-3 py-2">
|
||||||
|
<div>
|
||||||
|
<BlockLink blockTag={block.number} />
|
||||||
|
</div>
|
||||||
|
<div className="text-right">{block.baseFeePerGas?.toString()} wei</div>
|
||||||
|
<div
|
||||||
|
className={`text-right ${
|
||||||
|
block.gasUsed.gt(gasTarget)
|
||||||
|
? "text-green-500"
|
||||||
|
: block.gasUsed.lt(gasTarget)
|
||||||
|
? "text-red-500"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{ethers.utils.commify(block.gasUsed.toString())}
|
||||||
|
</div>
|
||||||
|
<div className="text-right">
|
||||||
|
{ethers.utils.commify(
|
||||||
|
ethers.utils.formatUnits(
|
||||||
|
block.gasUsed.mul(block.baseFeePerGas!).toString(),
|
||||||
|
9
|
||||||
|
)
|
||||||
|
)}{" "}
|
||||||
|
Gwei
|
||||||
|
</div>
|
||||||
|
<div className="text-right">
|
||||||
|
{ethers.utils.commify(gasTarget.toString())}
|
||||||
|
</div>
|
||||||
|
<div className="text-right col-span-2">
|
||||||
|
{ethers.utils.commify(ethers.utils.formatEther(totalReward))} Ether
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(BlockRecord);
|
65
src/special/Blocks.tsx
Normal file
65
src/special/Blocks.tsx
Normal file
@ -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<BlocksProps> = ({ latestBlock }) => {
|
||||||
|
const { provider } = useContext(RuntimeContext);
|
||||||
|
const [blocks, setBlock] = useState<ExtendedBlock[]>([]);
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className="w-full h-full">
|
||||||
|
<div className="m-10 divide-y-2">
|
||||||
|
<div className="grid grid-cols-8 px-3 py-2">
|
||||||
|
<div>Block</div>
|
||||||
|
<div className="text-right">Base fee</div>
|
||||||
|
<div className="text-right flex space-x-1 justify-end items-baseline">
|
||||||
|
<span className="text-gray-500">
|
||||||
|
<FontAwesomeIcon icon={faGasPump} />
|
||||||
|
</span>
|
||||||
|
<span>Gas used</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-right flex space-x-1 justify-end items-baseline">
|
||||||
|
<span className="text-orange-500">
|
||||||
|
<FontAwesomeIcon icon={faBurn} />
|
||||||
|
</span>
|
||||||
|
<span>Burnt fees</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-right">Gas target</div>
|
||||||
|
<div className="text-right col-span-2">Rewards</div>
|
||||||
|
</div>
|
||||||
|
{blocks.map((b) => (
|
||||||
|
<BlockRecord key={b.hash} block={b} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(Blocks);
|
@ -2,6 +2,7 @@ import React, { useContext } from "react";
|
|||||||
import { useLatestBlock } from "../useLatestBlock";
|
import { useLatestBlock } from "../useLatestBlock";
|
||||||
import { RuntimeContext } from "../useRuntime";
|
import { RuntimeContext } from "../useRuntime";
|
||||||
import Countdown from "./Countdown";
|
import Countdown from "./Countdown";
|
||||||
|
import Blocks from "./Blocks";
|
||||||
|
|
||||||
const londonBlockNumber: { [chainId: string]: number } = {
|
const londonBlockNumber: { [chainId: string]: number } = {
|
||||||
"1": 12965000,
|
"1": 12965000,
|
||||||
@ -30,7 +31,7 @@ const London: React.FC = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="w-full h-full"></div>;
|
return <Blocks latestBlock={block} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(London);
|
export default React.memo(London);
|
||||||
|
@ -13,6 +13,49 @@ export interface ExtendedBlock extends ethers.providers.Block {
|
|||||||
totalDifficulty: BigNumber;
|
totalDifficulty: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const readBlock = async (
|
||||||
|
provider: ethers.providers.JsonRpcProvider,
|
||||||
|
blockNumberOrHash: string
|
||||||
|
) => {
|
||||||
|
let blockPromise: Promise<any>;
|
||||||
|
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 = (
|
export const useBlockData = (
|
||||||
provider: ethers.providers.JsonRpcProvider | undefined,
|
provider: ethers.providers.JsonRpcProvider | undefined,
|
||||||
blockNumberOrHash: string
|
blockNumberOrHash: string
|
||||||
@ -23,52 +66,11 @@ export const useBlockData = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const readBlock = async () => {
|
const _readBlock = async () => {
|
||||||
let blockPromise: Promise<any>;
|
const extBlock = await readBlock(provider, blockNumberOrHash);
|
||||||
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,
|
|
||||||
};
|
|
||||||
setBlock(extBlock);
|
setBlock(extBlock);
|
||||||
};
|
};
|
||||||
readBlock();
|
_readBlock();
|
||||||
}, [provider, blockNumberOrHash]);
|
}, [provider, blockNumberOrHash]);
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
|
Loading…
Reference in New Issue
Block a user