From 4cdd6f18a0bf363287f52b37b786d545f0dbfba8 Mon Sep 17 00:00:00 2001 From: Kirill Klimenko Date: Thu, 7 Mar 2024 15:51:16 +0100 Subject: [PATCH] Refactor useEthersProvider and useEthersSigner to return singleton instance from EthersContext --- .../formComponents/AzoriusNFTDetail.tsx | 2 +- .../formComponents/AzoriusTokenDetails.tsx | 2 +- .../DaoCreator/hooks/usePrepareFormData.ts | 4 +- .../pages/DAOTreasury/components/Assets.tsx | 6 +- .../DaoDashboard/Info/InfoGovernance.tsx | 2 +- .../Signers/modals/AddSignerModal.tsx | 2 +- .../Signers/modals/RemoveSignerModal.tsx | 2 +- src/components/ui/modals/DelegateModal.tsx | 2 +- .../ui/modals/ForkProposalTemplateModal.tsx | 4 +- src/components/ui/modals/UnwrapToken.tsx | 2 +- src/components/ui/modals/WrapToken.tsx | 2 +- .../ui/proposal/useProposalCountdown.tsx | 2 +- src/graphql/utils/index.ts | 2 +- .../loaders/governance/useAzoriusProposals.ts | 8 ++- .../governance/useERC20LinearStrategy.ts | 2 +- .../governance/useERC721LinearStrategy.ts | 2 +- src/hooks/DAO/loaders/useFractalFreeze.ts | 2 +- .../DAO/loaders/useFractalGuardContracts.ts | 10 +++- src/hooks/DAO/loaders/useFractalNode.ts | 2 +- src/hooks/DAO/loaders/useFractalTreasury.ts | 2 +- .../DAO/loaders/useGovernanceContracts.ts | 3 +- src/hooks/DAO/proposal/useCastVote.ts | 2 +- src/hooks/DAO/proposal/usePrepareProposal.ts | 2 +- src/hooks/DAO/proposal/useSubmitProposal.ts | 4 +- src/hooks/DAO/useClawBack.ts | 2 +- src/hooks/DAO/useDAOName.ts | 2 +- src/hooks/safe/useSafeContracts.ts | 2 +- .../schemas/DAOCreate/useDAOCreateTests.ts | 2 +- .../schemas/common/useValidationAddress.tsx | 6 +- src/hooks/stake/lido/useLidoStaking.ts | 6 +- src/hooks/utils/useAddress.ts | 2 +- src/hooks/utils/useAvatar.ts | 2 +- src/hooks/utils/useBlockTimestamp.ts | 2 +- src/hooks/utils/useCurrentBlockNumber.ts | 2 +- src/hooks/utils/useDisplayName.ts | 2 +- src/hooks/utils/useEthersProvider.ts | 26 --------- src/hooks/utils/useEthersSigner.ts | 21 ------- src/hooks/utils/useSafeTransactions.ts | 2 +- src/hooks/utils/useSignerOrProvider.ts | 4 +- src/providers/App/hooks/useSafeAPI.ts | 5 +- src/providers/App/useReadOnlyValues.ts | 2 +- .../Ethers/hooks/useEthersProvider.ts | 7 +++ src/providers/Ethers/hooks/useEthersSigner.ts | 7 +++ src/providers/Ethers/index.tsx | 57 +++++++++++++++++++ src/providers/Providers.tsx | 26 +++++---- 45 files changed, 151 insertions(+), 109 deletions(-) delete mode 100644 src/hooks/utils/useEthersProvider.ts delete mode 100644 src/hooks/utils/useEthersSigner.ts create mode 100644 src/providers/Ethers/hooks/useEthersProvider.ts create mode 100644 src/providers/Ethers/hooks/useEthersSigner.ts create mode 100644 src/providers/Ethers/index.tsx diff --git a/src/components/DaoCreator/formComponents/AzoriusNFTDetail.tsx b/src/components/DaoCreator/formComponents/AzoriusNFTDetail.tsx index e422d285ea..7347420cf5 100644 --- a/src/components/DaoCreator/formComponents/AzoriusNFTDetail.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusNFTDetail.tsx @@ -4,7 +4,7 @@ import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { erc721ABI } from 'wagmi'; import useDisplayName from '../../../hooks/utils/useDisplayName'; -import { useEthersProvider } from '../../../hooks/utils/useEthersProvider'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { BigNumberValuePair, ERC721TokenConfig } from '../../../types'; import { BarLoader } from '../../ui/loaders/BarLoader'; diff --git a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx index 6ebd0fc126..5f3c2b775a 100644 --- a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; import { erc20ABI } from 'wagmi'; import { BACKGROUND_SEMI_TRANSPARENT } from '../../../constants/common'; import { createAccountSubstring } from '../../../hooks/utils/useDisplayName'; -import { useEthersProvider } from '../../../hooks/utils/useEthersProvider'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { TokenCreationType, ICreationStepProps } from '../../../types'; import SupportTooltip from '../../ui/badges/SupportTooltip'; import ContentBoxTitle from '../../ui/containers/ContentBox/ContentBoxTitle'; diff --git a/src/components/DaoCreator/hooks/usePrepareFormData.ts b/src/components/DaoCreator/hooks/usePrepareFormData.ts index 9e283280ed..54bece8582 100644 --- a/src/components/DaoCreator/hooks/usePrepareFormData.ts +++ b/src/components/DaoCreator/hooks/usePrepareFormData.ts @@ -1,8 +1,8 @@ import { IVotes__factory } from '@fractal-framework/fractal-contracts'; import { useCallback } from 'react'; -import { useEthersProvider } from '../../../hooks/utils/useEthersProvider'; -import { useEthersSigner } from '../../../hooks/utils/useEthersSigner'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { SafeMultisigDAO, DAOFreezeGuardConfig, diff --git a/src/components/pages/DAOTreasury/components/Assets.tsx b/src/components/pages/DAOTreasury/components/Assets.tsx index 5df12b13a4..89e0522f1f 100644 --- a/src/components/pages/DAOTreasury/components/Assets.tsx +++ b/src/components/pages/DAOTreasury/components/Assets.tsx @@ -248,7 +248,11 @@ export function Assets() { const showClaimETHButton = canUserCreateProposal && staking.lido && lidoWithdrawelNFT; useEffect(() => { const getLidoClaimableStatus = async () => { - if (!staking.lido?.withdrawalQueueContractAddress || !lidoWithdrawelNFT) { + if ( + !staking.lido?.withdrawalQueueContractAddress || + !lidoWithdrawelNFT || + !signerOrProvider + ) { return; } const withdrawalQueueContract = getWithdrawalQueueContract( diff --git a/src/components/pages/DaoDashboard/Info/InfoGovernance.tsx b/src/components/pages/DaoDashboard/Info/InfoGovernance.tsx index 6603d28907..b954621778 100644 --- a/src/components/pages/DaoDashboard/Info/InfoGovernance.tsx +++ b/src/components/pages/DaoDashboard/Info/InfoGovernance.tsx @@ -3,7 +3,7 @@ import { Govern } from '@decent-org/fractal-ui'; import { MultisigFreezeGuard } from '@fractal-framework/fractal-contracts'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useEthersProvider } from '../../../../hooks/utils/useEthersProvider'; +import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; import { useTimeHelpers } from '../../../../hooks/utils/useTimeHelpers'; import { useFractal } from '../../../../providers/App/AppProvider'; import { AzoriusGovernance, FreezeGuardType } from '../../../../types'; diff --git a/src/components/pages/DaoSettings/components/Signers/modals/AddSignerModal.tsx b/src/components/pages/DaoSettings/components/Signers/modals/AddSignerModal.tsx index 16877e04f1..55d7eb12cb 100644 --- a/src/components/pages/DaoSettings/components/Signers/modals/AddSignerModal.tsx +++ b/src/components/pages/DaoSettings/components/Signers/modals/AddSignerModal.tsx @@ -16,7 +16,7 @@ import { useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import * as Yup from 'yup'; import { useValidationAddress } from '../../../../../../hooks/schemas/common/useValidationAddress'; -import { useEthersSigner } from '../../../../../../hooks/utils/useEthersSigner'; +import { useEthersSigner } from '../../../../../../providers/Ethers/hooks/useEthersSigner'; import { useFractal } from '../../../../../../providers/App/AppProvider'; import { couldBeENS } from '../../../../../../utils/url'; import SupportTooltip from '../../../../../ui/badges/SupportTooltip'; diff --git a/src/components/pages/DaoSettings/components/Signers/modals/RemoveSignerModal.tsx b/src/components/pages/DaoSettings/components/Signers/modals/RemoveSignerModal.tsx index 7212e5a099..4cbf5454f8 100644 --- a/src/components/pages/DaoSettings/components/Signers/modals/RemoveSignerModal.tsx +++ b/src/components/pages/DaoSettings/components/Signers/modals/RemoveSignerModal.tsx @@ -13,7 +13,7 @@ import { import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Address, useEnsName } from 'wagmi'; -import { useEthersProvider } from '../../../../../../hooks/utils/useEthersProvider'; +import { useEthersProvider } from '../../../../../../providers/Ethers/hooks/useEthersProvider'; import { useFractal } from '../../../../../../providers/App/AppProvider'; import SupportTooltip from '../../../../../ui/badges/SupportTooltip'; import { CustomNonceInput } from '../../../../../ui/forms/CustomNonceInput'; diff --git a/src/components/ui/modals/DelegateModal.tsx b/src/components/ui/modals/DelegateModal.tsx index 9cff91ec09..db041c035e 100644 --- a/src/components/ui/modals/DelegateModal.tsx +++ b/src/components/ui/modals/DelegateModal.tsx @@ -7,7 +7,7 @@ import * as Yup from 'yup'; import useDelegateVote from '../../../hooks/DAO/useDelegateVote'; import { useValidationAddress } from '../../../hooks/schemas/common/useValidationAddress'; import useDisplayName from '../../../hooks/utils/useDisplayName'; -import { useEthersSigner } from '../../../hooks/utils/useEthersSigner'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useFractal } from '../../../providers/App/AppProvider'; import { AzoriusGovernance, DecentGovernance } from '../../../types'; import { formatCoin } from '../../../utils/numberFormats'; diff --git a/src/components/ui/modals/ForkProposalTemplateModal.tsx b/src/components/ui/modals/ForkProposalTemplateModal.tsx index 21ebdb0af2..9a94189acd 100644 --- a/src/components/ui/modals/ForkProposalTemplateModal.tsx +++ b/src/components/ui/modals/ForkProposalTemplateModal.tsx @@ -7,8 +7,8 @@ import { DAO_ROUTES } from '../../../constants/routes'; import useSubmitProposal from '../../../hooks/DAO/proposal/useSubmitProposal'; import { useIsSafe } from '../../../hooks/safe/useIsSafe'; import { validateAddress } from '../../../hooks/schemas/common/useValidationAddress'; -import { useEthersProvider } from '../../../hooks/utils/useEthersProvider'; -import { useEthersSigner } from '../../../hooks/utils/useEthersSigner'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useFractal } from '../../../providers/App/AppProvider'; import { disconnectedChain } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { ProposalTemplate } from '../../../types/createProposalTemplate'; diff --git a/src/components/ui/modals/UnwrapToken.tsx b/src/components/ui/modals/UnwrapToken.tsx index 72d5c562f4..f88a5db66f 100644 --- a/src/components/ui/modals/UnwrapToken.tsx +++ b/src/components/ui/modals/UnwrapToken.tsx @@ -9,7 +9,7 @@ import { useAccount } from 'wagmi'; import * as Yup from 'yup'; import { useERC20LinearToken } from '../../../hooks/DAO/loaders/governance/useERC20LinearToken'; import useApproval from '../../../hooks/utils/useApproval'; -import { useEthersSigner } from '../../../hooks/utils/useEthersSigner'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useFormHelpers } from '../../../hooks/utils/useFormHelpers'; import { useTransaction } from '../../../hooks/utils/useTransaction'; import { useFractal } from '../../../providers/App/AppProvider'; diff --git a/src/components/ui/modals/WrapToken.tsx b/src/components/ui/modals/WrapToken.tsx index 52320b578b..ed502c7a3e 100644 --- a/src/components/ui/modals/WrapToken.tsx +++ b/src/components/ui/modals/WrapToken.tsx @@ -10,7 +10,7 @@ import * as Yup from 'yup'; import { logError } from '../../../helpers/errorLogging'; import { useERC20LinearToken } from '../../../hooks/DAO/loaders/governance/useERC20LinearToken'; import useApproval from '../../../hooks/utils/useApproval'; -import { useEthersSigner } from '../../../hooks/utils/useEthersSigner'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useFormHelpers } from '../../../hooks/utils/useFormHelpers'; import { useTransaction } from '../../../hooks/utils/useTransaction'; import { useFractal } from '../../../providers/App/AppProvider'; diff --git a/src/components/ui/proposal/useProposalCountdown.tsx b/src/components/ui/proposal/useProposalCountdown.tsx index 32759d4227..a8d6ae538b 100644 --- a/src/components/ui/proposal/useProposalCountdown.tsx +++ b/src/components/ui/proposal/useProposalCountdown.tsx @@ -5,7 +5,7 @@ import { logError } from '../../../helpers/errorLogging'; import useSnapshotProposal from '../../../hooks/DAO/loaders/snapshot/useSnapshotProposal'; import { useDAOProposals } from '../../../hooks/DAO/loaders/useProposals'; import useUpdateProposalState from '../../../hooks/DAO/proposal/useUpdateProposalState'; -import { useEthersProvider } from '../../../hooks/utils/useEthersProvider'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { useFractal } from '../../../providers/App/AppProvider'; import { AzoriusGovernance, diff --git a/src/graphql/utils/index.ts b/src/graphql/utils/index.ts index 06aba49426..f0df4aa7e6 100644 --- a/src/graphql/utils/index.ts +++ b/src/graphql/utils/index.ts @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { useEthersProvider } from '../../hooks/utils/useEthersProvider'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; import { supportedChains } from '../../providers/NetworkConfig/NetworkConfigProvider'; export const useSubgraphChainName = () => { diff --git a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts index 3f8c43390a..df4c52ca4f 100644 --- a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts +++ b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts @@ -12,11 +12,11 @@ import { useCallback, useEffect, useMemo } from 'react'; import { getEventRPC } from '../../../../helpers'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; +import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; import { ProposalMetadata, MetaTransaction, VotingStrategyType } from '../../../../types'; import { AzoriusProposal, ProposalData } from '../../../../types/daoProposal'; import { mapProposalCreatedEventToProposal, getProposalVotesSummary } from '../../../../utils'; import { useAsyncRetry } from '../../../utils/useAsyncRetry'; -import { useEthersProvider } from '../../../utils/useEthersProvider'; import { useSafeDecoder } from '../../../utils/useSafeDecoder'; export const useAzoriusProposals = () => { @@ -51,7 +51,8 @@ export const useAzoriusProposals = () => { if ( !azoriusContract || !(ozLinearVotingContract || erc721LinearVotingContract) || - !strategyType + !strategyType || + !provider ) { return []; } @@ -108,7 +109,8 @@ export const useAzoriusProposals = () => { if ( !azoriusContract || !(ozLinearVotingContract || erc721LinearVotingContract) || - !strategyType + !strategyType || + !provider ) { return; } diff --git a/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts b/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts index 4909d9e6df..28c8db99a2 100644 --- a/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts +++ b/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts @@ -8,9 +8,9 @@ import { useCallback, useEffect } from 'react'; import { getEventRPC } from '../../../../helpers'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; +import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; import { VotingStrategyType } from '../../../../types'; import { blocksToSeconds } from '../../../../utils/contract'; -import { useEthersProvider } from '../../../utils/useEthersProvider'; import { useTimeHelpers } from '../../../utils/useTimeHelpers'; export const useERC20LinearStrategy = () => { diff --git a/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts b/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts index aac113ee03..0ba0a1a0fc 100644 --- a/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts +++ b/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts @@ -10,9 +10,9 @@ import { useCallback, useEffect } from 'react'; import { getEventRPC } from '../../../../helpers'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; +import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; import { VotingStrategyType } from '../../../../types'; import { blocksToSeconds } from '../../../../utils/contract'; -import { useEthersProvider } from '../../../utils/useEthersProvider'; import { useTimeHelpers } from '../../../utils/useTimeHelpers'; export const useERC721LinearStrategy = () => { diff --git a/src/hooks/DAO/loaders/useFractalFreeze.ts b/src/hooks/DAO/loaders/useFractalFreeze.ts index 4f8bdff7a9..c8c39f4489 100644 --- a/src/hooks/DAO/loaders/useFractalFreeze.ts +++ b/src/hooks/DAO/loaders/useFractalFreeze.ts @@ -15,9 +15,9 @@ import { } from '../../../helpers/freezePeriodHelpers'; import { useFractal } from '../../../providers/App/AppProvider'; import { FractalGuardAction } from '../../../providers/App/guard/action'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { ContractConnection, FractalGuardContracts, FreezeVotingType } from '../../../types'; import { blocksToSeconds, getTimeStamp } from '../../../utils/contract'; -import { useEthersProvider } from '../../utils/useEthersProvider'; import useUserERC721VotingTokens from '../proposal/useUserERC721VotingTokens'; import { FreezeGuard } from './../../../types/fractal'; diff --git a/src/hooks/DAO/loaders/useFractalGuardContracts.ts b/src/hooks/DAO/loaders/useFractalGuardContracts.ts index bf4281ab94..b01033aef6 100644 --- a/src/hooks/DAO/loaders/useFractalGuardContracts.ts +++ b/src/hooks/DAO/loaders/useFractalGuardContracts.ts @@ -3,6 +3,7 @@ import { constants } from 'ethers'; import { useCallback, useEffect, useRef } from 'react'; import { useFractal } from '../../../providers/App/AppProvider'; import { GuardContractAction } from '../../../providers/App/guardContracts/action'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { ContractConnection, SafeInfoResponseWithGuard, @@ -27,9 +28,8 @@ export const useFractalGuardContracts = ({ loadOnMount = true }: { loadOnMount?: action, } = useFractal(); - const { - network: { chainId }, - } = useEthersProvider(); + const provider = useEthersProvider(); + const chainId = provider?.network.chainId; const { getZodiacModuleProxyMasterCopyData } = useMasterCopy(); @@ -122,6 +122,10 @@ export const useFractalGuardContracts = ({ loadOnMount = true }: { loadOnMount?: }, [action, daoAddress, safe, fractalModules, loadFractalGuardContracts]); useEffect(() => { + if (chainId === undefined) { + return; + } + if (daoAddress && chainId + daoAddress !== loadKey.current && loadOnMount && isModulesLoaded) { loadKey.current = chainId + daoAddress; setGuardContracts(); diff --git a/src/hooks/DAO/loaders/useFractalNode.ts b/src/hooks/DAO/loaders/useFractalNode.ts index 5bd8cd4b9c..71b47e37ee 100644 --- a/src/hooks/DAO/loaders/useFractalNode.ts +++ b/src/hooks/DAO/loaders/useFractalNode.ts @@ -79,7 +79,7 @@ export const useFractalNode = ({ daoAddress }: { daoAddress?: string }) => { }); const fetchSafeInfo = useCallback(async () => { - if (daoAddress) { + if (daoAddress && safeAPI) { const safeInfo = await safeAPI.getSafeInfo(utils.getAddress(daoAddress)); return safeInfo; } diff --git a/src/hooks/DAO/loaders/useFractalTreasury.ts b/src/hooks/DAO/loaders/useFractalTreasury.ts index 92c56f66aa..2ddc1e3f99 100644 --- a/src/hooks/DAO/loaders/useFractalTreasury.ts +++ b/src/hooks/DAO/loaders/useFractalTreasury.ts @@ -4,9 +4,9 @@ import { logError } from '../../../helpers/errorLogging'; import { useFractal } from '../../../providers/App/AppProvider'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; import { TreasuryAction } from '../../../providers/App/treasury/action'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { buildSafeApiUrl } from '../../../utils'; -import { useEthersProvider } from '../../utils/useEthersProvider'; import { useUpdateTimer } from './../../utils/useUpdateTimer'; export const useFractalTreasury = () => { diff --git a/src/hooks/DAO/loaders/useGovernanceContracts.ts b/src/hooks/DAO/loaders/useGovernanceContracts.ts index cc8999e124..3e1e8be23e 100644 --- a/src/hooks/DAO/loaders/useGovernanceContracts.ts +++ b/src/hooks/DAO/loaders/useGovernanceContracts.ts @@ -10,6 +10,7 @@ import { useCallback, useEffect, useRef } from 'react'; import { LockRelease, LockRelease__factory } from '../../../assets/typechain-types/dcnt'; import { useFractal } from '../../../providers/App/AppProvider'; import { GovernanceContractAction } from '../../../providers/App/governanceContracts/action'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { ContractConnection } from '../../../types'; import { getAzoriusModuleFromModules } from '../../../utils'; import { useEthersProvider } from '../../utils/useEthersProvider'; @@ -108,7 +109,7 @@ export const useGovernanceContracts = () => { return undefined; }); - if (lockedToken) { + if (lockedToken && provider) { lockReleaseContract = { asSigner: LockRelease__factory.connect(govTokenAddress, signerOrProvider), asProvider: LockRelease__factory.connect(govTokenAddress, provider), diff --git a/src/hooks/DAO/proposal/useCastVote.ts b/src/hooks/DAO/proposal/useCastVote.ts index bd2090960c..af853c3255 100644 --- a/src/hooks/DAO/proposal/useCastVote.ts +++ b/src/hooks/DAO/proposal/useCastVote.ts @@ -6,6 +6,7 @@ import { toast } from 'react-toastify'; import { useVoteContext } from '../../../components/Proposals/ProposalVotes/context/VoteContext'; import { logError } from '../../../helpers/errorLogging'; import { useFractal } from '../../../providers/App/AppProvider'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { AzoriusGovernance, GovernanceType, @@ -13,7 +14,6 @@ import { ExtendedSnapshotProposal, } from '../../../types'; import encryptWithShutter from '../../../utils/shutter'; -import { useEthersSigner } from '../../utils/useEthersSigner'; import { useTransaction } from '../../utils/useTransaction'; import useSnapshotSpaceName from '../loaders/snapshot/useSnapshotSpaceName'; import useUserERC721VotingTokens from './useUserERC721VotingTokens'; diff --git a/src/hooks/DAO/proposal/usePrepareProposal.ts b/src/hooks/DAO/proposal/usePrepareProposal.ts index 245d81062c..2f660d31c5 100644 --- a/src/hooks/DAO/proposal/usePrepareProposal.ts +++ b/src/hooks/DAO/proposal/usePrepareProposal.ts @@ -1,8 +1,8 @@ import { useCallback } from 'react'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { CreateProposalForm } from '../../../types'; import { encodeFunction } from '../../../utils/crypto'; import { couldBeENS } from '../../../utils/url'; -import { useEthersSigner } from '../../utils/useEthersSigner'; export function usePrepareProposal() { const signer = useEthersSigner(); diff --git a/src/hooks/DAO/proposal/useSubmitProposal.ts b/src/hooks/DAO/proposal/useSubmitProposal.ts index cdc9c067b3..452f5c251b 100644 --- a/src/hooks/DAO/proposal/useSubmitProposal.ts +++ b/src/hooks/DAO/proposal/useSubmitProposal.ts @@ -12,6 +12,8 @@ import { logError } from '../../../helpers/errorLogging'; import { useFractal } from '../../../providers/App/AppProvider'; import useIPFSClient from '../../../providers/App/hooks/useIPFSClient'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { MetaTransaction, @@ -21,8 +23,6 @@ import { } from '../../../types'; import { buildSafeApiUrl, getAzoriusModuleFromModules } from '../../../utils'; import { getAverageBlockTime } from '../../../utils/contract'; -import { useEthersProvider } from '../../utils/useEthersProvider'; -import { useEthersSigner } from '../../utils/useEthersSigner'; import useSignerOrProvider from '../../utils/useSignerOrProvider'; import { useFractalModules } from '../loaders/useFractalModules'; import { useDAOProposals } from '../loaders/useProposals'; diff --git a/src/hooks/DAO/useClawBack.ts b/src/hooks/DAO/useClawBack.ts index 312dc8f388..46177d04af 100644 --- a/src/hooks/DAO/useClawBack.ts +++ b/src/hooks/DAO/useClawBack.ts @@ -3,8 +3,8 @@ import { ethers, utils } from 'ethers'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useSafeAPI } from '../../providers/App/hooks/useSafeAPI'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; import { FractalModuleType, FractalNode } from '../../types'; -import { useEthersProvider } from '../utils/useEthersProvider'; import useSubmitProposal from './proposal/useSubmitProposal'; interface IUseClawBack { diff --git a/src/hooks/DAO/useDAOName.ts b/src/hooks/DAO/useDAOName.ts index 8b22092a6e..816821dfae 100644 --- a/src/hooks/DAO/useDAOName.ts +++ b/src/hooks/DAO/useDAOName.ts @@ -3,10 +3,10 @@ import { useCallback, useEffect, useState } from 'react'; import { Address, useEnsName } from 'wagmi'; import { getEventRPC } from '../../helpers'; import { useFractal } from '../../providers/App/AppProvider'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; import { CacheKeys } from '../utils/cache/cacheDefaults'; import { useLocalStorage } from '../utils/cache/useLocalStorage'; import { createAccountSubstring } from '../utils/useDisplayName'; -import { useEthersProvider } from '../utils/useEthersProvider'; /** * Gets the 'display name' for a Fractal DAO, in the following order of preference: diff --git a/src/hooks/safe/useSafeContracts.ts b/src/hooks/safe/useSafeContracts.ts index affd66fa51..b280c0e5dd 100644 --- a/src/hooks/safe/useSafeContracts.ts +++ b/src/hooks/safe/useSafeContracts.ts @@ -19,8 +19,8 @@ import { import { useMemo } from 'react'; import { MultiSend__factory } from '../../assets/typechain-types/usul'; import { GnosisSafeL2__factory } from '../../assets/typechain-types/usul/factories/@gnosis.pm/safe-contracts/contracts'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider'; -import { useEthersProvider } from '../utils/useEthersProvider'; import useSignerOrProvider from '../utils/useSignerOrProvider'; export default function useSafeContracts() { diff --git a/src/hooks/schemas/DAOCreate/useDAOCreateTests.ts b/src/hooks/schemas/DAOCreate/useDAOCreateTests.ts index e5e3debbd4..3313d4c95c 100644 --- a/src/hooks/schemas/DAOCreate/useDAOCreateTests.ts +++ b/src/hooks/schemas/DAOCreate/useDAOCreateTests.ts @@ -4,9 +4,9 @@ import { useTranslation } from 'react-i18next'; import { erc20ABI } from 'wagmi'; import { AnyObject } from 'yup'; import { logError } from '../../../helpers/errorLogging'; +import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { AddressValidationMap, CreatorFormState, TokenAllocation } from '../../../types'; import { couldBeENS } from '../../../utils/url'; -import { useEthersProvider } from '../../utils/useEthersProvider'; import useSignerOrProvider from '../../utils/useSignerOrProvider'; import { validateAddress } from '../common/useValidationAddress'; diff --git a/src/hooks/schemas/common/useValidationAddress.tsx b/src/hooks/schemas/common/useValidationAddress.tsx index 66438fcaba..8a788260f6 100644 --- a/src/hooks/schemas/common/useValidationAddress.tsx +++ b/src/hooks/schemas/common/useValidationAddress.tsx @@ -3,10 +3,10 @@ import { useMemo, useRef, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { AnyObject } from 'yup'; import { useFractal } from '../../../providers/App/AppProvider'; +import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { AddressValidationMap, ERC721TokenConfig } from '../../../types'; import { Providers } from '../../../types/network'; import { couldBeENS } from '../../../utils/url'; -import { useEthersSigner } from '../../utils/useEthersSigner'; import useSignerOrProvider from '../../utils/useSignerOrProvider'; export function validateENSName({ ensName }: { ensName: string }) { @@ -33,11 +33,11 @@ export async function validateAddress({ address, checkENS = true, }: { - signerOrProvider: Signer | Providers; + signerOrProvider?: Signer | Providers; address: string; checkENS?: boolean; }) { - if (couldBeENS(address) && checkENS) { + if (couldBeENS(address) && checkENS && signerOrProvider) { const resolvedAddress = await signerOrProvider.resolveName(address).catch(); if (resolvedAddress) { return { diff --git a/src/hooks/stake/lido/useLidoStaking.ts b/src/hooks/stake/lido/useLidoStaking.ts index 5b853f4c82..8fef66ded3 100644 --- a/src/hooks/stake/lido/useLidoStaking.ts +++ b/src/hooks/stake/lido/useLidoStaking.ts @@ -21,7 +21,7 @@ export default function useLidoStaking() { const handleStake = useCallback( async (value: BigNumber) => { - if (!lido || !daoAddress) { + if (!lido || !daoAddress || !signerOrProvider) { // Means it is not supported on current network return; } @@ -51,7 +51,7 @@ export default function useLidoStaking() { const handleUnstake = useCallback( async (value: string) => { - if (!lido || !daoAddress) { + if (!lido || !daoAddress || !signerOrProvider) { // Means it is not supported on current network return; } @@ -96,7 +96,7 @@ export default function useLidoStaking() { const handleClaimUnstakedETH = useCallback( async (nftId: BigNumber) => { - if (!lido || !daoAddress) { + if (!lido || !daoAddress || !signerOrProvider) { // Means it is not supported on current network return; } diff --git a/src/hooks/utils/useAddress.ts b/src/hooks/utils/useAddress.ts index 90b95fa9fa..6eab22627d 100644 --- a/src/hooks/utils/useAddress.ts +++ b/src/hooks/utils/useAddress.ts @@ -2,10 +2,10 @@ import { ethers } from 'ethers'; import { useEffect, useState } from 'react'; import { useNetwork } from 'wagmi'; import { supportsENS } from '../../helpers'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; import { couldBeENS } from '../../utils/url'; import { CacheKeys, CacheExpiry } from './cache/cacheDefaults'; import { useLocalStorage } from './cache/useLocalStorage'; -import { useEthersProvider } from './useEthersProvider'; const useAddress = (addressInput: string | undefined) => { const provider = useEthersProvider(); diff --git a/src/hooks/utils/useAvatar.ts b/src/hooks/utils/useAvatar.ts index 2275e6dffd..54d3245f58 100644 --- a/src/hooks/utils/useAvatar.ts +++ b/src/hooks/utils/useAvatar.ts @@ -1,5 +1,5 @@ import { useEnsAvatar } from 'wagmi'; -import { useEthersProvider } from './useEthersProvider'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; const useAvatar = (account: string | null) => { const provider = useEthersProvider(); diff --git a/src/hooks/utils/useBlockTimestamp.ts b/src/hooks/utils/useBlockTimestamp.ts index 47b07b35a7..2e57cb02e6 100644 --- a/src/hooks/utils/useBlockTimestamp.ts +++ b/src/hooks/utils/useBlockTimestamp.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { logError } from '../../helpers/errorLogging'; -import { useEthersProvider } from './useEthersProvider'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; const useBlockTimestamp = (blockNumber?: number) => { const [timestamp, setTimestamp] = useState(Math.floor(Date.now() / 1000)); diff --git a/src/hooks/utils/useCurrentBlockNumber.ts b/src/hooks/utils/useCurrentBlockNumber.ts index f2c9cee9f1..a8bed53dff 100644 --- a/src/hooks/utils/useCurrentBlockNumber.ts +++ b/src/hooks/utils/useCurrentBlockNumber.ts @@ -1,5 +1,5 @@ import { useEffect, useState, useCallback } from 'react'; -import { useEthersProvider } from './useEthersProvider'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; const useCurrentBlockNumber = () => { const [currentBlockNumber, setCurrentBlockNumber] = useState(); diff --git a/src/hooks/utils/useDisplayName.ts b/src/hooks/utils/useDisplayName.ts index 325fab1043..68e40c1385 100644 --- a/src/hooks/utils/useDisplayName.ts +++ b/src/hooks/utils/useDisplayName.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { Address, useEnsName } from 'wagmi'; -import { useEthersProvider } from './useEthersProvider'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; export const createAccountSubstring = (account: string) => { return `${account.substring(0, 6)}...${account.slice(-4)}`; diff --git a/src/hooks/utils/useEthersProvider.ts b/src/hooks/utils/useEthersProvider.ts deleted file mode 100644 index c041144bbf..0000000000 --- a/src/hooks/utils/useEthersProvider.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { providers } from 'ethers'; -import { useMemo } from 'react'; -import type { Transport } from 'viem'; -import { usePublicClient } from 'wagmi'; - -/** Hook to convert a viem Client to an ethers.js Provider. */ -export function useEthersProvider() { - const client = usePublicClient(); - const provider = useMemo(() => { - const { chain, transport } = client; - const network = { - chainId: chain.id, - name: chain.name, - ensAddress: chain.contracts?.ensRegistry?.address, - }; - if (transport.type === 'fallback') { - return new providers.FallbackProvider( - (transport.transports as ReturnType[]).map( - ({ value }) => new providers.JsonRpcProvider(value?.url, network) - ) - ); - } - return new providers.JsonRpcProvider(transport.url, network); - }, [client]); - return provider; -} diff --git a/src/hooks/utils/useEthersSigner.ts b/src/hooks/utils/useEthersSigner.ts deleted file mode 100644 index 278bca5ba1..0000000000 --- a/src/hooks/utils/useEthersSigner.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { providers } from 'ethers'; -import { useMemo } from 'react'; -import { useWalletClient } from 'wagmi'; - -/** Hook to convert a Viem Client to an ethers.js Signer. */ -export function useEthersSigner() { - const { data: client } = useWalletClient(); - const signer = useMemo(() => { - if (client) { - const { account, chain, transport } = client; - const network = { - chainId: chain.id, - name: chain.name, - ensAddress: chain.contracts?.ensRegistry?.address, - }; - const provider = new providers.Web3Provider(transport, network); - return provider.getSigner(account.address); - } - }, [client]); - return signer; -} diff --git a/src/hooks/utils/useSafeTransactions.ts b/src/hooks/utils/useSafeTransactions.ts index 657f9b663e..b7dea61012 100644 --- a/src/hooks/utils/useSafeTransactions.ts +++ b/src/hooks/utils/useSafeTransactions.ts @@ -9,6 +9,7 @@ import { constants, BigNumber, ethers } from 'ethers'; import { useCallback } from 'react'; import { isApproved, isRejected } from '../../helpers/activity'; import { useFractal } from '../../providers/App/AppProvider'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider'; import { AssetTotals, @@ -20,7 +21,6 @@ import { import { formatWeiToValue, isModuleTx, isMultiSigTx, parseDecodedData } from '../../utils'; import { getAverageBlockTime } from '../../utils/contract'; import { getTxTimelockedTimestamp } from '../../utils/guard'; -import { useEthersProvider } from './useEthersProvider'; import { useSafeDecoder } from './useSafeDecoder'; type FreezeGuardData = { diff --git a/src/hooks/utils/useSignerOrProvider.ts b/src/hooks/utils/useSignerOrProvider.ts index f49f868622..b180b73e12 100644 --- a/src/hooks/utils/useSignerOrProvider.ts +++ b/src/hooks/utils/useSignerOrProvider.ts @@ -1,6 +1,6 @@ import { useMemo } from 'react'; -import { useEthersProvider } from './useEthersProvider'; -import { useEthersSigner } from './useEthersSigner'; +import { useEthersProvider } from '../../providers/Ethers/hooks/useEthersProvider'; +import { useEthersSigner } from '../../providers/Ethers/hooks/useEthersSigner'; export default function useSignerOrProvider() { const signer = useEthersSigner(); diff --git a/src/providers/App/hooks/useSafeAPI.ts b/src/providers/App/hooks/useSafeAPI.ts index cdcdf47f8d..f15119a941 100644 --- a/src/providers/App/hooks/useSafeAPI.ts +++ b/src/providers/App/hooks/useSafeAPI.ts @@ -229,7 +229,10 @@ export function useSafeAPI() { const { safeBaseURL, chainId } = useNetworkConfig(); const signerOrProvider = useSignerOrProvider(); - const safeAPI: SafeServiceClient = useMemo(() => { + const safeAPI: SafeServiceClient | undefined = useMemo(() => { + if (!signerOrProvider) { + return undefined; + } const ethAdapter = new EthersAdapter({ ethers, signerOrProvider, diff --git a/src/providers/App/useReadOnlyValues.ts b/src/providers/App/useReadOnlyValues.ts index f965d07189..1defb10925 100644 --- a/src/providers/App/useReadOnlyValues.ts +++ b/src/providers/App/useReadOnlyValues.ts @@ -39,7 +39,7 @@ export const useReadOnlyValues = ({ node, governance }: Fractal, _account?: stri const tokenWeight = azoriusGovernance.votesToken?.votingWeight || BigNumber.from(0); return lockedTokenWeight || tokenWeight; case GovernanceType.AZORIUS_ERC721: - if (!_account || !azoriusGovernance.erc721Tokens) { + if (!_account || !azoriusGovernance.erc721Tokens || !signerOrProvider) { return BigNumber.from(0); } const userVotingWeight = ( diff --git a/src/providers/Ethers/hooks/useEthersProvider.ts b/src/providers/Ethers/hooks/useEthersProvider.ts new file mode 100644 index 0000000000..8cf195e078 --- /dev/null +++ b/src/providers/Ethers/hooks/useEthersProvider.ts @@ -0,0 +1,7 @@ +import { useContext } from 'react'; +import { EthersContext } from '..'; + +export function useEthersProvider() { + const { provider } = useContext(EthersContext); + return provider; +} diff --git a/src/providers/Ethers/hooks/useEthersSigner.ts b/src/providers/Ethers/hooks/useEthersSigner.ts new file mode 100644 index 0000000000..2d2b395d6d --- /dev/null +++ b/src/providers/Ethers/hooks/useEthersSigner.ts @@ -0,0 +1,7 @@ +import { useContext } from 'react'; +import { EthersContext } from '..'; + +export function useEthersSigner() { + const { signer } = useContext(EthersContext); + return signer; +} diff --git a/src/providers/Ethers/index.tsx b/src/providers/Ethers/index.tsx new file mode 100644 index 0000000000..0d4f5cf1f2 --- /dev/null +++ b/src/providers/Ethers/index.tsx @@ -0,0 +1,57 @@ +'use client'; + +import { Signer, providers } from 'ethers'; +import { ReactNode, createContext, useMemo } from 'react'; +import type { Transport } from 'viem'; +import { usePublicClient, useWalletClient } from 'wagmi'; + +interface IEthersContext { + provider?: providers.JsonRpcProvider | providers.FallbackProvider; + signer?: Signer; +} + +export const EthersContext = createContext({ + provider: undefined, + signer: undefined, +}); + +/** + * Provider to convert a viem Clients to an ethers.js Provider and Signer + * and supply "singleton" instances of it to underlying components. + */ +export default function EthersContextProvider({ children }: { children: ReactNode }) { + const publicClient = usePublicClient(); + const { data: walletClient } = useWalletClient(); + + const provider = useMemo(() => { + const { chain, transport } = publicClient; + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + }; + if (transport.type === 'fallback') { + return new providers.FallbackProvider( + (transport.transports as ReturnType[]).map( + ({ value }) => new providers.JsonRpcProvider(value?.url, network) + ) + ); + } + return new providers.JsonRpcProvider(transport.url, network); + }, [publicClient]); + + const signer = useMemo(() => { + if (walletClient) { + const { account, chain, transport } = walletClient; + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + }; + const publicProvider = new providers.Web3Provider(transport, network); + return publicProvider.getSigner(account.address); + } + }, [walletClient]); + + return {children}; +} diff --git a/src/providers/Providers.tsx b/src/providers/Providers.tsx index 2968441281..def0190b26 100644 --- a/src/providers/Providers.tsx +++ b/src/providers/Providers.tsx @@ -12,6 +12,7 @@ import { ErrorFallback } from '../components/ui/utils/ErrorFallback'; import graphQLClient from '../graphql'; import { FractalErrorBoundary, initErrorLogging } from '../helpers/errorLogging'; import { AppProvider } from './App/AppProvider'; +import EthersContextProvider from './Ethers'; import { NetworkConfigProvider } from './NetworkConfig/NetworkConfigProvider'; import { wagmiConfig, chains } from './NetworkConfig/rainbow-kit.config'; import '@fontsource/ibm-plex-mono'; @@ -21,6 +22,7 @@ export default function Providers({ children }: { children: ReactNode }) { useEffect(() => { initErrorLogging(); }, []); + return ( - - - - {children} - - + + + + + {children} + + +