Add faucets support

This commit is contained in:
Willian Mitsuda 2022-04-05 22:38:27 -03:00
parent 00893de2e2
commit 45441884e1
5 changed files with 128 additions and 12 deletions

View File

@ -15,6 +15,7 @@ import StandardFrame from "./StandardFrame";
import StandardSubtitle from "./StandardSubtitle"; import StandardSubtitle from "./StandardSubtitle";
import AddressOrENSNameNotFound from "./components/AddressOrENSNameNotFound"; import AddressOrENSNameNotFound from "./components/AddressOrENSNameNotFound";
import Copy from "./components/Copy"; import Copy from "./components/Copy";
import Faucet from "./components/Faucet";
import NavTab from "./components/NavTab"; import NavTab from "./components/NavTab";
import SourcifyLogo from "./sourcify/SourcifyLogo"; import SourcifyLogo from "./sourcify/SourcifyLogo";
import AddressTransactionResults from "./address/AddressTransactionResults"; import AddressTransactionResults from "./address/AddressTransactionResults";
@ -25,6 +26,7 @@ import { useAddressOrENS } from "./useResolvedAddresses";
import { useMultipleMetadata } from "./sourcify/useSourcify"; import { useMultipleMetadata } from "./sourcify/useSourcify";
import { ChecksummedAddress } from "./types"; import { ChecksummedAddress } from "./types";
import { useAddressesWithCode } from "./useErigonHooks"; import { useAddressesWithCode } from "./useErigonHooks";
import { useChainInfo } from "./useChainInfo";
const AddressTransactionByNonce = React.lazy( const AddressTransactionByNonce = React.lazy(
() => () =>
@ -86,6 +88,8 @@ const Address: React.FC = () => {
? metadatas[checksummedAddress] ? metadatas[checksummedAddress]
: undefined; : undefined;
const { faucets } = useChainInfo();
// Search address by nonce === transaction @ nonce // Search address by nonce === transaction @ nonce
const rawNonce = searchParams.get("nonce"); const rawNonce = searchParams.get("nonce");
if (rawNonce !== null) { if (rawNonce !== null) {
@ -119,6 +123,10 @@ const Address: React.FC = () => {
{checksummedAddress} {checksummedAddress}
</span> </span>
<Copy value={checksummedAddress} rounded /> <Copy value={checksummedAddress} rounded />
{/* Only display faucets for testnets who actually have any */}
{faucets && faucets.length > 0 && (
<Faucet address={checksummedAddress} rounded />
)}
{isENS && ( {isENS && (
<span className="rounded-lg px-2 py-1 bg-gray-200 text-gray-500 text-xs"> <span className="rounded-lg px-2 py-1 bg-gray-200 text-gray-500 text-xs">
ENS: {addressOrName} ENS: {addressOrName}

View File

@ -27,10 +27,10 @@ const Transaction = React.lazy(
import(/* webpackChunkName: "tx", webpackPrefetch: true */ "./Transaction") import(/* webpackChunkName: "tx", webpackPrefetch: true */ "./Transaction")
); );
const London = React.lazy( const London = React.lazy(
() => () => import(/* webpackChunkName: "london" */ "./special/london/London")
import( );
/* webpackChunkName: "london", webpackPrefetch: true */ "./special/london/London" const Faucets = React.lazy(
) () => import(/* webpackChunkName: "faucets" */ "./Faucets")
); );
const PageNotFound = React.lazy( const PageNotFound = React.lazy(
() => () =>
@ -74,6 +74,7 @@ const App = () => {
path="address/:addressOrName/*" path="address/:addressOrName/*"
element={<Address />} element={<Address />}
/> />
<Route path="faucets/*" element={<Faucets />} />
<Route path="*" element={<PageNotFound />} /> <Route path="*" element={<PageNotFound />} />
</Route> </Route>
</Routes> </Routes>

85
src/Faucets.tsx Normal file
View File

@ -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 (
<StandardFrame>
<StandardSubtitle>Faucets</StandardSubtitle>
<ContentFrame>
<div className="py-4 space-y-3">
{urls.length > 0 && (
<div className="flex space-x-2 items-baseline rounded bg-yellow-200 text-red-800 font-bold underline px-2 py-1">
<FontAwesomeIcon
className="self-center"
icon={faTriangleExclamation}
size="1x"
/>
<span>
The following external links come from
https://github.com/ethereum-lists/chains and are *NOT* endorsed
by us. Use at your own risk.
</span>
</div>
)}
{/* Display the shuffling notice only if there are 1+ faucets */}
{urls.length > 1 && (
<div className="flex space-x-2 items-baseline rounded bg-yellow-200 text-yellow-700 px-2 py-1">
<FontAwesomeIcon
className="self-center"
icon={faTriangleExclamation}
size="1x"
/>
<span>The faucet links below are shuffled on page load.</span>
</div>
)}
{urls.length > 0 ? (
<div className="pt-2 space-y-3">
{urls.map((url) => (
<div className="flex space-x-2 items-baseline">
<FontAwesomeIcon
className="text-gray-400"
icon={faFaucetDrip}
size="1x"
/>
<ExternalLink key={url} href={url}>
<span>{url}</span>
</ExternalLink>
</div>
))}
</div>
) : (
<div>There are no registered faucets.</div>
)}
</div>
</ContentFrame>
</StandardFrame>
);
};
export default Faucets;

26
src/components/Faucet.tsx Normal file
View File

@ -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<FaucetProps> = ({ address, rounded }) => (
<NavLink
className={`self-center flex flex-no-wrap justify-center items-center space-x-1 text-gray-500 focus:outline-none ${
rounded
? "transition-colors transition-shadows bg-gray-200 hover:bg-gray-500 hover:text-gray-200 hover:shadow w-7 h-7 rounded-full text-xs"
: "text-sm"
}`}
to={`/faucets?address=${address}`}
title="Click to go to faucets page"
>
<FontAwesomeIcon icon={faFaucetDrip} size="1x" />
</NavLink>
);
export default React.memo(Faucet);

View File

@ -3,6 +3,7 @@ import { chainInfoURL } from "./url";
import { OtterscanRuntime } from "./useRuntime"; import { OtterscanRuntime } from "./useRuntime";
export type ChainInfo = { export type ChainInfo = {
faucets: string[];
nativeCurrency: { nativeCurrency: {
name: string; name: string;
symbol: string; symbol: string;
@ -11,6 +12,7 @@ export type ChainInfo = {
}; };
export const defaultChainInfo: ChainInfo = { export const defaultChainInfo: ChainInfo = {
faucets: [],
nativeCurrency: { nativeCurrency: {
name: "Ether", name: "Ether",
symbol: "ETH", symbol: "ETH",
@ -41,15 +43,9 @@ export const useChainInfoFromMetadataFile = (
setChainInfo(defaultChainInfo); setChainInfo(defaultChainInfo);
return; return;
} }
const info = await res.json();
setChainInfo({ const info: ChainInfo = await res.json();
nativeCurrency: { setChainInfo(info);
name: info.nativeCurrency.name,
decimals: info.nativeCurrency.decimals,
symbol: info.nativeCurrency.symbol,
},
});
} catch (err) { } catch (err) {
// ignore // ignore
setChainInfo(defaultChainInfo); setChainInfo(defaultChainInfo);