diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 2307e1a2d..544e31d15 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -344,7 +344,7 @@ "empty": "No options found" }, "testnetFaucet": { - "explanation": "Each address on goerli can claim {{ amount }}ETH to test out the ENS manager app, as well as all the new contracts.", + "explanation": "Each address on {{ testnet }} can claim {{ amount }} {{ ticker }} to test out the ENS manager app, as well as any other testnet usage.", "note": "It may take a few minutes to show up in your wallet." } } diff --git a/src/components/@molecules/FaucetBanner.tsx b/src/components/@molecules/FaucetBanner.tsx index e899f3c0f..f275d2798 100644 --- a/src/components/@molecules/FaucetBanner.tsx +++ b/src/components/@molecules/FaucetBanner.tsx @@ -1,5 +1,7 @@ +import { BigNumber } from '@ethersproject/bignumber' +import { formatEther } from '@ethersproject/units' import { useRouter } from 'next/router' -import { useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' @@ -15,7 +17,7 @@ import { } from '@ensdomains/thorin' import { useAccountSafely } from '@app/hooks/useAccountSafely' -import { useChainId } from '@app/hooks/useChainId' +import { useChainName } from '@app/hooks/useChainName' import useFaucet from '@app/hooks/useFaucet' import { InnerDialog } from '../@atoms/InnerDialog' @@ -44,8 +46,12 @@ const LargeCheckIcon = styled.svg( `, ) +const getAmountFromHex = (hex: `0x${string}`) => formatEther(BigNumber.from(hex)) +const msToDays = (ms: number) => Math.floor(ms / 1000 / 60 / 60 / 24) +const chainEthTicker = (chainName: string) => `${chainName.slice(0, 2)}ETH` + const FaucetBanner = () => { - const chainId = useChainId() + const chainName = useChainName() const { isReady } = useRouter() const { address } = useAccountSafely() const { @@ -60,7 +66,14 @@ const FaucetBanner = () => { const closeDialog = () => setDialogOpen(false) const openDialog = () => setDialogOpen(true) - if (chainId !== 5 || !isReady) return null + const amount = useMemo(() => getAmountFromHex(data?.amount || '0x0'), [data?.amount]) + + useEffect(() => { + closeDialog() + }, [chainName, address]) + + if ((chainName !== 'goerli' && chainName !== 'sepolia') || !isReady || isLoading || !data) + return null const BannerComponent = ( @@ -69,9 +82,13 @@ const FaucetBanner = () => { icon={} onClick={openDialog} alert="info" - title="You have unclaimed goETH!" + title={`You have unclaimed ${chainName} ETH!`} > - {t('testnetFaucet.explanation', { amount: '0.25' })} + {t('testnetFaucet.explanation', { + amount, + testnet: chainName, + ticker: chainEthTicker(chainName), + })} ) @@ -80,11 +97,18 @@ const FaucetBanner = () => { {dialogStage === 'default' ? ( <> - + diff --git a/src/components/pages/profile/[name]/tabs/PermissionsTab/NameChangePermissions.tsx b/src/components/pages/profile/[name]/tabs/PermissionsTab/NameChangePermissions.tsx index 4d0291945..a599b4fac 100644 --- a/src/components/pages/profile/[name]/tabs/PermissionsTab/NameChangePermissions.tsx +++ b/src/components/pages/profile/[name]/tabs/PermissionsTab/NameChangePermissions.tsx @@ -89,7 +89,7 @@ export const NameChangePermissions = ({ const { prepareDataInput } = useTransactionFlow() const showRevokePermissionsInput = prepareDataInput('RevokePermissions') - const isParentLocked = parentState === 'locked' + const isParentLocked = parentState === 'locked' || wrapperData?.parent.IS_DOT_ETH const permissions = CHILD_FUSES_WITHOUT_CBF.reduce<{ burned: FuseItem[]; unburned: FuseItem[] }>( (acc, permission) => { diff --git a/src/hooks/useFaucet.ts b/src/hooks/useFaucet.ts index 19083c996..be8146cdc 100644 --- a/src/hooks/useFaucet.ts +++ b/src/hooks/useFaucet.ts @@ -1,9 +1,11 @@ +import { useEffect } from 'react' import { useMutation, useQuery, useQueryClient } from 'wagmi' import { useQueryKeys } from '@app/utils/cacheKeyFactory' +import { FAUCET_WORKER_URL } from '@app/utils/constants' import { useAccountSafely } from './useAccountSafely' -import { useChainId } from './useChainId' +import { useChainName } from './useChainName' type BaseJsonRPC = { jsonrpc: string @@ -29,45 +31,53 @@ type FaucetStatus = 'ok' | 'paused' | 'out of funds' type JsonRpc = BaseJsonRPC & (ErrorJsonRPC | SuccessJsonRPC) -const ENDPOINT = +const createEndpoint = (chainName: string) => process.env.NODE_ENV === 'development' - ? 'http://localhost:8787/' - : 'https://ens-faucet.ens-cf.workers.dev/' + ? `http://localhost:8787/${chainName}` + : `${FAUCET_WORKER_URL}/${chainName}` const useFaucet = () => { const queryClient = useQueryClient() + const { address } = useAccountSafely() - const chainId = useChainId() + const chainName = useChainName() + const queryKey = useQueryKeys().faucet(address) + const { data, error, isLoading } = useQuery( - useQueryKeys().faucet(address), + queryKey, async () => { - const result: JsonRpc<{ eligible: boolean; next: number; status: FaucetStatus }> = - await fetch(ENDPOINT, { - method: 'POST', - body: JSON.stringify({ - jsonrpc: '2.0', - method: 'faucet_getAddress', - params: [address], - id: 1, - }), - headers: { - // eslint-disable-next-line @typescript-eslint/naming-convention - 'Content-Type': 'application/json', - }, - }).then((res) => res.json()) + const result: JsonRpc<{ + eligible: boolean + amount: `0x${string}` + interval: number + next: number + status: FaucetStatus + }> = await fetch(createEndpoint(chainName), { + method: 'POST', + body: JSON.stringify({ + jsonrpc: '2.0', + method: 'faucet_getAddress', + params: [address], + id: 1, + }), + headers: { + // eslint-disable-next-line @typescript-eslint/naming-convention + 'Content-Type': 'application/json', + }, + }).then((res) => res.json()) if (result.error) throw new Error(result.error.message) return result.result }, { - enabled: !!address && chainId === 5, + enabled: !!address && (chainName === 'goerli' || chainName === 'sepolia'), }, ) const mutation = useMutation( async () => { - const result: JsonRpc<{ id: string }> = await fetch(ENDPOINT, { + const result: JsonRpc<{ id: string }> = await fetch(createEndpoint(chainName), { method: 'POST', body: JSON.stringify({ jsonrpc: '2.0', @@ -87,11 +97,16 @@ const useFaucet = () => { }, { onSuccess: () => { - queryClient.resetQueries(['getFaucetEligibility', address]) + queryClient.resetQueries(queryKey) }, }, ) + useEffect(() => { + mutation.reset() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [chainName, address]) + return { data, error, diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 24625f813..63375c563 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -87,6 +87,8 @@ export const MOONPAY_WORKER_URL: { [key: number]: string } = { 1337: 'https://moonpay-goerli.ens-cf.workers.dev', } +export const FAUCET_WORKER_URL = 'https://ens-faucet.ens-cf.workers.dev' + export const WC_PROJECT_ID = '9b14144d470af1e03ab9d88aaa127332' // 102% of price as buffer for fluctuations