From 5086b6f8565fc665669b6e3349f404420a5e9d1d Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Sat, 2 Apr 2022 14:56:36 -0300 Subject: [PATCH 1/5] Use native ethereum-lists/chains json format; dont reinvent the wheel --- src/Block.tsx | 8 +++++--- src/PriceBox.tsx | 8 +++++--- src/components/InternalSelfDestruct.tsx | 6 ++++-- src/components/InternalTransfer.tsx | 6 ++++-- src/components/TransactionValue.tsx | 10 ++++++---- src/components/USDValue.tsx | 6 ++++-- src/special/london/BlockRow.tsx | 9 +++++---- src/transaction/Details.tsx | 18 +++++++++--------- src/transaction/RewardSplit.tsx | 8 +++++--- src/transaction/TraceInput.tsx | 7 ++++--- src/useChainInfo.ts | 24 +++++++++++++++--------- 11 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/Block.tsx b/src/Block.tsx index 97b14ba..c8afe43 100644 --- a/src/Block.tsx +++ b/src/Block.tsx @@ -34,7 +34,9 @@ const Block: React.FC = () => { if (blockNumberOrHash === undefined) { throw new Error("blockNumberOrHash couldn't be undefined here"); } - const { nativeName, nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { name, symbol }, + } = useChainInfo(); const block = useBlockData(provider, blockNumberOrHash); useEffect(() => { @@ -146,7 +148,7 @@ const Block: React.FC = () => { {" "} - {nativeSymbol} + {symbol} @@ -165,7 +167,7 @@ const Block: React.FC = () => { {extraStr} (Hex:{" "} {block.extraData}) - + diff --git a/src/PriceBox.tsx b/src/PriceBox.tsx index 2f5bd4d..1e2586a 100644 --- a/src/PriceBox.tsx +++ b/src/PriceBox.tsx @@ -14,7 +14,9 @@ const ETH_FEED_DECIMALS = 8; // TODO: reduce duplication with useETHUSDOracle const PriceBox: React.FC = () => { const { provider } = useContext(RuntimeContext); - const { nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); const latestBlock = useLatestBlock(provider); const maybeOutdated: boolean = @@ -82,9 +84,9 @@ const PriceBox: React.FC = () => { } font-sans text-xs text-gray-800`} > - {nativeSymbol}: ${latestPrice} + {symbol}: ${latestPrice} {latestGasData && ( <> diff --git a/src/components/InternalSelfDestruct.tsx b/src/components/InternalSelfDestruct.tsx index 9bcb0ad..8cb828e 100644 --- a/src/components/InternalSelfDestruct.tsx +++ b/src/components/InternalSelfDestruct.tsx @@ -17,7 +17,9 @@ const InternalSelfDestruct: React.FC = ({ txData, internalOp, }) => { - const { nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); const toMiner = txData.confirmedData?.miner !== undefined && internalOp.to === txData.confirmedData.miner; @@ -46,7 +48,7 @@ const InternalSelfDestruct: React.FC = ({ TRANSFER - {formatEther(internalOp.value)} {nativeSymbol} + {formatEther(internalOp.value)} {symbol}
To diff --git a/src/components/InternalTransfer.tsx b/src/components/InternalTransfer.tsx index b73bdf0..b52acb9 100644 --- a/src/components/InternalTransfer.tsx +++ b/src/components/InternalTransfer.tsx @@ -18,7 +18,9 @@ const InternalTransfer: React.FC = ({ txData, internalOp, }) => { - const { nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); const fromMiner = txData.confirmedData?.miner !== undefined && internalOp.from === txData.confirmedData.miner; @@ -44,7 +46,7 @@ const InternalTransfer: React.FC = ({ TRANSFER - {formatEther(internalOp.value)} {nativeSymbol} + {formatEther(internalOp.value)} {symbol}
From diff --git a/src/components/TransactionValue.tsx b/src/components/TransactionValue.tsx index b4a9d54..53f9300 100644 --- a/src/components/TransactionValue.tsx +++ b/src/components/TransactionValue.tsx @@ -22,16 +22,18 @@ const TransactionValue: React.FC = ({ value, hideUnit, }) => { - const { nativeSymbol, nativeDecimals } = useChainInfo(); - const formattedValue = formatValue(value, nativeDecimals); + const { + nativeCurrency: { symbol, decimals }, + } = useChainInfo(); + const formattedValue = formatValue(value, decimals); return ( {formattedValue} - {!hideUnit && ` ${nativeSymbol}`} + {!hideUnit && ` ${symbol}`} ); }; diff --git a/src/components/USDValue.tsx b/src/components/USDValue.tsx index 9554e41..90da1c2 100644 --- a/src/components/USDValue.tsx +++ b/src/components/USDValue.tsx @@ -10,7 +10,9 @@ type USDValueProps = { }; const USDValue: React.FC = ({ value }) => { - const { nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); return ( @@ -24,7 +26,7 @@ const USDValue: React.FC = ({ value }) => { .toString() )} {" "} - / {nativeSymbol} + / {symbol} ) : ( "N/A" diff --git a/src/special/london/BlockRow.tsx b/src/special/london/BlockRow.tsx index 3d1cf8f..3bec637 100644 --- a/src/special/london/BlockRow.tsx +++ b/src/special/london/BlockRow.tsx @@ -16,7 +16,9 @@ type BlockRowProps = { }; const BlockRow: React.FC = ({ now, block, baseFeeDelta }) => { - const { nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); const gasTarget = block.gasLimit.div(ELASTICITY_MULTIPLIER); const burntFees = block?.baseFeePerGas && block.baseFeePerGas.mul(block.gasUsed); @@ -55,11 +57,10 @@ const BlockRow: React.FC = ({ now, block, baseFeeDelta }) => {
- {commify(formatEther(totalReward))} {nativeSymbol} + {commify(formatEther(totalReward))} {symbol}
- {commify(formatEther(block.gasUsed.mul(block.baseFeePerGas!)))}{" "} - {nativeSymbol} + {commify(formatEther(block.gasUsed.mul(block.baseFeePerGas!)))} {symbol}
diff --git a/src/transaction/Details.tsx b/src/transaction/Details.tsx index e845d5e..a5d0661 100644 --- a/src/transaction/Details.tsx +++ b/src/transaction/Details.tsx @@ -87,7 +87,9 @@ const Details: React.FC = ({ const devMethod = txDesc ? devDoc?.methods[txDesc.signature] : undefined; const { provider } = useContext(RuntimeContext); - const { nativeName, nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { name, symbol }, + } = useChainInfo(); const addresses = useMemo(() => { const _addresses: ChecksummedAddress[] = []; if (txData.to) { @@ -315,7 +317,7 @@ const Details: React.FC = ({ )} - {nativeSymbol}{" "} + {symbol}{" "} {!txData.value.isZero() && ethUSDPrice && ( @@ -338,8 +340,7 @@ const Details: React.FC = ({ {txData.type === 2 && ( <> - {" "} - {nativeSymbol} ( + {symbol} ( = ({ Gwei) - {nativeSymbol} ( + {symbol} ( Gwei) @@ -356,7 +357,7 @@ const Details: React.FC = ({
- {nativeSymbol} ( + {symbol} ( Gwei) {sendsEthToMiner && ( @@ -407,8 +408,7 @@ const Details: React.FC = ({
- {" "} - {nativeSymbol}{" "} + {symbol}{" "} {ethUSDPrice && ( = ({ {hasEIP1559 && }
- + diff --git a/src/transaction/RewardSplit.tsx b/src/transaction/RewardSplit.tsx index d6e47b3..b9268c4 100644 --- a/src/transaction/RewardSplit.tsx +++ b/src/transaction/RewardSplit.tsx @@ -12,7 +12,9 @@ type RewardSplitProps = { }; const RewardSplit: React.FC = ({ txData }) => { - const { nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); const paidFees = txData.gasPrice.mul(txData.confirmedData!.gasUsed); const burntFees = txData.confirmedData!.blockBaseFeePerGas!.mul( txData.confirmedData!.gasUsed @@ -41,7 +43,7 @@ const RewardSplit: React.FC = ({ txData }) => { {" "} - {nativeSymbol} + {symbol}
@@ -57,7 +59,7 @@ const RewardSplit: React.FC = ({ txData }) => { - {nativeSymbol} + {symbol}
diff --git a/src/transaction/TraceInput.tsx b/src/transaction/TraceInput.tsx index c21adfc..f8f469a 100644 --- a/src/transaction/TraceInput.tsx +++ b/src/transaction/TraceInput.tsx @@ -19,7 +19,9 @@ type TraceInputProps = { }; const TraceInput: React.FC = ({ t }) => { - const { nativeSymbol } = useChainInfo(); + const { + nativeCurrency: { symbol }, + } = useChainInfo(); const raw4Bytes = extract4Bytes(t.input); const fourBytes = use4Bytes(raw4Bytes); const sigText = @@ -57,8 +59,7 @@ const TraceInput: React.FC = ({ t }) => { {t.value && !t.value.isZero() && ( - {"{"}value: {" "} - {nativeSymbol} + {"{"}value: {symbol} {"}"} )} diff --git a/src/useChainInfo.ts b/src/useChainInfo.ts index 5cd0f01..1d62904 100644 --- a/src/useChainInfo.ts +++ b/src/useChainInfo.ts @@ -3,15 +3,19 @@ import { chainInfoURL } from "./url"; import { OtterscanRuntime } from "./useRuntime"; export type ChainInfo = { - nativeName: string; - nativeSymbol: string; - nativeDecimals: number; + nativeCurrency: { + name: string; + symbol: string; + decimals: number; + }; }; export const defaultChainInfo: ChainInfo = { - nativeName: "Ether", - nativeSymbol: "ETH", - nativeDecimals: 18, + nativeCurrency: { + name: "Ether", + symbol: "ETH", + decimals: 18, + }, }; export const ChainInfoContext = createContext(undefined); @@ -40,9 +44,11 @@ export const useChainInfoFromMetadataFile = ( const info = await res.json(); setChainInfo({ - nativeName: info.nativeCurrency.name, - nativeDecimals: info.nativeCurrency.decimals, - nativeSymbol: info.nativeCurrency.symbol, + nativeCurrency: { + name: info.nativeCurrency.name, + decimals: info.nativeCurrency.decimals, + symbol: info.nativeCurrency.symbol, + }, }); } catch (err) { // ignore From 00893de2e230af6622b1d6c1b1efc90dae1a2784 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 5 Apr 2022 18:21:51 -0300 Subject: [PATCH 2/5] Rename and standardize Faucet prefix --- src/api/address-resolver/hardcoded-addresses/11155111.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/address-resolver/hardcoded-addresses/11155111.json b/src/api/address-resolver/hardcoded-addresses/11155111.json index d2a62ab..e534bca 100644 --- a/src/api/address-resolver/hardcoded-addresses/11155111.json +++ b/src/api/address-resolver/hardcoded-addresses/11155111.json @@ -1,3 +1,3 @@ { - "0xcFe95817aC44C3f8CE75F1EE6EC1431F586AB5A3": "FaucETH: Hot wallet" + "0xcFe95817aC44C3f8CE75F1EE6EC1431F586AB5A3": "Faucet: FaucETH" } \ No newline at end of file From 45441884e1ce95f08905bf7753c8a866542aaf8d Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 5 Apr 2022 22:38:27 -0300 Subject: [PATCH 3/5] Add faucets support --- src/Address.tsx | 8 ++++ src/App.tsx | 9 +++-- src/Faucets.tsx | 85 +++++++++++++++++++++++++++++++++++++++ src/components/Faucet.tsx | 26 ++++++++++++ src/useChainInfo.ts | 12 ++---- 5 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 src/Faucets.tsx create mode 100644 src/components/Faucet.tsx diff --git a/src/Address.tsx b/src/Address.tsx index f739e7b..24260c3 100644 --- a/src/Address.tsx +++ b/src/Address.tsx @@ -15,6 +15,7 @@ import StandardFrame from "./StandardFrame"; import StandardSubtitle from "./StandardSubtitle"; import AddressOrENSNameNotFound from "./components/AddressOrENSNameNotFound"; import Copy from "./components/Copy"; +import Faucet from "./components/Faucet"; import NavTab from "./components/NavTab"; import SourcifyLogo from "./sourcify/SourcifyLogo"; import AddressTransactionResults from "./address/AddressTransactionResults"; @@ -25,6 +26,7 @@ import { useAddressOrENS } from "./useResolvedAddresses"; import { useMultipleMetadata } from "./sourcify/useSourcify"; import { ChecksummedAddress } from "./types"; import { useAddressesWithCode } from "./useErigonHooks"; +import { useChainInfo } from "./useChainInfo"; const AddressTransactionByNonce = React.lazy( () => @@ -86,6 +88,8 @@ const Address: React.FC = () => { ? metadatas[checksummedAddress] : undefined; + const { faucets } = useChainInfo(); + // Search address by nonce === transaction @ nonce const rawNonce = searchParams.get("nonce"); if (rawNonce !== null) { @@ -119,6 +123,10 @@ const Address: React.FC = () => { {checksummedAddress}
+ {/* Only display faucets for testnets who actually have any */} + {faucets && faucets.length > 0 && ( + + )} {isENS && ( ENS: {addressOrName} diff --git a/src/App.tsx b/src/App.tsx index 81116d7..523dc5e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,10 +27,10 @@ const Transaction = React.lazy( import(/* webpackChunkName: "tx", webpackPrefetch: true */ "./Transaction") ); const London = React.lazy( - () => - import( - /* webpackChunkName: "london", webpackPrefetch: true */ "./special/london/London" - ) + () => import(/* webpackChunkName: "london" */ "./special/london/London") +); +const Faucets = React.lazy( + () => import(/* webpackChunkName: "faucets" */ "./Faucets") ); const PageNotFound = React.lazy( () => @@ -74,6 +74,7 @@ const App = () => { path="address/:addressOrName/*" element={
} /> + } /> } /> diff --git a/src/Faucets.tsx b/src/Faucets.tsx new file mode 100644 index 0000000..7e26bd1 --- /dev/null +++ b/src/Faucets.tsx @@ -0,0 +1,85 @@ +import React, { useMemo } from "react"; +import { useLocation } from "react-router-dom"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons/faTriangleExclamation"; +import { faFaucetDrip } from "@fortawesome/free-solid-svg-icons/faFaucetDrip"; +import ExternalLink from "./components/ExternalLink"; +import ContentFrame from "./ContentFrame"; +import StandardFrame from "./StandardFrame"; +import StandardSubtitle from "./StandardSubtitle"; +import { useChainInfo } from "./useChainInfo"; +const Faucets: React.FC = () => { + const { faucets } = useChainInfo(); + const loc = useLocation(); + const urls = useMemo(() => { + const s = new URLSearchParams(loc.search); + const address = s.get("address"); + + const _urls = faucets.map((u) => + address !== null ? u.replaceAll("${ADDRESS}", address) : u + ); + + // Shuffle faucets to avoid UI bias + for (let i = _urls.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [_urls[i], _urls[j]] = [_urls[j], _urls[i]]; + } + + return _urls; + }, [faucets, loc]); + + return ( + + Faucets + +
+ {urls.length > 0 && ( +
+ + + The following external links come from + https://github.com/ethereum-lists/chains and are *NOT* endorsed + by us. Use at your own risk. + +
+ )} + {/* Display the shuffling notice only if there are 1+ faucets */} + {urls.length > 1 && ( +
+ + The faucet links below are shuffled on page load. +
+ )} + {urls.length > 0 ? ( +
+ {urls.map((url) => ( +
+ + + {url} + +
+ ))} +
+ ) : ( +
There are no registered faucets.
+ )} +
+
+
+ ); +}; + +export default Faucets; diff --git a/src/components/Faucet.tsx b/src/components/Faucet.tsx new file mode 100644 index 0000000..a0480df --- /dev/null +++ b/src/components/Faucet.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import { NavLink } from "react-router-dom"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faFaucetDrip } from "@fortawesome/free-solid-svg-icons/faFaucetDrip"; +import { ChecksummedAddress } from "../types"; + +type FaucetProps = { + address: ChecksummedAddress; + rounded?: boolean; +}; + +const Faucet: React.FC = ({ address, rounded }) => ( + + + +); + +export default React.memo(Faucet); diff --git a/src/useChainInfo.ts b/src/useChainInfo.ts index 1d62904..c737c68 100644 --- a/src/useChainInfo.ts +++ b/src/useChainInfo.ts @@ -3,6 +3,7 @@ import { chainInfoURL } from "./url"; import { OtterscanRuntime } from "./useRuntime"; export type ChainInfo = { + faucets: string[]; nativeCurrency: { name: string; symbol: string; @@ -11,6 +12,7 @@ export type ChainInfo = { }; export const defaultChainInfo: ChainInfo = { + faucets: [], nativeCurrency: { name: "Ether", symbol: "ETH", @@ -41,15 +43,9 @@ export const useChainInfoFromMetadataFile = ( setChainInfo(defaultChainInfo); return; } - const info = await res.json(); - setChainInfo({ - nativeCurrency: { - name: info.nativeCurrency.name, - decimals: info.nativeCurrency.decimals, - symbol: info.nativeCurrency.symbol, - }, - }); + const info: ChainInfo = await res.json(); + setChainInfo(info); } catch (err) { // ignore setChainInfo(defaultChainInfo); From c59d07d17219ebadfc79e41a938ffca4c372b70f Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 5 Apr 2022 22:48:25 -0300 Subject: [PATCH 4/5] Update ethereum-lists/chains submodule --- chains | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chains b/chains index af79eb7..f795a1a 160000 --- a/chains +++ b/chains @@ -1 +1 @@ -Subproject commit af79eb7387b2a4f747bf31cb318d4f1db43c4d84 +Subproject commit f795a1a1ec5a6e87012f34eb148419a358bec04b From 6e5831af4b31060bedef8e3cc766b276a6ad318d Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Tue, 5 Apr 2022 22:51:34 -0300 Subject: [PATCH 5/5] Supress eslint because the template is intentional --- src/Faucets.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Faucets.tsx b/src/Faucets.tsx index 7e26bd1..d9c1eab 100644 --- a/src/Faucets.tsx +++ b/src/Faucets.tsx @@ -16,6 +16,7 @@ const Faucets: React.FC = () => { const address = s.get("address"); const _urls = faucets.map((u) => + // eslint-disable-next-line no-template-curly-in-string address !== null ? u.replaceAll("${ADDRESS}", address) : u );