From f0c3317e66b9eada866ee86f1a74160dc8ec6264 Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Sun, 5 May 2024 15:01:16 -0400 Subject: [PATCH] Remove votesTokenMasterCopyContract from useSafeContracts, fix downstream typescript issues --- src/components/Proposals/ProposalSummary.tsx | 26 +++- .../DAO/loaders/governance/useERC20Claim.ts | 28 +++- .../loaders/governance/useERC20LinearToken.ts | 139 +++++++++++------- src/hooks/DAO/loaders/useFractalFreeze.ts | 37 +++-- src/hooks/safe/useSafeContracts.ts | 9 -- 5 files changed, 146 insertions(+), 93 deletions(-) diff --git a/src/components/Proposals/ProposalSummary.tsx b/src/components/Proposals/ProposalSummary.tsx index 1c0c5f307a..79d87fc614 100644 --- a/src/components/Proposals/ProposalSummary.tsx +++ b/src/components/Proposals/ProposalSummary.tsx @@ -4,8 +4,10 @@ import { format } from 'date-fns'; import { formatInTimeZone } from 'date-fns-tz'; import { useMemo, useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; +import { getAddress, getContract } from 'viem'; +import { usePublicClient } from 'wagmi'; +import VotesERC20Abi from '../../assets/abi/VotesERC20'; import { BACKGROUND_SEMI_TRANSPARENT } from '../../constants/common'; -import useSafeContracts from '../../hooks/safe/useSafeContracts'; import useBlockTimestamp from '../../hooks/utils/useBlockTimestamp'; import { useFractal } from '../../providers/App/AppProvider'; import { AzoriusGovernance, AzoriusProposal, GovernanceType } from '../../types'; @@ -36,7 +38,7 @@ export default function ProposalSummary({ user: { votingWeight, address }, }, } = useFractal(); - const baseContracts = useSafeContracts(); + const azoriusGovernance = governance as AzoriusGovernance; const { votesToken, type, erc721Tokens, votingStrategy } = azoriusGovernance; const { t } = useTranslation(['proposal', 'common', 'navigation']); @@ -59,13 +61,21 @@ export default function ProposalSummary({ const toggleShowVotingPower = () => setShowVotingPower(prevState => !prevState); + const publicClient = usePublicClient(); + useEffect(() => { async function loadProposalVotingWeight() { - if (address && baseContracts && votesToken) { - const tokenContract = baseContracts.votesTokenMasterCopyContract.asProvider.attach( - votesToken.address, - ); - const pastVotingWeight = (await tokenContract.getPastVotes(address, startBlock)).toBigInt(); + if (address && votesToken && publicClient) { + const tokenContract = getContract({ + abi: VotesERC20Abi, + address: votesToken.address, + client: publicClient, + }); + + const pastVotingWeight = await tokenContract.read.getPastVotes([ + getAddress(address), + startBlock, + ]); setProposalsERC20VotingWeight( (pastVotingWeight / votesTokenDecimalsDenominator).toString(), ); @@ -73,7 +83,7 @@ export default function ProposalSummary({ } loadProposalVotingWeight(); - }, [address, startBlock, votesTokenDecimalsDenominator, baseContracts, votesToken]); + }, [address, publicClient, startBlock, votesToken, votesTokenDecimalsDenominator]); const isERC20 = type === GovernanceType.AZORIUS_ERC20; const isERC721 = type === GovernanceType.AZORIUS_ERC721; diff --git a/src/hooks/DAO/loaders/governance/useERC20Claim.ts b/src/hooks/DAO/loaders/governance/useERC20Claim.ts index 16032bcb62..0e16c201ec 100644 --- a/src/hooks/DAO/loaders/governance/useERC20Claim.ts +++ b/src/hooks/DAO/loaders/governance/useERC20Claim.ts @@ -1,4 +1,7 @@ import { useEffect, useCallback, useRef } from 'react'; +import { getContract, getAddress } from 'viem'; +import { usePublicClient } from 'wagmi'; +import VotesERC20Abi from '../../../../assets/abi/VotesERC20'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; import useSafeContracts from '../../../safe/useSafeContracts'; @@ -14,22 +17,30 @@ export function useERC20Claim() { action, } = useFractal(); const baseContracts = useSafeContracts(); + const publicClient = usePublicClient(); + const loadTokenClaimContract = useCallback(async () => { - if (!baseContracts || !votesTokenContractAddress) { + if (!baseContracts || !votesTokenContractAddress || !publicClient) { return; } const { claimingMasterCopyContract } = baseContracts; - const votesTokenContract = - baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); + const votesTokenContract = getContract({ + abi: VotesERC20Abi, + address: getAddress(votesTokenContractAddress), + client: publicClient, + }); + + // TODO here be dark programming... - const approvalFilter = votesTokenContract.filters.Approval(); - const approvals = await votesTokenContract.queryFilter(approvalFilter); - if (!approvals.length) { + const approvals = await votesTokenContract.getEvents.Approval(); + + if (approvals.length === 0 || !approvals[0].args.spender) { return; } + const possibleTokenClaimContract = claimingMasterCopyContract.asProvider.attach( - approvals[0].args[1], + getAddress(approvals[0].args.spender), ); const tokenClaimFilter = possibleTokenClaimContract.filters.ERC20ClaimCreated(); const tokenClaimArray = await possibleTokenClaimContract @@ -44,7 +55,8 @@ export function useERC20Claim() { type: FractalGovernanceAction.SET_CLAIMING_CONTRACT, payload: possibleTokenClaimContract, }); - }, [baseContracts, votesTokenContractAddress, action]); + }, [action, baseContracts, publicClient, votesTokenContractAddress]); + const loadKey = useRef(); useEffect(() => { diff --git a/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts b/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts index 735c0acca1..91e5b58c45 100644 --- a/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts +++ b/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts @@ -1,8 +1,9 @@ -import { useCallback, useEffect, useRef } from 'react'; -import { getAddress } from 'viem'; +import { useCallback, useEffect, useMemo, useRef } from 'react'; +import { getAddress, getContract } from 'viem'; +import { usePublicClient } from 'wagmi'; +import VotesERC20Abi from '../../../../assets/abi/VotesERC20'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; -import useSafeContracts from '../../../safe/useSafeContracts'; export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) => { const isTokenLoaded = useRef(false); @@ -14,65 +15,84 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) = readOnly: { user }, } = useFractal(); const account = user.address; - const baseContracts = useSafeContracts(); + const publicClient = usePublicClient(); + + const tokenContract = useMemo(() => { + if (!votesTokenContractAddress || !publicClient) { + return; + } + + return getContract({ + abi: VotesERC20Abi, + address: getAddress(votesTokenContractAddress), + client: publicClient, + }); + }, [publicClient, votesTokenContractAddress]); + + const underlyingTokenContract = useMemo(() => { + if (!underlyingTokenAddress || !publicClient) { + return; + } + + return getContract({ + abi: VotesERC20Abi, + address: getAddress(underlyingTokenAddress), + client: publicClient, + }); + }, [publicClient, underlyingTokenAddress]); const loadERC20Token = useCallback(async () => { - if (!votesTokenContractAddress || !baseContracts) { + if (!tokenContract) { return; } - const tokenContract = - baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); + const [tokenName, tokenSymbol, tokenDecimals, totalSupply] = await Promise.all([ - tokenContract.name(), - tokenContract.symbol(), - tokenContract.decimals(), - (await tokenContract.totalSupply()).toBigInt(), + tokenContract.read.name(), + tokenContract.read.symbol(), + tokenContract.read.decimals(), + await tokenContract.read.totalSupply(), ]); const tokenData = { name: tokenName, symbol: tokenSymbol, decimals: tokenDecimals, - address: getAddress(votesTokenContractAddress), + address: tokenContract.address, totalSupply, }; isTokenLoaded.current = true; action.dispatch({ type: FractalGovernanceAction.SET_TOKEN_DATA, payload: tokenData }); - }, [votesTokenContractAddress, action, baseContracts]); + }, [tokenContract, action]); const loadUnderlyingERC20Token = useCallback(async () => { - if (!underlyingTokenAddress || !baseContracts) { + if (!underlyingTokenContract) { return; } - const tokenContract = - baseContracts.votesTokenMasterCopyContract.asProvider.attach(underlyingTokenAddress); const [tokenName, tokenSymbol] = await Promise.all([ - tokenContract.name(), - tokenContract.symbol(), + underlyingTokenContract.read.name(), + underlyingTokenContract.read.symbol(), ]); const tokenData = { name: tokenName, symbol: tokenSymbol, - address: getAddress(underlyingTokenAddress), + address: underlyingTokenContract.address, }; action.dispatch({ type: FractalGovernanceAction.SET_UNDERLYING_TOKEN_DATA, payload: tokenData, }); - }, [underlyingTokenAddress, action, baseContracts]); + }, [underlyingTokenContract, action]); const loadERC20TokenAccountData = useCallback(async () => { - if (!votesTokenContractAddress || !account || !baseContracts) { + if (!account || !tokenContract) { action.dispatch({ type: FractalGovernanceAction.RESET_TOKEN_ACCOUNT_DATA }); return; } - const tokenContract = - baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); - // @todo We could probably save on some requests here. + const [tokenBalance, tokenDelegatee, tokenVotingWeight] = await Promise.all([ - (await tokenContract.balanceOf(account)).toBigInt(), - tokenContract.delegates(account), - (await tokenContract.getVotes(account)).toBigInt(), + tokenContract.read.balanceOf([getAddress(account)]), + tokenContract.read.delegates([getAddress(account)]), + tokenContract.read.getVotes([getAddress(account)]), ]); const tokenAccountData = { @@ -85,7 +105,7 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) = type: FractalGovernanceAction.SET_TOKEN_ACCOUNT_DATA, payload: tokenAccountData, }); - }, [votesTokenContractAddress, action, account, baseContracts]); + }, [account, tokenContract, action]); useEffect(() => { if ( @@ -100,49 +120,64 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) = }, [account, votesTokenContractAddress, onMount, loadERC20TokenAccountData]); useEffect(() => { - if (!votesTokenContractAddress || !onMount || !baseContracts) { + if (!onMount || !tokenContract || !account) { return; } - const tokenContract = - baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); - const delegateVotesChangedfilter = tokenContract.filters.DelegateVotesChanged(); - tokenContract.on(delegateVotesChangedfilter, loadERC20TokenAccountData); + const unwatch = tokenContract.watchEvent.DelegateVotesChanged( + { delegate: getAddress(account) }, + { onLogs: loadERC20TokenAccountData }, + ); return () => { - tokenContract.off(delegateVotesChangedfilter, loadERC20TokenAccountData); + unwatch(); }; - }, [votesTokenContractAddress, loadERC20TokenAccountData, onMount, baseContracts]); + }, [loadERC20TokenAccountData, onMount, tokenContract, account]); useEffect(() => { - if (!votesTokenContractAddress || !onMount || !baseContracts) { + if (!tokenContract || !onMount || !account) { return; } - const tokenContract = - baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); - const delegateChangedfilter = tokenContract.filters.DelegateChanged(); - tokenContract.on(delegateChangedfilter, loadERC20TokenAccountData); + + const unwatchDelegator = tokenContract.watchEvent.DelegateChanged( + { delegator: getAddress(account) }, + { onLogs: loadERC20TokenAccountData }, + ); + const unwatchFromDelegate = tokenContract.watchEvent.DelegateChanged( + { fromDelegate: getAddress(account) }, + { onLogs: loadERC20TokenAccountData }, + ); + const unwatchToDelegate = tokenContract.watchEvent.DelegateChanged( + { toDelegate: getAddress(account) }, + { onLogs: loadERC20TokenAccountData }, + ); return () => { - tokenContract.off(delegateChangedfilter, loadERC20TokenAccountData); + unwatchDelegator(); + unwatchFromDelegate(); + unwatchToDelegate(); }; - }, [votesTokenContractAddress, loadERC20TokenAccountData, onMount, baseContracts]); + }, [account, loadERC20TokenAccountData, onMount, tokenContract]); useEffect(() => { - if (!votesTokenContractAddress || !onMount || !baseContracts) { + if (!onMount || !account || !tokenContract) { return; } - const tokenContract = - baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); - const filterTo = tokenContract.filters.Transfer(null, account); - const filterFrom = tokenContract.filters.Transfer(account, null); - tokenContract.on(filterTo, loadERC20TokenAccountData); - tokenContract.on(filterFrom, loadERC20TokenAccountData); + + const unwatchTo = tokenContract.watchEvent.Transfer( + { from: getAddress(account) }, + { onLogs: loadERC20TokenAccountData }, + ); + const unwatchFrom = tokenContract.watchEvent.Transfer( + { to: getAddress(account) }, + { onLogs: loadERC20TokenAccountData }, + ); + return () => { - tokenContract.off(filterTo, loadERC20TokenAccountData); - tokenContract.off(filterFrom, loadERC20TokenAccountData); + unwatchTo(); + unwatchFrom(); }; - }, [votesTokenContractAddress, account, onMount, loadERC20TokenAccountData, baseContracts]); + }, [account, loadERC20TokenAccountData, onMount, tokenContract]); return { loadERC20Token, loadUnderlyingERC20Token, loadERC20TokenAccountData }; }; diff --git a/src/hooks/DAO/loaders/useFractalFreeze.ts b/src/hooks/DAO/loaders/useFractalFreeze.ts index 16ce49105b..06a6c255f9 100644 --- a/src/hooks/DAO/loaders/useFractalFreeze.ts +++ b/src/hooks/DAO/loaders/useFractalFreeze.ts @@ -6,8 +6,9 @@ import { import { TypedListener } from '@fractal-framework/fractal-contracts/dist/typechain-types/common'; import { FreezeVoteCastEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/ERC20FreezeVoting'; import { useCallback, useEffect, useRef } from 'react'; -import { zeroAddress } from 'viem'; -import { useAccount } from 'wagmi'; +import { getAddress, getContract, zeroAddress } from 'viem'; +import { useAccount, usePublicClient } from 'wagmi'; +import VotesERC20Abi from '../../../assets/abi/VotesERC20'; import { isWithinFreezeProposalPeriod, isWithinFreezePeriod, @@ -42,6 +43,7 @@ export const useFractalFreeze = ({ ); const provider = useEthersProvider(); + const publicClient = usePublicClient(); const loadFractalFreezeGuard = useCallback( async ({ @@ -53,7 +55,8 @@ export const useFractalFreeze = ({ !freezeVotingContractAddress || !account || !provider || - !baseContracts + !baseContracts || + !publicClient ) { return; } @@ -95,11 +98,7 @@ export const useFractalFreeze = ({ isFrozen, }; - const { - votesTokenMasterCopyContract, - safeSingletonContract, - freezeERC20VotingMasterCopyContract, - } = baseContracts; + const { safeSingletonContract, freezeERC20VotingMasterCopyContract } = baseContracts; if (freezeVotingType === FreezeVotingType.MULTISIG) { const safeContract = safeSingletonContract!.asProvider.attach( @@ -111,9 +110,13 @@ export const useFractalFreeze = ({ const freezeERC20VotingContract = freezeERC20VotingMasterCopyContract.asProvider.attach( freezeVotingContractAddress, ); - const votesTokenContract = votesTokenMasterCopyContract!.asProvider.attach( - await freezeERC20VotingContract.votesERC20(), - ); + + const votesTokenContract = getContract({ + abi: VotesERC20Abi, + address: getAddress(await freezeERC20VotingContract.votesERC20()), + client: publicClient, + }); + const currentTimestamp = await getTimeStamp('latest', provider); const isFreezeActive = isWithinFreezeProposalPeriod( @@ -129,11 +132,13 @@ export const useFractalFreeze = ({ userHasVotes = (!isFreezeActive ? // freeze not active - (await votesTokenContract.getVotes(account || '')).toBigInt() + // TODO should this be a comparison?? + await votesTokenContract.read.getVotes([account || '']) : // freeze is active - ( - await votesTokenContract.getPastVotes(account || '', freezeCreatedBlock) - ).toBigInt()) > 0n; + await votesTokenContract.read.getPastVotes([ + account || '', + BigInt(freezeCreatedBlock), + ])) > 0n; } else if (freezeVotingType === FreezeVotingType.ERC721) { const { totalVotingTokenAddresses } = await getUserERC721VotingTokens( undefined, @@ -149,7 +154,7 @@ export const useFractalFreeze = ({ isFreezeSet.current = true; return freeze; }, - [account, provider, baseContracts, getUserERC721VotingTokens, parentSafeAddress], + [account, provider, baseContracts, publicClient, getUserERC721VotingTokens, parentSafeAddress], ); const setFractalFreezeGuard = useCallback( diff --git a/src/hooks/safe/useSafeContracts.ts b/src/hooks/safe/useSafeContracts.ts index 9860758be7..439d9944ca 100644 --- a/src/hooks/safe/useSafeContracts.ts +++ b/src/hooks/safe/useSafeContracts.ts @@ -5,7 +5,6 @@ import { ERC20FreezeVoting__factory, MultisigFreezeGuard__factory, MultisigFreezeVoting__factory, - VotesERC20__factory, GnosisSafeProxyFactory__factory, ModuleProxyFactory__factory, LinearERC20Voting__factory, @@ -41,7 +40,6 @@ export default function useSafeContracts() { multisigFreezeVotingMasterCopy, erc20FreezeVotingMasterCopy, erc721FreezeVotingMasterCopy, - votesERC20MasterCopy, claimingMasterCopy, linearVotingERC721MasterCopy, keyValuePairs, @@ -127,11 +125,6 @@ export default function useSafeContracts() { asProvider: ERC721FreezeVoting__factory.connect(erc721FreezeVotingMasterCopy, provider), }; - const votesTokenMasterCopyContract = { - asSigner: VotesERC20__factory.connect(votesERC20MasterCopy, signerOrProvider), - asProvider: VotesERC20__factory.connect(votesERC20MasterCopy, provider), - }; - const claimingMasterCopyContract = { asSigner: ERC20Claim__factory.connect(claimingMasterCopy, signerOrProvider), asProvider: ERC20Claim__factory.connect(claimingMasterCopy, provider), @@ -156,7 +149,6 @@ export default function useSafeContracts() { freezeMultisigVotingMasterCopyContract, freezeERC20VotingMasterCopyContract, freezeERC721VotingMasterCopyContract, - votesTokenMasterCopyContract, claimingMasterCopyContract, linearVotingERC721MasterCopyContract, keyValuePairsContract, @@ -174,7 +166,6 @@ export default function useSafeContracts() { azoriusFreezeGuardMasterCopy, multisigFreezeVotingMasterCopy, erc20FreezeVotingMasterCopy, - votesERC20MasterCopy, claimingMasterCopy, linearVotingERC721MasterCopy, erc721FreezeVotingMasterCopy,