import { useState, useEffect, useMemo } from "react"; import { Box, Container, Typography, useMediaQuery } from "@mui/material"; import { useConfig, useBalance } from "wagmi"; import { Helmet } from "react-helmet"; import ReactGA from "react-ga4"; import PageTitle from "../../components/PageTitle/PageTitle"; import Paper from "../../components/Paper/Paper"; import SwapCard from "../../components/Swap/SwapCard"; import TokenStack from "../../components/TokenStack/TokenStack"; import { PrimaryButton } from "../../components/Button"; import { Tab, Tabs } from "../../components/Tabs/Tabs"; import { DAI_ADDRESSES } from "../../constants/addresses"; import { DecimalBigNumber } from "../../helpers/DecimalBigNumber"; import { formatCurrency, formatNumber } from "../../helpers"; import { useBalance as useTokenBalance, useTokenSymbol, useTotalSupply, useConversionRate, useAccumulatedDonation, mintDai, burnDai } from "../../hooks/tokens"; const Faucet = ({ chainId, address, config, connect }) => { const isSmallScreen = useMediaQuery("(max-width: 650px)"); const isSemiSmallScreen = useMediaQuery("(max-width: 480px)"); const isVerySmallScreen = useMediaQuery("(max-width: 379px)"); const daiConversionRate = useConversionRate(chainId, "GDAI"); const accumulatedDonation = useAccumulatedDonation(chainId, "GDAI"); const { balance: daiBalance, refetch: daiBalanceRefetch } = useTokenBalance(chainId, "GDAI", address); const { data: nativeBalance, refetch: balanceRefetch } = useBalance({ address }); const { data: contractBalance, refetch: contractBalanceRefetch } = useBalance({ address }); const { totalSupply: reserveTotalSupply, refetch: refetchReserveTotalSupply } = useTotalSupply(chainId, "GDAI"); const { symbol: faucetSymbol } = useTokenSymbol(chainId, "GDAI"); const [isMint, setIsMint] = useState(true); const [isPending, setIsPending] = useState(false); const [balance, setBalance] = useState(new DecimalBigNumber(0, 0)); const [amount, setAmount] = useState(""); const [scanInfo, setScanInfo] = useState({ name: "", url: "", }); const [nativeInfo, setNativeInfo] = useState({ decimals: 18, name: "", symbol: "", }) useEffect(() => { ReactGA.send({ hitType: "pageview", page: "/faucet" }); }, []) useEffect(() => { const value = nativeBalance ? nativeBalance.value : 0n; const decimals = nativeBalance ? nativeBalance.decimals : 18; setBalance(new DecimalBigNumber(value, decimals)); }, [nativeBalance]); useEffect(() => { let scanName = ""; let scanUrl = ""; const client = config?.getClient(); scanName = client?.chain?.blockExplorers?.default?.name; scanUrl = client?.chain?.blockExplorers?.default?.url; setScanInfo({ name: scanName, url: scanUrl, }) setNativeInfo(client?.chain?.nativeCurrency) }, [chainId]); const changeIsMinted = (value) => { if (accumulatedDonation) { setAmount(""); setIsMint(value); } } const preparedAmount = useMemo(() => { if (address === "") new DecimalBigNumber("0", 0); const decimals = isMint ? nativeInfo.decimals : 18; return new DecimalBigNumber(amount, decimals); }, [amount, balance, nativeInfo]) const estimatedAmountIn = useMemo(() => { const rate = new DecimalBigNumber(daiConversionRate.toString(), 0); const value = new DecimalBigNumber(amount, nativeInfo.decimals); return value.mul(rate); }, [amount, daiConversionRate, nativeInfo]); const contractBalanceFree = useMemo(() => { const realContractBalance = contractBalance ? contractBalance : 0n; const preparedContractBalance = new DecimalBigNumber(realContractBalance, nativeInfo.decimals); const preparedAccumulatedDonation = new DecimalBigNumber( accumulatedDonation._value, accumulatedDonation._decimals + nativeInfo.decimals - 18 ); return preparedContractBalance.sub(preparedAccumulatedDonation); }, [contractBalance, accumulatedDonation]); const estimatedAmountOut = useMemo(() => { const value = new DecimalBigNumber(amount, nativeInfo.decimals); if (reserveTotalSupply._value > 0n) { return value.mul(contractBalanceFree).div(reserveTotalSupply); } return new DecimalBigNumber(0n, nativeInfo.decimals); }, [amount, contractBalanceFree, reserveTotalSupply, nativeInfo]); const actionOrConnect = async () => { if (address === "") { connect(); } else { setIsPending(true); if (isMint) { await mintDai(chainId, address, preparedAmount._value.toString()); } else { await burnDai(chainId, address, preparedAmount._value.toString()); } await balanceRefetch(); await daiBalanceRefetch(); await contractBalanceRefetch(); await refetchReserveTotalSupply(); setAmount(""); setIsPending(false); } } return ( ghostFaucet | gDAI Faucet changeIsMinted(view === 0)} TabIndicatorProps={{ style: { display: "none" } }} > {accumulatedDonation && } {!isSemiSmallScreen && Check on {scanInfo.name} } } enableBackground fullWidth > {isMint && } info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(balance.toString(), 4, nativeInfo.symbol)}`} value={amount} onChange={event => setAmount(event.currentTarget.value)} inputProps={{ "data-testid": "fromInput" }} />} {!isMint && } info={`${isSemiSmallScreen ? "" : "Balance: "}${formatCurrency(daiBalance.toString(), 4, faucetSymbol)}`} value={amount} onChange={event => setAmount(event.currentTarget.value)} inputProps={{ "data-testid": "fromInput" }} />} {isMint && ( <> {!isVerySmallScreen && {nativeInfo.symbol} multiplier:} {formatNumber(daiConversionRate, 2)} {!isVerySmallScreen && You will get:} {formatCurrency(estimatedAmountIn, 5, faucetSymbol)} {!isVerySmallScreen && Your {faucetSymbol} balance:} {formatCurrency(daiBalance, 5, faucetSymbol)} )} {!isMint && ( <> {!isVerySmallScreen && Accumulated {nativeInfo.symbol}:} {formatNumber(contractBalanceFree, 5)} {!isVerySmallScreen && You will get:} {formatCurrency(estimatedAmountOut, 5, nativeInfo.symbol)} {!isVerySmallScreen && Your {nativeInfo.symbol} balance:} {formatCurrency(balance, 5, nativeInfo.symbol)} )} actionOrConnect()} > {address === "" ? "Connect" : isMint ? "Mint" : "Burn" } ) } export default Faucet;