From d2b8b5d48c050acef3c6a7fd95bf8e29c012c2ec Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:07:52 -0400 Subject: [PATCH 01/13] Fixes Contract state being incorrectly saved into state as FallbackProvider - Saves only addresses to state --- .../DAO/loaders/useGovernanceContracts.ts | 168 +++++------------- .../App/governanceContracts/reducer.ts | 10 +- src/types/fractal.ts | 35 +++- 3 files changed, 74 insertions(+), 139 deletions(-) diff --git a/src/hooks/DAO/loaders/useGovernanceContracts.ts b/src/hooks/DAO/loaders/useGovernanceContracts.ts index 3278ce5b2c..1301a7052b 100644 --- a/src/hooks/DAO/loaders/useGovernanceContracts.ts +++ b/src/hooks/DAO/loaders/useGovernanceContracts.ts @@ -1,28 +1,21 @@ -import { - Azorius, - LinearERC20Voting, - VotesERC20, - VotesERC20Wrapper, - LinearERC721Voting, -} from '@fractal-framework/fractal-contracts'; +import { Azorius } from '@fractal-framework/fractal-contracts'; import { ethers } from 'ethers'; 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 useSafeContracts from '../../safe/useSafeContracts'; import { useMasterCopy } from '../../utils/useMasterCopy'; -import useSignerOrProvider from '../../utils/useSignerOrProvider'; export const useGovernanceContracts = () => { // tracks the current valid DAO address; helps prevent unnecessary calls const currentValidAddress = useRef(); - const { node, baseContracts, action } = useFractal(); + const { node, action } = useFractal(); + const baseContracts = useSafeContracts(); const { getZodiacModuleProxyMasterCopyData } = useMasterCopy(); const provider = useEthersProvider(); - const signerOrProvider = useSignerOrProvider(); const { fractalModules, isModulesLoaded, daoAddress } = node; @@ -31,64 +24,42 @@ export const useGovernanceContracts = () => { return; } const { - votesTokenMasterCopyContract, fractalAzoriusMasterCopyContract, votesERC20WrapperMasterCopyContract, linearVotingMasterCopyContract, - linearVotingERC721MasterCopyContract, } = baseContracts; const azoriusModule = getAzoriusModuleFromModules(fractalModules); const azoriusModuleContract = azoriusModule?.moduleContract as Azorius; if (!!azoriusModuleContract) { - const azoriusContract = { - asProvider: fractalAzoriusMasterCopyContract.asProvider.attach( - azoriusModuleContract.address, - ), - asSigner: fractalAzoriusMasterCopyContract.asSigner.attach(azoriusModuleContract.address), - }; + const azoriusContract = fractalAzoriusMasterCopyContract.asProvider.attach( + azoriusModuleContract.address, + ); - let votingContractMasterCopyAddress: string | undefined; let govTokenAddress: string | undefined; - let ozLinearVotingContract: ContractConnection | undefined; - let erc721LinearVotingContract: ContractConnection | undefined; - let tokenContract: ContractConnection | undefined; + let ozLinearVotingContractAddress: string | undefined; + let erc721LinearVotingContractAddress: string | undefined; + let votesTokenContractAddress: string | undefined; let underlyingTokenAddress: string | undefined; - let lockReleaseContract: ContractConnection | null = null; + let lockReleaseContractAddress: string | undefined; // @dev assumes the first strategy is the voting contract - const votingContractAddress = ( - await azoriusContract.asProvider.getStrategies( - '0x0000000000000000000000000000000000000001', - 0, - ) + const votingStrategyAddress = ( + await azoriusContract.getStrategies('0x0000000000000000000000000000000000000001', 0) )[1]; - let isOzLinearVoting, - isOzLinearVotingERC721 = false; - if (!votingContractMasterCopyAddress) { - const masterCopyData = await getZodiacModuleProxyMasterCopyData(votingContractAddress); - isOzLinearVoting = masterCopyData.isOzLinearVoting; - isOzLinearVotingERC721 = masterCopyData.isOzLinearVotingERC721; - } + const masterCopyData = await getZodiacModuleProxyMasterCopyData(votingStrategyAddress); + const isOzLinearVoting = masterCopyData.isOzLinearVoting; + const isOzLinearVotingERC721 = masterCopyData.isOzLinearVotingERC721; if (isOzLinearVoting) { - ozLinearVotingContract = { - asSigner: linearVotingMasterCopyContract.asSigner.attach(votingContractAddress!), - asProvider: linearVotingMasterCopyContract.asProvider.attach(votingContractAddress!), - }; - } else if (isOzLinearVotingERC721) { - erc721LinearVotingContract = { - asSigner: linearVotingERC721MasterCopyContract.asSigner.attach(votingContractAddress!), - asProvider: linearVotingERC721MasterCopyContract.asProvider.attach( - votingContractAddress!, - ), - }; - } - - if (ozLinearVotingContract) { - govTokenAddress = await ozLinearVotingContract.asProvider.governanceToken(); + ozLinearVotingContractAddress = votingStrategyAddress; + // asProvider: linearVotingMasterCopyContract.asProvider.attach(votingStrategyAddress!), + const ozLinearVotingContract = linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); + govTokenAddress = await ozLinearVotingContract.governanceToken(); const possibleERC20Wrapper = votesERC20WrapperMasterCopyContract.asProvider.attach(govTokenAddress); underlyingTokenAddress = await possibleERC20Wrapper.underlying().catch(() => { @@ -102,103 +73,46 @@ export const useGovernanceContracts = () => { provider, ) as LockRelease; - const lockedToken = await possibleLockRelease.token().catch(() => { + const lockedTokenAddress = await possibleLockRelease.token().catch(() => { // if the underlying token is not an ERC20Wrapper, this will throw an error, // so we catch it and return undefined return undefined; }); - if (lockedToken && provider && signerOrProvider) { - lockReleaseContract = { - asSigner: LockRelease__factory.connect(govTokenAddress, signerOrProvider), - asProvider: LockRelease__factory.connect(govTokenAddress, provider), - }; - tokenContract = { - asSigner: votesERC20WrapperMasterCopyContract.asSigner.attach(lockedToken), - asProvider: votesERC20WrapperMasterCopyContract.asProvider.attach(lockedToken), - }; - } else if (!underlyingTokenAddress) { - tokenContract = { - asSigner: votesTokenMasterCopyContract.asSigner.attach(govTokenAddress), - asProvider: votesTokenMasterCopyContract.asProvider.attach(govTokenAddress), - }; + if (lockedTokenAddress) { + lockReleaseContractAddress = govTokenAddress; + votesTokenContractAddress = lockedTokenAddress; } else { - tokenContract = { - asSigner: votesERC20WrapperMasterCopyContract.asSigner.attach(govTokenAddress), - asProvider: votesERC20WrapperMasterCopyContract.asProvider.attach(govTokenAddress), - }; + // @dev if the underlying token is an ERC20Wrapper, we use the underlying token as the token contract + // @dev if the no underlying token, we use the governance token as the token contract + votesTokenContractAddress = govTokenAddress; } + } else if (isOzLinearVotingERC721) { + // @dev for use with the ERC721 voting contract + erc721LinearVotingContractAddress = votingStrategyAddress; } - if (!!ozLinearVotingContract && !!tokenContract) { - action.dispatch({ - type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, - payload: { - ozLinearVotingContract, - erc721LinearVotingContract: null, - azoriusContract, - tokenContract, - underlyingTokenAddress, - lockReleaseContract, - }, - }); - } else if (!!erc721LinearVotingContract) { - action.dispatch({ - type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, - payload: { - ozLinearVotingContract: null, - lockReleaseContract: null, - erc721LinearVotingContract, - azoriusContract, - tokenContract: null, - underlyingTokenAddress, - }, - }); - } else if (!!erc721LinearVotingContract) { + + if (!!votesTokenContractAddress) { action.dispatch({ type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, payload: { - ozLinearVotingContract: null, - erc721LinearVotingContract, - azoriusContract, - tokenContract: null, + ozLinearVotingContractAddress: ozLinearVotingContractAddress, + erc721LinearVotingContractAddress: erc721LinearVotingContractAddress, + azoriusContractAddress: azoriusModuleContract.address, + votesTokenContractAddress, underlyingTokenAddress, - lockReleaseContract: null, + lockReleaseContractAddress, }, }); } else { action.dispatch({ type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, - payload: { - ozLinearVotingContract: null, - erc721LinearVotingContract: null, - azoriusContract: null, - tokenContract: null, - lockReleaseContract: null, - }, + payload: {}, }); currentValidAddress.current = null; } - } else { - action.dispatch({ - type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, - payload: { - ozLinearVotingContract: null, - azoriusContract: null, - erc721LinearVotingContract: null, - tokenContract: null, - lockReleaseContract: null, - }, - }); - currentValidAddress.current = null; } - }, [ - action, - provider, - signerOrProvider, - getZodiacModuleProxyMasterCopyData, - baseContracts, - fractalModules, - ]); + }, [action, provider, getZodiacModuleProxyMasterCopyData, baseContracts, fractalModules]); useEffect(() => { if (currentValidAddress.current !== daoAddress && isModulesLoaded) { diff --git a/src/providers/App/governanceContracts/reducer.ts b/src/providers/App/governanceContracts/reducer.ts index 11ae0f7d5b..069f80200f 100644 --- a/src/providers/App/governanceContracts/reducer.ts +++ b/src/providers/App/governanceContracts/reducer.ts @@ -2,11 +2,11 @@ import { FractalGovernanceContracts } from '../../../types'; import { GovernanceContractAction, GovernanceContractActions } from './action'; export const initialGovernanceContractsState: FractalGovernanceContracts = { - ozLinearVotingContract: null, - erc721LinearVotingContract: null, - azoriusContract: null, - tokenContract: null, - lockReleaseContract: null, + erc721LinearVotingContractAddress: undefined, + ozLinearVotingContractAddress: undefined, + azoriusContractAddress: undefined, + votesTokenContractAddress: undefined, + lockReleaseContractAddress: undefined, isLoaded: false, }; diff --git a/src/types/fractal.ts b/src/types/fractal.ts index ce6c670f08..962f915330 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -25,7 +25,6 @@ import { } from '@safe-global/safe-service-client'; import { BigNumber } from 'ethers'; import { Dispatch } from 'react'; -import { LockRelease } from '../assets/typechain-types/dcnt'; import { MultiSend } from '../assets/typechain-types/usul'; import { GnosisSafeL2 } from '../assets/typechain-types/usul/@gnosis.pm/safe-contracts/contracts'; import { FractalGovernanceActions } from '../providers/App/governance/action'; @@ -223,14 +222,23 @@ export interface Fractal { } export interface FractalGovernanceContracts { - ozLinearVotingContract: ContractConnection | null; - erc721LinearVotingContract: ContractConnection | null; - azoriusContract: ContractConnection | null; - tokenContract: ContractConnection | null; - lockReleaseContract: ContractConnection | null; + ozLinearVotingContractAddress?: string; + erc721LinearVotingContractAddress?: string; + azoriusContractAddress?: string; + votesTokenContractAddress?: string; + lockReleaseContractAddress?: string; underlyingTokenAddress?: string; isLoaded: boolean; } +// export interface FractalGovernanceContracts { +// ozLinearVotingContract: ContractConnection | null; +// erc721LinearVotingContract: ContractConnection | null; +// azoriusContract: ContractConnection | null; +// tokenContract: ContractConnection | null; +// lockReleaseContract: ContractConnection | null; +// underlyingTokenAddress?: string; +// isLoaded: boolean; +// } export interface FractalNode { daoName: string | null; @@ -256,7 +264,13 @@ export enum FractalModuleType { FRACTAL, UNKNOWN, } - +// @todo updates Fractal Guard Contract to just store addresses in the store +// export interface FractalGuardContracts { +// freezeGuardContractAddress?: string; +// freezeVotingContractAddress?: string; +// freezeGuardType: FreezeGuardType | null; +// freezeVotingType: FreezeVotingType | null; +// } export interface FractalGuardContracts { freezeGuardContract?: ContractConnection; freezeVotingContract?: ContractConnection< @@ -294,6 +308,13 @@ export interface DecentGovernance extends AzoriusGovernance { } export interface SafeMultisigGovernance extends Governance {} +// @todo update FractalContracts to just store addresses in the store +// export interface Governance { +// type?: GovernanceType; +// proposals: FractalProposal[] | null; +// proposalTemplates?: ProposalTemplate[] | null; +// tokenClaimContractAddress?: string; +// } export interface Governance { type?: GovernanceType; proposals: FractalProposal[] | null; From b2feac24a3e1c990c0ed8147509ba91bd74eeb6e Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:09:04 -0400 Subject: [PATCH 02/13] Support changes to contract state refactor - uses useSafeContracts directly instead of global state to get base contracts --- .../formComponents/GuardDetails.tsx | 4 +- src/components/Proposals/ProposalSummary.tsx | 11 +- .../ProposalVotes/context/VoteContext.tsx | 27 ++-- .../DAOTreasury/hooks/useFormatTransfers.tsx | 2 +- src/components/ui/modals/DelegateModal.tsx | 18 ++- src/components/ui/modals/UnwrapToken.tsx | 15 +- src/components/ui/modals/WrapToken.tsx | 27 +++- .../loaders/governance/useAzoriusProposals.ts | 149 +++++++++++------- .../DAO/loaders/governance/useERC20Claim.ts | 19 ++- .../governance/useERC20LinearStrategy.ts | 72 +++++---- .../loaders/governance/useERC20LinearToken.ts | 105 ++++++------ .../governance/useERC721LinearStrategy.ts | 81 ++++++---- .../DAO/loaders/governance/useERC721Tokens.ts | 17 +- .../DAO/loaders/governance/useLockRelease.ts | 56 +++---- src/hooks/DAO/loaders/useFractalGovernance.ts | 18 +-- src/hooks/DAO/proposal/useCastVote.ts | 29 +++- src/hooks/DAO/proposal/useExecuteProposal.ts | 23 +-- src/hooks/DAO/proposal/useSubmitProposal.ts | 50 +++--- .../DAO/proposal/useUpdateProposalState.ts | 13 +- .../DAO/proposal/useUserERC721VotingTokens.ts | 12 +- src/hooks/DAO/useBuildDAOTx.ts | 8 +- src/utils/azorius.ts | 10 +- 22 files changed, 470 insertions(+), 296 deletions(-) diff --git a/src/components/DaoCreator/formComponents/GuardDetails.tsx b/src/components/DaoCreator/formComponents/GuardDetails.tsx index 2091fa8d8c..f042cda381 100644 --- a/src/components/DaoCreator/formComponents/GuardDetails.tsx +++ b/src/components/DaoCreator/formComponents/GuardDetails.tsx @@ -33,7 +33,7 @@ function GuardDetails(props: ICreationStepProps) { const { node: { safe }, governance, - governanceContracts: { azoriusContract }, + governanceContracts: { azoriusContractAddress }, readOnly: { dao }, } = useFractal(); const { type } = governance; @@ -55,7 +55,7 @@ function GuardDetails(props: ICreationStepProps) { setFieldValue('multisig.customNonce', safe.nonce); setShowCustomNonce(true); } - }, [isSubDAO, azoriusContract, type, setFieldValue, safe, dao, showCustomNonce]); + }, [isSubDAO, azoriusContractAddress, type, setFieldValue, safe, dao, showCustomNonce]); useEffect(() => { // set the initial value for freezeGuard.freezeVotesThreshold diff --git a/src/components/Proposals/ProposalSummary.tsx b/src/components/Proposals/ProposalSummary.tsx index a0e586476e..2cf0a7f5e5 100644 --- a/src/components/Proposals/ProposalSummary.tsx +++ b/src/components/Proposals/ProposalSummary.tsx @@ -6,6 +6,7 @@ import { BigNumber } from 'ethers'; import { useMemo, useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; 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'; @@ -32,12 +33,11 @@ export default function ProposalSummary({ }) { const { governance, - governanceContracts: { tokenContract }, readOnly: { user: { votingWeight, address }, }, } = useFractal(); - + const baseContracts = useSafeContracts(); const azoriusGovernance = governance as AzoriusGovernance; const { votesToken, type, erc721Tokens, votingStrategy } = azoriusGovernance; const { t } = useTranslation(['proposal', 'common', 'navigation']); @@ -62,8 +62,9 @@ export default function ProposalSummary({ useEffect(() => { async function loadProposalVotingWeight() { - if (tokenContract && address) { - const pastVotingWeight = await tokenContract.asProvider.getPastVotes(address, startBlock); + if (address && baseContracts && votesToken) { + const tokenContract = baseContracts?.votesTokenMasterCopyContract.asProvider.attach(votesToken.address); + const pastVotingWeight = await tokenContract.getPastVotes(address, startBlock); setProposalsERC20VotingWeight( pastVotingWeight.div(votesTokenDecimalsDenominator).toString(), ); @@ -71,7 +72,7 @@ export default function ProposalSummary({ } loadProposalVotingWeight(); - }, [address, startBlock, tokenContract, votesTokenDecimalsDenominator]); + }, [address, startBlock, votesTokenDecimalsDenominator, baseContracts, votesToken]); const isERC20 = type === GovernanceType.AZORIUS_ERC20; const isERC721 = type === GovernanceType.AZORIUS_ERC721; diff --git a/src/components/Proposals/ProposalVotes/context/VoteContext.tsx b/src/components/Proposals/ProposalVotes/context/VoteContext.tsx index aeab0cee8a..60bb8b6de0 100644 --- a/src/components/Proposals/ProposalVotes/context/VoteContext.tsx +++ b/src/components/Proposals/ProposalVotes/context/VoteContext.tsx @@ -1,6 +1,7 @@ import { useContext, useCallback, useEffect, useState, createContext, ReactNode } from 'react'; import useSnapshotProposal from '../../../../hooks/DAO/loaders/snapshot/useSnapshotProposal'; import useUserERC721VotingTokens from '../../../../hooks/DAO/proposal/useUserERC721VotingTokens'; +import useSafeContracts from '../../../../hooks/safe/useSafeContracts'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalProposal, @@ -52,8 +53,10 @@ export function VoteContextProvider({ readOnly: { user, dao }, node: { safe }, governance: { type }, - governanceContracts: { ozLinearVotingContract }, + governanceContracts: { ozLinearVotingContractAddress }, } = useFractal(); + const baseContracts = useSafeContracts(); + const { loadVotingWeight } = useSnapshotProposal(proposal as SnapshotProposal); const { remainingTokenIds, getUserERC721VotingTokens } = useUserERC721VotingTokens( proposal.proposalId, @@ -91,14 +94,19 @@ export function VoteContextProvider({ if (isSnapshotProposal) { const votingWeightData = await loadVotingWeight(); newCanVote = votingWeightData.votingWeight >= 1; - } else if (type === GovernanceType.AZORIUS_ERC20) { + } else if ( + type === GovernanceType.AZORIUS_ERC20 && + ozLinearVotingContractAddress && + baseContracts + ) { + const ozLinearVotingContract = + baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); newCanVote = - ( - await ozLinearVotingContract!.asProvider.getVotingWeight( - user.address, - proposal.proposalId, - ) - )?.gt(0) && !hasVoted; + (await ozLinearVotingContract.getVotingWeight(user.address, proposal.proposalId))?.gt( + 0, + ) && !hasVoted; } else if (type === GovernanceType.AZORIUS_ERC721) { if (refetchUserTokens) { await getUserERC721VotingTokens(); @@ -126,8 +134,9 @@ export function VoteContextProvider({ getUserERC721VotingTokens, isSnapshotProposal, loadVotingWeight, - ozLinearVotingContract, proposal?.proposalId, + baseContracts, + ozLinearVotingContractAddress, ], ); useEffect(() => { diff --git a/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx b/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx index 49bd666d08..620cbda865 100644 --- a/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx +++ b/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx @@ -2,11 +2,11 @@ import { useNetworkConfig } from '../../../../providers/NetworkConfig/NetworkCon import { TransferType, TokenInfo, AssetTransfer } from '../../../../types'; import { formatCoin } from '../../../../utils/numberFormats'; + export enum TokenEventType { DEPOSIT, WITHDRAW, } - export interface TransferDisplayData { eventType: TokenEventType; transferType: TransferType; diff --git a/src/components/ui/modals/DelegateModal.tsx b/src/components/ui/modals/DelegateModal.tsx index ee86291b5b..4735e881ae 100644 --- a/src/components/ui/modals/DelegateModal.tsx +++ b/src/components/ui/modals/DelegateModal.tsx @@ -4,7 +4,9 @@ import { BigNumber, constants } from 'ethers'; import { Field, FieldAttributes, Formik } from 'formik'; import { useTranslation } from 'react-i18next'; import * as Yup from 'yup'; +import { LockRelease__factory } from '../../../assets/typechain-types/dcnt'; import useDelegateVote from '../../../hooks/DAO/useDelegateVote'; +import useSafeContracts from '../../../hooks/safe/useSafeContracts'; import { useValidationAddress } from '../../../hooks/schemas/common/useValidationAddress'; import useDisplayName from '../../../hooks/utils/useDisplayName'; import { useFractal } from '../../../providers/App/AppProvider'; @@ -20,11 +22,13 @@ export function DelegateModal({ close }: { close: Function }) { const { governance, - governanceContracts: { tokenContract, lockReleaseContract }, + governanceContracts: { votesTokenContractAddress, lockReleaseContractAddress }, readOnly: { user }, action: { loadReadOnlyValues }, } = useFractal(); + const baseContracts = useSafeContracts() + const signer = useEthersSigner(); const azoriusGovernance = governance as AzoriusGovernance; const decentGovernance = azoriusGovernance as DecentGovernance; @@ -34,28 +38,32 @@ export function DelegateModal({ close }: { close: Function }) { const { addressValidationTest } = useValidationAddress(); const submitDelegation = async (values: { address: string }) => { - if (!tokenContract) return; + if (!votesTokenContractAddress || !baseContracts) return; let validAddress = values.address; if (couldBeENS(validAddress)) { validAddress = await signer!.resolveName(values.address); } + const votingTokenContract = baseContracts.votesERC20WrapperMasterCopyContract.asProvider.attach( + votesTokenContractAddress, + ); delegateVote({ delegatee: validAddress, - votingTokenContract: tokenContract?.asSigner, + votingTokenContract, successCallback: () => { close(); }, }); }; const submitLockedDelegation = async (values: { address: string }) => { - if (!lockReleaseContract) return; + if (!lockReleaseContractAddress || !baseContracts || !signer) return; let validAddress = values.address; if (couldBeENS(validAddress)) { validAddress = await signer!.resolveName(values.address); } + const lockReleaseContract = LockRelease__factory.connect(lockReleaseContractAddress, signer) delegateVote({ delegatee: validAddress, - votingTokenContract: lockReleaseContract.asSigner, + votingTokenContract: lockReleaseContract, successCallback: async () => { await loadReadOnlyValues(); close(); diff --git a/src/components/ui/modals/UnwrapToken.tsx b/src/components/ui/modals/UnwrapToken.tsx index bd61796f7d..0b1b2a7e81 100644 --- a/src/components/ui/modals/UnwrapToken.tsx +++ b/src/components/ui/modals/UnwrapToken.tsx @@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next'; import { useAccount } from 'wagmi'; import * as Yup from 'yup'; import { useERC20LinearToken } from '../../../hooks/DAO/loaders/governance/useERC20LinearToken'; +import useSafeContracts from '../../../hooks/safe/useSafeContracts'; import useApproval from '../../../hooks/utils/useApproval'; import { useFormHelpers } from '../../../hooks/utils/useFormHelpers'; import { useTransaction } from '../../../hooks/utils/useTransaction'; @@ -22,7 +23,7 @@ export function UnwrapToken({ close }: { close: () => void }) { const azoriusGovernance = governance as AzoriusGovernance; const signer = useEthersSigner(); const { address: account } = useAccount(); - + const baseContracts = useSafeContracts(); const { loadERC20TokenAccountData } = useERC20LinearToken({ onMount: false }); const [contractCall, pending] = useTransaction(); @@ -31,18 +32,20 @@ export function UnwrapToken({ close }: { close: () => void }) { approveTransaction, pending: approvalPending, } = useApproval( - governanceContracts.tokenContract?.asSigner.attach(governanceContracts.underlyingTokenAddress!), + baseContracts?.votesTokenMasterCopyContract?.asSigner.attach(governanceContracts.underlyingTokenAddress!), azoriusGovernance.votesToken?.address, ); + const { t } = useTranslation(['modals', 'treasury']); const { restrictChars } = useFormHelpers(); const handleFormSubmit = useCallback( (amount: BigNumberValuePair) => { - const { tokenContract } = governanceContracts; - if (!tokenContract || !signer || !account) return; - const wrapperTokenContract = tokenContract.asSigner as VotesERC20Wrapper; + const { votesTokenContractAddress } = governanceContracts; + if (!votesTokenContractAddress || !signer || !account) return; + const votesTokenContract = baseContracts?.votesERC20WrapperMasterCopyContract?.asSigner.attach(votesTokenContractAddress); + const wrapperTokenContract = votesTokenContract as VotesERC20Wrapper; contractCall({ contractFn: () => wrapperTokenContract.withdrawTo(account, amount.bigNumberValue!), pendingMessage: t('unwrapTokenPendingMessage'), @@ -56,7 +59,7 @@ export function UnwrapToken({ close }: { close: () => void }) { }, }); }, - [account, contractCall, governanceContracts, signer, close, t, loadERC20TokenAccountData], + [account, contractCall, governanceContracts, signer, close, t, loadERC20TokenAccountData, baseContracts], ); if ( diff --git a/src/components/ui/modals/WrapToken.tsx b/src/components/ui/modals/WrapToken.tsx index e6b05d75ca..00041d5c17 100644 --- a/src/components/ui/modals/WrapToken.tsx +++ b/src/components/ui/modals/WrapToken.tsx @@ -1,6 +1,5 @@ import { Button, Flex, Input } from '@chakra-ui/react'; import { LabelWrapper } from '@decent-org/fractal-ui'; -import { VotesERC20Wrapper } from '@fractal-framework/fractal-contracts'; import { BigNumber, Contract } from 'ethers'; import { Formik, FormikProps } from 'formik'; import { useCallback, useEffect, useState } from 'react'; @@ -9,6 +8,7 @@ import { erc20ABI, useAccount } from 'wagmi'; import * as Yup from 'yup'; import { logError } from '../../../helpers/errorLogging'; import { useERC20LinearToken } from '../../../hooks/DAO/loaders/governance/useERC20LinearToken'; +import useSafeContracts from '../../../hooks/safe/useSafeContracts'; import useApproval from '../../../hooks/utils/useApproval'; import { useFormHelpers } from '../../../hooks/utils/useFormHelpers'; import { useTransaction } from '../../../hooks/utils/useTransaction'; @@ -27,6 +27,7 @@ export function WrapToken({ close }: { close: () => void }) { value: '', bigNumberValue: BigNumber.from(0), }); + const baseContracts = useSafeContracts(); const { loadERC20TokenAccountData } = useERC20LinearToken({ onMount: false }); const [contractCall, pending] = useTransaction(); @@ -35,7 +36,9 @@ export function WrapToken({ close }: { close: () => void }) { approveTransaction, pending: approvalPending, } = useApproval( - governanceContracts.tokenContract?.asSigner.attach(governanceContracts.underlyingTokenAddress!), + baseContracts?.votesTokenMasterCopyContract?.asSigner.attach( + governanceContracts.underlyingTokenAddress!, + ), azoriusGovernance.votesToken?.address, userBalance.bigNumberValue, ); @@ -82,9 +85,12 @@ export function WrapToken({ close }: { close: () => void }) { const handleFormSubmit = useCallback( (amount: BigNumberValuePair) => { - const { tokenContract } = governanceContracts; - if (!tokenContract || !signer || !account) return; - const wrapperTokenContract = tokenContract.asSigner as VotesERC20Wrapper; + const { votesTokenContractAddress } = governanceContracts; + if (!votesTokenContractAddress || !signer || !account || !baseContracts) return; + const wrapperTokenContract = + baseContracts.votesERC20WrapperMasterCopyContract.asSigner.attach( + votesTokenContractAddress, + ); contractCall({ contractFn: () => wrapperTokenContract.depositFor(account, amount.bigNumberValue!), pendingMessage: t('wrapTokenPendingMessage'), @@ -98,7 +104,16 @@ export function WrapToken({ close }: { close: () => void }) { }, }); }, - [account, contractCall, governanceContracts, signer, close, t, loadERC20TokenAccountData], + [ + account, + contractCall, + governanceContracts, + signer, + close, + t, + loadERC20TokenAccountData, + baseContracts, + ], ); if ( diff --git a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts index 7da07adb7d..86b6174dd0 100644 --- a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts +++ b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts @@ -1,38 +1,39 @@ -import { - Azorius, - LinearERC20Voting, - LinearERC721Voting, -} from '@fractal-framework/fractal-contracts'; +import { LinearERC20Voting, LinearERC721Voting } from '@fractal-framework/fractal-contracts'; import { TypedListener } from '@fractal-framework/fractal-contracts/dist/typechain-types/common'; import { ProposalCreatedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/azorius/Azorius'; import { VotedEvent as ERC20VotedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/azorius/LinearERC20Voting'; import { VotedEvent as ERC721VotedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/azorius/LinearERC721Voting'; import { BigNumber } from 'ethers'; 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 useSafeContracts from '../../../safe/useSafeContracts'; import { useAsyncRetry } from '../../../utils/useAsyncRetry'; import { useSafeDecoder } from '../../../utils/useSafeDecoder'; export const useAzoriusProposals = () => { const { - governanceContracts: { azoriusContract, ozLinearVotingContract, erc721LinearVotingContract }, + governanceContracts: { + azoriusContractAddress, + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, + }, action, } = useFractal(); + const baseContracts = useSafeContracts(); const strategyType = useMemo(() => { - if (ozLinearVotingContract) { + if (ozLinearVotingContractAddress) { return VotingStrategyType.LINEAR_ERC20; - } else if (erc721LinearVotingContract) { + } else if (erc721LinearVotingContractAddress) { return VotingStrategyType.LINEAR_ERC721; } else { return undefined; } - }, [ozLinearVotingContract, erc721LinearVotingContract]); + }, [ozLinearVotingContractAddress, erc721LinearVotingContractAddress]); const provider = useEthersProvider(); const decode = useSafeDecoder(); const decodeTransactions = useCallback( @@ -49,21 +50,32 @@ export const useAzoriusProposals = () => { const loadAzoriusProposals = useCallback(async (): Promise => { if ( - !azoriusContract || - !(ozLinearVotingContract || erc721LinearVotingContract) || + !azoriusContractAddress || + !(ozLinearVotingContractAddress || erc721LinearVotingContractAddress) || !strategyType || - !provider + !provider || + !baseContracts ) { return []; } - const rpc = getEventRPC(azoriusContract); - const proposalCreatedFilter = rpc.filters.ProposalCreated(); - - const proposalCreatedEvents = await rpc.queryFilter(proposalCreatedFilter); + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); + const proposalCreatedFilter = azoriusContract.filters.ProposalCreated(); - const strategyContract = getEventRPC( - ozLinearVotingContract ?? erc721LinearVotingContract!, - ); + const proposalCreatedEvents = await azoriusContract.queryFilter(proposalCreatedFilter); + let strategyContract: LinearERC20Voting | LinearERC721Voting; + if (ozLinearVotingContractAddress) { + strategyContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); + } else if (erc721LinearVotingContractAddress) { + strategyContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + } else { + console.error('No strategy contract found'); + return []; + } const proposals = await Promise.all( proposalCreatedEvents.map(async ({ args }) => { @@ -95,11 +107,12 @@ export const useAzoriusProposals = () => { return proposals; }, [ decodeTransactions, - ozLinearVotingContract, - erc721LinearVotingContract, - azoriusContract, + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, + azoriusContractAddress, provider, strategyType, + baseContracts, ]); const { requestWithRetries } = useAsyncRetry(); @@ -107,15 +120,17 @@ export const useAzoriusProposals = () => { const proposalCreatedListener: TypedListener = useCallback( async (strategyAddress, proposalId, proposer, transactions, _metadata) => { if ( - !azoriusContract || - !(ozLinearVotingContract || erc721LinearVotingContract) || + !azoriusContractAddress || + !(ozLinearVotingContractAddress || erc721LinearVotingContractAddress) || !strategyType || - !provider + !provider || + !baseContracts ) { return; } let proposalData: ProposalData | undefined; - + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); if (_metadata) { const metaDataEvent: ProposalMetadata = JSON.parse(_metadata); proposalData = { @@ -128,9 +143,17 @@ export const useAzoriusProposals = () => { decodedTransactions: await decodeTransactions(transactions), }; } - const strategyContract = getEventRPC( - ozLinearVotingContract ?? erc721LinearVotingContract!, - ).attach(strategyAddress); + let strategyContract: LinearERC20Voting | LinearERC721Voting; + if (ozLinearVotingContractAddress) { + strategyContract = + baseContracts.linearVotingMasterCopyContract.asProvider.attach(strategyAddress); + } else if (erc721LinearVotingContractAddress) { + strategyContract = + baseContracts.linearVotingMasterCopyContract.asProvider.attach(strategyAddress); + } else { + console.error('No strategy contract found'); + return []; + } const func = async () => { return mapProposalCreatedEventToProposal( strategyContract, @@ -149,23 +172,27 @@ export const useAzoriusProposals = () => { }); }, [ - ozLinearVotingContract, - erc721LinearVotingContract, - azoriusContract, + baseContracts, + azoriusContractAddress, provider, decodeTransactions, action, requestWithRetries, strategyType, + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, ], ); const erc20ProposalVotedEventListener: TypedListener = useCallback( async (voter, proposalId, support, weight) => { - if (!ozLinearVotingContract || !strategyType) { + if (!ozLinearVotingContractAddress || !strategyType || !baseContracts) { return; } - const strategyContract = getEventRPC(ozLinearVotingContract); + const strategyContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); + const votesSummary = await getProposalVotesSummary( strategyContract, strategyType, @@ -183,15 +210,17 @@ export const useAzoriusProposals = () => { }, }); }, - [ozLinearVotingContract, action, strategyType], + [ozLinearVotingContractAddress, action, strategyType, baseContracts], ); const erc721ProposalVotedEventListener: TypedListener = useCallback( async (voter, proposalId, support, tokenAddresses, tokenIds) => { - if (!erc721LinearVotingContract || !strategyType) { + if (!erc721LinearVotingContractAddress || !strategyType || !baseContracts) { return; } - const strategyContract = getEventRPC(erc721LinearVotingContract); + const strategyContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); const votesSummary = await getProposalVotesSummary( strategyContract, strategyType, @@ -210,45 +239,57 @@ export const useAzoriusProposals = () => { }, }); }, - [erc721LinearVotingContract, action, strategyType], + [erc721LinearVotingContractAddress, action, strategyType, baseContracts], ); useEffect(() => { - if (!azoriusContract) { + if (!azoriusContractAddress || !baseContracts) { return; } - const proposalCreatedFilter = azoriusContract.asProvider.filters.ProposalCreated(); - azoriusContract.asProvider.on(proposalCreatedFilter, proposalCreatedListener); + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); + const proposalCreatedFilter = azoriusContract.filters.ProposalCreated(); + + azoriusContract.on(proposalCreatedFilter, proposalCreatedListener); return () => { - azoriusContract.asProvider.off(proposalCreatedFilter, proposalCreatedListener); + azoriusContract.off(proposalCreatedFilter, proposalCreatedListener); }; - }, [azoriusContract, proposalCreatedListener]); + }, [azoriusContractAddress, proposalCreatedListener, baseContracts]); useEffect(() => { - if (ozLinearVotingContract) { - const votedEvent = ozLinearVotingContract.asProvider.filters.Voted(); + if (ozLinearVotingContractAddress && baseContracts) { + const ozLinearVotingContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); - ozLinearVotingContract.asProvider.on(votedEvent, erc20ProposalVotedEventListener); + const votedEvent = ozLinearVotingContract.filters.Voted(); + + ozLinearVotingContract.on(votedEvent, erc20ProposalVotedEventListener); return () => { - ozLinearVotingContract.asProvider.off(votedEvent, erc20ProposalVotedEventListener); + ozLinearVotingContract.off(votedEvent, erc20ProposalVotedEventListener); }; - } else if (erc721LinearVotingContract) { - const votedEvent = erc721LinearVotingContract.asProvider.filters.Voted(); + } else if (erc721LinearVotingContractAddress && baseContracts) { + const erc721LinearVotingContract = + baseContracts.linearVotingMasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + const votedEvent = erc721LinearVotingContract.filters.Voted(); - erc721LinearVotingContract.asProvider.on(votedEvent, erc721ProposalVotedEventListener); + erc721LinearVotingContract.on(votedEvent, erc721ProposalVotedEventListener); return () => { - erc721LinearVotingContract.asProvider.off(votedEvent, erc721ProposalVotedEventListener); + erc721LinearVotingContract.off(votedEvent, erc721ProposalVotedEventListener); }; } }, [ - ozLinearVotingContract, - erc721LinearVotingContract, + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, erc20ProposalVotedEventListener, erc721ProposalVotedEventListener, + baseContracts, ]); return loadAzoriusProposals; diff --git a/src/hooks/DAO/loaders/governance/useERC20Claim.ts b/src/hooks/DAO/loaders/governance/useERC20Claim.ts index ba01b6036e..d2398c3f2f 100644 --- a/src/hooks/DAO/loaders/governance/useERC20Claim.ts +++ b/src/hooks/DAO/loaders/governance/useERC20Claim.ts @@ -1,6 +1,7 @@ import { useEffect, useCallback } from 'react'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; +import useSafeContracts from '../../../safe/useSafeContracts'; // get list of approvals; approval [0] should be token claim // query using attach = masterTokenClaim.attach(approval[0]).queryFilter() // check if module is tokenClaim; @@ -9,16 +10,18 @@ import { FractalGovernanceAction } from '../../../../providers/App/governance/ac export function useERC20Claim() { const { node: { daoAddress }, - governanceContracts: { tokenContract }, - baseContracts, + governanceContracts: { votesTokenContractAddress }, action, } = useFractal(); - + const baseContracts = useSafeContracts(); const loadTokenClaimContract = useCallback(async () => { - if (!baseContracts || !tokenContract) return; + if (!baseContracts || !votesTokenContractAddress) return; const { claimingMasterCopyContract } = baseContracts; - const approvalFilter = tokenContract.asProvider.filters.Approval(); - const approvals = await tokenContract.asProvider.queryFilter(approvalFilter); + const votesTokenContract = baseContracts.votesTokenMasterCopyContract.asProvider.attach( + votesTokenContractAddress, + ); + const approvalFilter = votesTokenContract.filters.Approval(); + const approvals = await votesTokenContract.queryFilter(approvalFilter); if (!approvals.length) return; const possibleTokenClaimContract = claimingMasterCopyContract.asProvider.attach( approvals[0].args[1], @@ -30,7 +33,7 @@ export function useERC20Claim() { if ( !tokenClaimArray.length || - tokenClaimArray[0].args[1] === tokenContract.asProvider.address + tokenClaimArray[0].args[1] === votesTokenContractAddress ) { return; } @@ -39,7 +42,7 @@ export function useERC20Claim() { type: FractalGovernanceAction.SET_CLAIMING_CONTRACT, payload: possibleTokenClaimContract, }); - }, [baseContracts, tokenContract, action]); + }, [baseContracts, votesTokenContractAddress, action]); useEffect(() => { if (daoAddress) { diff --git a/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts b/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts index 061bcf4714..4b17f90dc6 100644 --- a/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts +++ b/src/hooks/DAO/loaders/governance/useERC20LinearStrategy.ts @@ -1,36 +1,41 @@ -import { Azorius, LinearERC20Voting } from '@fractal-framework/fractal-contracts'; import { TypedListener } from '@fractal-framework/fractal-contracts/dist/typechain-types/common'; import { TimelockPeriodUpdatedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/MultisigFreezeGuard'; import { QuorumNumeratorUpdatedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/azorius/BaseQuorumPercent'; import { VotingPeriodUpdatedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/azorius/LinearERC20Voting'; import { BigNumber } from 'ethers'; 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 useSafeContracts from '../../../safe/useSafeContracts'; import { useTimeHelpers } from '../../../utils/useTimeHelpers'; export const useERC20LinearStrategy = () => { const { - governanceContracts: { ozLinearVotingContract, azoriusContract }, + governanceContracts: { ozLinearVotingContractAddress, azoriusContractAddress }, action, } = useFractal(); + const baseContracts = useSafeContracts(); const provider = useEthersProvider(); const { getTimeDuration } = useTimeHelpers(); const loadERC20Strategy = useCallback(async () => { - if (!ozLinearVotingContract || !azoriusContract || !provider) { + if (!ozLinearVotingContractAddress || !azoriusContractAddress || !provider || !baseContracts) { return {}; } + const ozLinearVotingContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); const [votingPeriodBlocks, quorumNumerator, quorumDenominator, timeLockPeriod] = await Promise.all([ - ozLinearVotingContract.asProvider.votingPeriod(), - ozLinearVotingContract.asProvider.quorumNumerator(), - ozLinearVotingContract.asProvider.QUORUM_DENOMINATOR(), - azoriusContract.asProvider.timelockPeriod(), + ozLinearVotingContract.votingPeriod(), + ozLinearVotingContract.quorumNumerator(), + ozLinearVotingContract.QUORUM_DENOMINATOR(), + azoriusContract.timelockPeriod(), ]); const quorumPercentage = quorumNumerator.mul(100).div(quorumDenominator); @@ -52,32 +57,44 @@ export const useERC20LinearStrategy = () => { strategyType: VotingStrategyType.LINEAR_ERC20, }; action.dispatch({ type: FractalGovernanceAction.SET_STRATEGY, payload: votingData }); - }, [ozLinearVotingContract, azoriusContract, getTimeDuration, action, provider]); + }, [ + ozLinearVotingContractAddress, + azoriusContractAddress, + getTimeDuration, + action, + provider, + baseContracts, + ]); useEffect(() => { - if (!ozLinearVotingContract) { + if (!ozLinearVotingContractAddress || !baseContracts) { return; } - const rpc = getEventRPC(ozLinearVotingContract); - const votingPeriodfilter = rpc.filters.VotingPeriodUpdated(); + const ozLinearVotingContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); + + const votingPeriodfilter = ozLinearVotingContract.filters.VotingPeriodUpdated(); const listener: TypedListener = votingPeriod => { action.dispatch({ type: FractalGovernanceAction.UPDATE_VOTING_PERIOD, payload: BigNumber.from(votingPeriod), }); }; - rpc.on(votingPeriodfilter, listener); + ozLinearVotingContract.on(votingPeriodfilter, listener); return () => { - rpc.off(votingPeriodfilter, listener); + ozLinearVotingContract.off(votingPeriodfilter, listener); }; - }, [ozLinearVotingContract, action]); + }, [ozLinearVotingContractAddress, action, baseContracts]); useEffect(() => { - if (!ozLinearVotingContract) { + if (!ozLinearVotingContractAddress || !baseContracts) { return; } - const rpc = getEventRPC(ozLinearVotingContract); - const quorumNumeratorUpdatedFilter = rpc.filters.QuorumNumeratorUpdated(); + const ozLinearVotingContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); + const quorumNumeratorUpdatedFilter = ozLinearVotingContract.filters.QuorumNumeratorUpdated(); const quorumNumeratorUpdatedListener: TypedListener< QuorumNumeratorUpdatedEvent > = quorumPercentage => { @@ -86,29 +103,30 @@ export const useERC20LinearStrategy = () => { payload: quorumPercentage, }); }; - rpc.on(quorumNumeratorUpdatedFilter, quorumNumeratorUpdatedListener); + ozLinearVotingContract.on(quorumNumeratorUpdatedFilter, quorumNumeratorUpdatedListener); return () => { - rpc.off(quorumNumeratorUpdatedFilter, quorumNumeratorUpdatedListener); + ozLinearVotingContract.off(quorumNumeratorUpdatedFilter, quorumNumeratorUpdatedListener); }; - }, [ozLinearVotingContract, action]); + }, [ozLinearVotingContractAddress, action, baseContracts]); useEffect(() => { - if (!azoriusContract) { + if (!azoriusContractAddress || !baseContracts) { return; } - const rpc = getEventRPC(azoriusContract); - const timeLockPeriodFilter = rpc.filters.TimelockPeriodUpdated(); + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); + const timeLockPeriodFilter = azoriusContract.filters.TimelockPeriodUpdated(); const timelockPeriodListener: TypedListener = timelockPeriod => { action.dispatch({ type: FractalGovernanceAction.UPDATE_TIMELOCK_PERIOD, payload: BigNumber.from(timelockPeriod), }); }; - rpc.on(timeLockPeriodFilter, timelockPeriodListener); + azoriusContract.on(timeLockPeriodFilter, timelockPeriodListener); return () => { - rpc.off(timeLockPeriodFilter, timelockPeriodListener); + azoriusContract.off(timeLockPeriodFilter, timelockPeriodListener); }; - }, [azoriusContract, action]); + }, [azoriusContractAddress, action, baseContracts]); return loadERC20Strategy; }; diff --git a/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts b/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts index c01dc5713d..bc4d00a4c3 100644 --- a/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts +++ b/src/hooks/DAO/loaders/governance/useERC20LinearToken.ts @@ -1,53 +1,54 @@ -import { VotesERC20 } from '@fractal-framework/fractal-contracts'; import { DelegateChangedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/VotesERC20'; import { useCallback, useEffect, useRef } from 'react'; -import { getEventRPC } from '../../../../helpers'; 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); const tokenAccount = useRef(); const { - governanceContracts: { tokenContract, underlyingTokenAddress }, + governanceContracts: { votesTokenContractAddress, underlyingTokenAddress }, action, readOnly: { user }, } = useFractal(); const account = user.address; + const baseContracts = useSafeContracts(); const loadERC20Token = useCallback(async () => { - if (!tokenContract) { + if (!votesTokenContractAddress || !baseContracts) { return; } - const tokenAddress = tokenContract.asProvider.address; + const tokenContract = + baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); const [tokenName, tokenSymbol, tokenDecimals, totalSupply] = await Promise.all([ - tokenContract.asProvider.name(), - tokenContract.asProvider.symbol(), - tokenContract.asProvider.decimals(), - tokenContract.asProvider.totalSupply(), + tokenContract.name(), + tokenContract.symbol(), + tokenContract.decimals(), + tokenContract.totalSupply(), ]); const tokenData = { name: tokenName, symbol: tokenSymbol, decimals: tokenDecimals, - address: tokenAddress, + address: votesTokenContractAddress, totalSupply, }; isTokenLoaded.current = true; action.dispatch({ type: FractalGovernanceAction.SET_TOKEN_DATA, payload: tokenData }); - }, [tokenContract, action]); + }, [votesTokenContractAddress, action, baseContracts]); const loadUnderlyingERC20Token = useCallback(async () => { - if (!tokenContract || !underlyingTokenAddress) { + if (!underlyingTokenAddress || !baseContracts) { return; } - - const erc20WrapperContract = tokenContract.asProvider.attach(underlyingTokenAddress); + const tokenContract = + baseContracts.votesTokenMasterCopyContract.asProvider.attach(underlyingTokenAddress); const [tokenName, tokenSymbol] = await Promise.all([ - erc20WrapperContract.name(), - erc20WrapperContract.symbol(), + tokenContract.name(), + tokenContract.symbol(), ]); const tokenData = { name: tokenName, @@ -58,24 +59,26 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) = type: FractalGovernanceAction.SET_UNDERLYING_TOKEN_DATA, payload: tokenData, }); - }, [tokenContract, underlyingTokenAddress, action]); + }, [underlyingTokenAddress, action, baseContracts]); const loadERC20TokenAccountData = useCallback(async () => { - if (!tokenContract || !account) { + if (!votesTokenContractAddress || !account || !baseContracts) { 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([ - tokenContract.asProvider.balanceOf(account), - tokenContract.asProvider.delegates(account), - tokenContract.asProvider.getVotes(account), + tokenContract.balanceOf(account), + tokenContract.delegates(account), + tokenContract.getVotes(account), ]); let delegateChangeEvents: DelegateChangedEvent[]; try { - delegateChangeEvents = await tokenContract.asProvider.queryFilter( - tokenContract.asProvider.filters.DelegateChanged(), + delegateChangeEvents = await tokenContract.queryFilter( + tokenContract.filters.DelegateChanged(), ); } catch (e) { delegateChangeEvents = []; @@ -92,60 +95,64 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) = type: FractalGovernanceAction.SET_TOKEN_ACCOUNT_DATA, payload: tokenAccountData, }); - }, [tokenContract, action, account]); + }, [votesTokenContractAddress, action, account, baseContracts]); useEffect(() => { if ( - tokenContract && + votesTokenContractAddress && isTokenLoaded.current && - tokenAccount.current !== account + tokenContract.asProvider.address && + tokenAccount.current !== account + votesTokenContractAddress && onMount ) { - tokenAccount.current = account + tokenContract.asProvider.address; + tokenAccount.current = account + votesTokenContractAddress; loadERC20TokenAccountData(); } - }, [account, tokenContract, onMount, loadERC20TokenAccountData]); + }, [account, votesTokenContractAddress, onMount, loadERC20TokenAccountData]); useEffect(() => { - if (!tokenContract || !onMount) { + if (!votesTokenContractAddress || !onMount || !baseContracts) { return; } - const rpc = getEventRPC(tokenContract); - const delegateVotesChangedfilter = rpc.filters.DelegateVotesChanged(); - rpc.on(delegateVotesChangedfilter, loadERC20TokenAccountData); + const tokenContract = + baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); + + const delegateVotesChangedfilter = tokenContract.filters.DelegateVotesChanged(); + tokenContract.on(delegateVotesChangedfilter, loadERC20TokenAccountData); return () => { - rpc.off(delegateVotesChangedfilter, loadERC20TokenAccountData); + tokenContract.off(delegateVotesChangedfilter, loadERC20TokenAccountData); }; - }, [tokenContract, loadERC20TokenAccountData, onMount]); + }, [votesTokenContractAddress, loadERC20TokenAccountData, onMount, baseContracts]); useEffect(() => { - if (!tokenContract || !onMount) { + if (!votesTokenContractAddress || !onMount || !baseContracts) { return; } - const rpc = getEventRPC(tokenContract); - const delegateChangedfilter = rpc.filters.DelegateChanged(); - rpc.on(delegateChangedfilter, loadERC20TokenAccountData); + const tokenContract = + baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); + const delegateChangedfilter = tokenContract.filters.DelegateChanged(); + tokenContract.on(delegateChangedfilter, loadERC20TokenAccountData); return () => { - rpc.off(delegateChangedfilter, loadERC20TokenAccountData); + tokenContract.off(delegateChangedfilter, loadERC20TokenAccountData); }; - }, [tokenContract, loadERC20TokenAccountData, onMount]); + }, [votesTokenContractAddress, loadERC20TokenAccountData, onMount, baseContracts]); useEffect(() => { - if (!tokenContract || !account || !onMount) { + if (!votesTokenContractAddress || !onMount || !baseContracts) { return; } - const rpc = getEventRPC(tokenContract); - const filterTo = rpc.filters.Transfer(null, account); - const filterFrom = rpc.filters.Transfer(account, null); - rpc.on(filterTo, loadERC20TokenAccountData); - rpc.on(filterFrom, loadERC20TokenAccountData); + 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); return () => { - rpc.off(filterTo, loadERC20TokenAccountData); - rpc.off(filterFrom, loadERC20TokenAccountData); + tokenContract.off(filterTo, loadERC20TokenAccountData); + tokenContract.off(filterFrom, loadERC20TokenAccountData); }; - }, [tokenContract, account, onMount, loadERC20TokenAccountData]); + }, [votesTokenContractAddress, account, onMount, loadERC20TokenAccountData, baseContracts]); return { loadERC20Token, loadUnderlyingERC20Token, loadERC20TokenAccountData }; }; diff --git a/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts b/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts index 915506d284..97012eab3a 100644 --- a/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts +++ b/src/hooks/DAO/loaders/governance/useERC721LinearStrategy.ts @@ -1,4 +1,3 @@ -import { Azorius, LinearERC721Voting } from '@fractal-framework/fractal-contracts'; import { TypedListener } from '@fractal-framework/fractal-contracts/dist/typechain-types/common'; import { TimelockPeriodUpdatedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/MultisigFreezeGuard'; import { @@ -7,30 +6,42 @@ import { } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/azorius/LinearERC721Voting'; import { BigNumber } from 'ethers'; 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 useSafeContracts from '../../../safe/useSafeContracts'; import { useTimeHelpers } from '../../../utils/useTimeHelpers'; export const useERC721LinearStrategy = () => { const { - governanceContracts: { erc721LinearVotingContract, azoriusContract }, + governanceContracts: { erc721LinearVotingContractAddress, azoriusContractAddress }, action, } = useFractal(); const provider = useEthersProvider(); const { getTimeDuration } = useTimeHelpers(); - + const baseContracts = useSafeContracts(); const loadERC721Strategy = useCallback(async () => { - if (!erc721LinearVotingContract || !azoriusContract || !provider) { + if ( + !erc721LinearVotingContractAddress || + !azoriusContractAddress || + !provider || + !baseContracts + ) { return {}; } + const erc721LinearVotingContract = + baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); + const [votingPeriodBlocks, quorumThreshold, timeLockPeriod] = await Promise.all([ - erc721LinearVotingContract.asProvider.votingPeriod(), - erc721LinearVotingContract.asProvider.quorumThreshold(), - azoriusContract.asProvider.timelockPeriod(), + erc721LinearVotingContract.votingPeriod(), + erc721LinearVotingContract.quorumThreshold(), + azoriusContract.timelockPeriod(), ]); const votingPeriodValue = await blocksToSeconds(votingPeriodBlocks, provider); @@ -51,32 +62,46 @@ export const useERC721LinearStrategy = () => { strategyType: VotingStrategyType.LINEAR_ERC721, }; action.dispatch({ type: FractalGovernanceAction.SET_STRATEGY, payload: votingData }); - }, [erc721LinearVotingContract, azoriusContract, getTimeDuration, action, provider]); + }, [ + erc721LinearVotingContractAddress, + azoriusContractAddress, + getTimeDuration, + action, + provider, + baseContracts, + ]); useEffect(() => { - if (!erc721LinearVotingContract) { + if (!erc721LinearVotingContractAddress || !baseContracts) { return; } - const rpc = getEventRPC(erc721LinearVotingContract); - const votingPeriodfilter = rpc.filters.VotingPeriodUpdated(); + const erc721LinearVotingContract = + baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + const votingPeriodfilter = erc721LinearVotingContract.filters.VotingPeriodUpdated(); const listener: TypedListener = votingPeriod => { action.dispatch({ type: FractalGovernanceAction.UPDATE_VOTING_PERIOD, payload: BigNumber.from(votingPeriod), }); }; - rpc.on(votingPeriodfilter, listener); + erc721LinearVotingContract.on(votingPeriodfilter, listener); return () => { - rpc.off(votingPeriodfilter, listener); + erc721LinearVotingContract.off(votingPeriodfilter, listener); }; - }, [erc721LinearVotingContract, action]); + }, [erc721LinearVotingContractAddress, action, baseContracts]); useEffect(() => { - if (!erc721LinearVotingContract) { + if (!erc721LinearVotingContractAddress || !baseContracts) { return; } - const rpc = getEventRPC(erc721LinearVotingContract); - const quorumThresholdUpdatedFilter = rpc.filters.QuorumThresholdUpdated(); + const erc721LinearVotingContract = + baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + const quorumThresholdUpdatedFilter = + erc721LinearVotingContract.filters.QuorumThresholdUpdated(); const quorumThresholdUpdatedListener: TypedListener< QuorumThresholdUpdatedEvent > = quorumThreshold => { @@ -85,29 +110,31 @@ export const useERC721LinearStrategy = () => { payload: quorumThreshold, }); }; - rpc.on(quorumThresholdUpdatedFilter, quorumThresholdUpdatedListener); + erc721LinearVotingContract.on(quorumThresholdUpdatedFilter, quorumThresholdUpdatedListener); return () => { - rpc.off(quorumThresholdUpdatedFilter, quorumThresholdUpdatedListener); + erc721LinearVotingContract.off(quorumThresholdUpdatedFilter, quorumThresholdUpdatedListener); }; - }, [erc721LinearVotingContract, action]); + }, [erc721LinearVotingContractAddress, action, baseContracts]); useEffect(() => { - if (!azoriusContract) { + if (!azoriusContractAddress || !baseContracts) { return; } - const rpc = getEventRPC(azoriusContract); - const timeLockPeriodFilter = rpc.filters.TimelockPeriodUpdated(); + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); + + const timeLockPeriodFilter = azoriusContract.filters.TimelockPeriodUpdated(); const timelockPeriodListener: TypedListener = timelockPeriod => { action.dispatch({ type: FractalGovernanceAction.UPDATE_TIMELOCK_PERIOD, payload: BigNumber.from(timelockPeriod), }); }; - rpc.on(timeLockPeriodFilter, timelockPeriodListener); + azoriusContract.on(timeLockPeriodFilter, timelockPeriodListener); return () => { - rpc.off(timeLockPeriodFilter, timelockPeriodListener); + azoriusContract.off(timeLockPeriodFilter, timelockPeriodListener); }; - }, [azoriusContract, action]); + }, [azoriusContractAddress, action, baseContracts]); return loadERC721Strategy; }; diff --git a/src/hooks/DAO/loaders/governance/useERC721Tokens.ts b/src/hooks/DAO/loaders/governance/useERC721Tokens.ts index bfd99643b7..c2ebe2d513 100644 --- a/src/hooks/DAO/loaders/governance/useERC721Tokens.ts +++ b/src/hooks/DAO/loaders/governance/useERC721Tokens.ts @@ -5,25 +5,28 @@ import { logError } from '../../../../helpers/errorLogging'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; import { ERC721TokenData } from '../../../../types'; +import useSafeContracts from '../../../safe/useSafeContracts'; import useSignerOrProvider from '../../../utils/useSignerOrProvider'; export default function useERC721Tokens() { const signerOrProvider = useSignerOrProvider(); const { - governanceContracts: { erc721LinearVotingContract }, + governanceContracts: { erc721LinearVotingContractAddress }, action, } = useFractal(); + const baseContracts = useSafeContracts() const loadERC721Tokens = useCallback(async () => { - if (!erc721LinearVotingContract || !signerOrProvider) { + if (!erc721LinearVotingContractAddress || !signerOrProvider || !baseContracts) { return; } - - const erc721LinearVotingProviderContract = erc721LinearVotingContract.asProvider; - const addresses = await erc721LinearVotingProviderContract.getAllTokenAddresses(); + const erc721LinearVotingContract = baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + const addresses = await erc721LinearVotingContract.getAllTokenAddresses(); const erc721Tokens: ERC721TokenData[] = await Promise.all( addresses.map(async address => { const tokenContract = ERC721__factory.connect(address, signerOrProvider); - const votingWeight = await erc721LinearVotingProviderContract.getTokenWeight(address); + const votingWeight = await erc721LinearVotingContract.getTokenWeight(address); const name = await tokenContract.name(); const symbol = await tokenContract.symbol(); let totalSupply = undefined; @@ -46,7 +49,7 @@ export default function useERC721Tokens() { type: FractalGovernanceAction.SET_ERC721_TOKENS_DATA, payload: erc721Tokens, }); - }, [erc721LinearVotingContract, signerOrProvider, action]); + }, [erc721LinearVotingContractAddress, signerOrProvider, action, baseContracts]); return loadERC721Tokens; } diff --git a/src/hooks/DAO/loaders/governance/useLockRelease.ts b/src/hooks/DAO/loaders/governance/useLockRelease.ts index 8e0472f9e8..64c3698cd7 100644 --- a/src/hooks/DAO/loaders/governance/useLockRelease.ts +++ b/src/hooks/DAO/loaders/governance/useLockRelease.ts @@ -1,9 +1,9 @@ import { DelegateChangedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/VotesERC20'; import { useCallback, useEffect, useRef } from 'react'; -import { LockRelease } from '../../../../assets/typechain-types/dcnt'; -import { getEventRPC } from '../../../../helpers'; +import { LockRelease__factory } from '../../../../assets/typechain-types/dcnt'; import { useFractal } from '../../../../providers/App/AppProvider'; import { DecentGovernanceAction } from '../../../../providers/App/governance/action'; +import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; /** * @link https://github.com/decent-dao/dcnt/blob/master/contracts/LockRelease.sol @@ -14,29 +14,31 @@ export const useLockRelease = ({ onMount = true }: { onMount?: boolean }) => { const tokenAccount = useRef(); const { - governanceContracts: { lockReleaseContract }, + governanceContracts: { lockReleaseContractAddress }, action, readOnly: { user }, } = useFractal(); + const provider = useEthersProvider(); const account = user.address; const loadLockedVotesToken = useCallback(async () => { - if (!lockReleaseContract || !account) { + if (!lockReleaseContractAddress || !account || !provider) { action.dispatch({ type: DecentGovernanceAction.RESET_LOCKED_TOKEN_ACCOUNT_DATA }); return; } + const lockReleaseContract = LockRelease__factory.connect(lockReleaseContractAddress, provider); const [tokenAmountTotal, tokenAmountReleased, tokenDelegatee, tokenVotingWeight] = await Promise.all([ - lockReleaseContract.asProvider.getTotal(account), - lockReleaseContract.asProvider.getReleased(account), - lockReleaseContract.asProvider.delegates(account), - lockReleaseContract.asProvider.getVotes(account), + lockReleaseContract.getTotal(account), + lockReleaseContract.getReleased(account), + lockReleaseContract.delegates(account), + lockReleaseContract.getVotes(account), ]); let delegateChangeEvents: DelegateChangedEvent[]; try { - delegateChangeEvents = await lockReleaseContract.asProvider.queryFilter( - lockReleaseContract.asProvider.filters.DelegateChanged(), + delegateChangeEvents = await lockReleaseContract.queryFilter( + lockReleaseContract.filters.DelegateChanged(), ); } catch (e) { delegateChangeEvents = []; @@ -52,45 +54,45 @@ export const useLockRelease = ({ onMount = true }: { onMount?: boolean }) => { type: DecentGovernanceAction.SET_LOCKED_TOKEN_ACCOUNT_DATA, payload: tokenAccountData, }); - }, [lockReleaseContract, action, account]); + }, [lockReleaseContractAddress, action, account, provider]); useEffect(() => { if ( - lockReleaseContract && + lockReleaseContractAddress && isTokenLoaded.current && - tokenAccount.current !== account + lockReleaseContract.asProvider.address && + tokenAccount.current !== account + lockReleaseContractAddress && onMount ) { - tokenAccount.current = account + lockReleaseContract.asProvider.address; + tokenAccount.current = account + lockReleaseContractAddress; loadLockedVotesToken(); } - }, [account, lockReleaseContract, onMount, loadLockedVotesToken]); + }, [account, lockReleaseContractAddress, onMount, loadLockedVotesToken]); useEffect(() => { - if (!lockReleaseContract || !onMount) { + if (!lockReleaseContractAddress || !onMount || !provider) { return; } - const rpc = getEventRPC(lockReleaseContract); - const delegateVotesChangedfilter = rpc.filters.DelegateVotesChanged(); - rpc.on(delegateVotesChangedfilter, loadLockedVotesToken); + const lockReleaseContract = LockRelease__factory.connect(lockReleaseContractAddress, provider); + const delegateVotesChangedfilter = lockReleaseContract.filters.DelegateVotesChanged(); + lockReleaseContract.on(delegateVotesChangedfilter, loadLockedVotesToken); return () => { - rpc.off(delegateVotesChangedfilter, loadLockedVotesToken); + lockReleaseContract.off(delegateVotesChangedfilter, loadLockedVotesToken); }; - }, [lockReleaseContract, loadLockedVotesToken, onMount]); + }, [lockReleaseContractAddress, loadLockedVotesToken, onMount, provider]); useEffect(() => { - if (!lockReleaseContract || !onMount) { + if (!lockReleaseContractAddress || !onMount || !provider) { return; } - const rpc = getEventRPC(lockReleaseContract); - const delegateChangedfilter = rpc.filters.DelegateChanged(); - rpc.on(delegateChangedfilter, loadLockedVotesToken); + const lockReleaseContract = LockRelease__factory.connect(lockReleaseContractAddress, provider); + const delegateChangedfilter = lockReleaseContract.filters.DelegateChanged(); + lockReleaseContract.on(delegateChangedfilter, loadLockedVotesToken); return () => { - rpc.off(delegateChangedfilter, loadLockedVotesToken); + lockReleaseContract.off(delegateChangedfilter, loadLockedVotesToken); }; - }, [lockReleaseContract, loadLockedVotesToken, onMount]); + }, [lockReleaseContractAddress, loadLockedVotesToken, onMount, provider]); return { loadLockedVotesToken }; }; diff --git a/src/hooks/DAO/loaders/useFractalGovernance.ts b/src/hooks/DAO/loaders/useFractalGovernance.ts index 4a3b86ff3e..f99a44af27 100644 --- a/src/hooks/DAO/loaders/useFractalGovernance.ts +++ b/src/hooks/DAO/loaders/useFractalGovernance.ts @@ -74,22 +74,22 @@ export const useFractalGovernance = () => { useEffect(() => { const { isLoaded, - azoriusContract, - lockReleaseContract, - erc721LinearVotingContract, - ozLinearVotingContract, + azoriusContractAddress, + lockReleaseContractAddress, + erc721LinearVotingContractAddress, + ozLinearVotingContractAddress, } = governanceContracts; const newLoadKey = - (azoriusContract ? '1' : '0') + + (azoriusContractAddress ? '1' : '0') + nodeHierarchy.parentAddress + !!guardContracts.freezeGuardContract; if (isLoaded && newLoadKey !== loadKey.current) { loadKey.current = newLoadKey; - if (azoriusContract) { - if (ozLinearVotingContract) { + if (azoriusContractAddress) { + if (ozLinearVotingContractAddress) { action.dispatch({ type: FractalGovernanceAction.SET_GOVERNANCE_TYPE, payload: GovernanceType.AZORIUS_ERC20, @@ -97,10 +97,10 @@ export const useFractalGovernance = () => { loadERC20Strategy(); loadERC20Token(); loadUnderlyingERC20Token(); - if (lockReleaseContract) { + if (lockReleaseContractAddress) { loadLockedVotesToken(); } - } else if (erc721LinearVotingContract) { + } else if (erc721LinearVotingContractAddress) { action.dispatch({ type: FractalGovernanceAction.SET_GOVERNANCE_TYPE, payload: GovernanceType.AZORIUS_ERC721, diff --git a/src/hooks/DAO/proposal/useCastVote.ts b/src/hooks/DAO/proposal/useCastVote.ts index 05536e713a..f0550e5836 100644 --- a/src/hooks/DAO/proposal/useCastVote.ts +++ b/src/hooks/DAO/proposal/useCastVote.ts @@ -14,6 +14,7 @@ import { ExtendedSnapshotProposal, } from '../../../types'; import encryptWithShutter from '../../../utils/shutter'; +import useSafeContracts from '../../safe/useSafeContracts'; import { useTransaction } from '../../utils/useTransaction'; import useSnapshotSpaceName from '../loaders/snapshot/useSnapshotSpaceName'; import useUserERC721VotingTokens from './useUserERC721VotingTokens'; @@ -31,13 +32,14 @@ const useCastVote = ({ const [snapshotWeightedChoice, setSnapshotWeightedChoice] = useState([]); const { - governanceContracts: { ozLinearVotingContract, erc721LinearVotingContract }, + governanceContracts: { ozLinearVotingContractAddress, erc721LinearVotingContractAddress }, governance, node: { daoSnapshotURL }, readOnly: { user: { address }, }, } = useFractal(); + const baseContracts = useSafeContracts(); const daoSnapshotSpaceName = useSnapshotSpaceName(); const signer = useEthersSigner(); const client = useMemo(() => { @@ -88,11 +90,23 @@ const useCastVote = ({ const castVote = useCallback( async (vote: number) => { let contractFn; - if (type === GovernanceType.AZORIUS_ERC20 && ozLinearVotingContract) { - contractFn = () => ozLinearVotingContract.asSigner.vote(proposal.proposalId, vote); - } else if (type === GovernanceType.AZORIUS_ERC721 && erc721LinearVotingContract) { + if (type === GovernanceType.AZORIUS_ERC20 && ozLinearVotingContractAddress && baseContracts) { + const ozLinearVotingContract = baseContracts.linearVotingMasterCopyContract.asSigner.attach( + ozLinearVotingContractAddress, + ); + contractFn = () => ozLinearVotingContract.vote(proposal.proposalId, vote); + } else if ( + type === GovernanceType.AZORIUS_ERC721 && + erc721LinearVotingContractAddress && + baseContracts + ) { + const erc721LinearVotingContract = + baseContracts.linearVotingERC721MasterCopyContract.asSigner.attach( + erc721LinearVotingContractAddress, + ); + contractFn = () => - erc721LinearVotingContract.asSigner.vote( + erc721LinearVotingContract.vote( proposal.proposalId, vote, remainingTokenAddresses, @@ -118,14 +132,15 @@ const useCastVote = ({ [ contractCallCastVote, t, - ozLinearVotingContract, - erc721LinearVotingContract, + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, type, proposal, remainingTokenAddresses, remainingTokenIds, getCanVote, getHasVoted, + baseContracts, ], ); diff --git a/src/hooks/DAO/proposal/useExecuteProposal.ts b/src/hooks/DAO/proposal/useExecuteProposal.ts index a14a0209e5..6cda488673 100644 --- a/src/hooks/DAO/proposal/useExecuteProposal.ts +++ b/src/hooks/DAO/proposal/useExecuteProposal.ts @@ -3,6 +3,7 @@ import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useFractal } from '../../../providers/App/AppProvider'; import { MetaTransaction, FractalProposal, AzoriusProposal } from '../../../types'; +import useSafeContracts from '../../safe/useSafeContracts'; import { useTransaction } from '../../utils/useTransaction'; import useUpdateProposalState from './useUpdateProposalState'; @@ -10,7 +11,8 @@ export default function useExecuteProposal() { const { t } = useTranslation('transaction'); const { governanceContracts, action } = useFractal(); - const { azoriusContract } = governanceContracts; + const { azoriusContractAddress } = governanceContracts; + const baseContracts = useSafeContracts(); const updateProposalState = useUpdateProposalState({ governanceContracts, governanceDispatch: action.dispatch, @@ -20,9 +22,16 @@ export default function useExecuteProposal() { const executeProposal = useCallback( (proposal: FractalProposal) => { const azoriusProposal = proposal as AzoriusProposal; - if (!azoriusContract || !azoriusProposal.data || !azoriusProposal.data.transactions) { + if ( + !azoriusContractAddress || + !azoriusProposal.data || + !azoriusProposal.data.transactions || + !baseContracts + ) { return; } + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asSigner.attach(azoriusContractAddress); const targets: string[] = []; const values: MetaTransaction['value'][] = []; @@ -38,13 +47,7 @@ export default function useExecuteProposal() { contractCallExecuteProposal({ contractFn: () => - azoriusContract.asSigner.executeProposal( - proposal.proposalId, - targets, - values, - data, - operations, - ), + azoriusContract.executeProposal(proposal.proposalId, targets, values, data, operations), pendingMessage: t('pendingExecute'), failedMessage: t('failedExecute'), successMessage: t('successExecute'), @@ -54,7 +57,7 @@ export default function useExecuteProposal() { }, }); }, - [contractCallExecuteProposal, t, azoriusContract, updateProposalState], + [contractCallExecuteProposal, t, azoriusContractAddress, updateProposalState, baseContracts], ); return { diff --git a/src/hooks/DAO/proposal/useSubmitProposal.ts b/src/hooks/DAO/proposal/useSubmitProposal.ts index cfbfbe4333..49be918ada 100644 --- a/src/hooks/DAO/proposal/useSubmitProposal.ts +++ b/src/hooks/DAO/proposal/useSubmitProposal.ts @@ -1,5 +1,5 @@ import { TypedDataSigner } from '@ethersproject/abstract-signer'; -import { Azorius, BaseStrategy__factory } from '@fractal-framework/fractal-contracts'; +import { Azorius } from '@fractal-framework/fractal-contracts'; import axios from 'axios'; import { BigNumber, Signer, utils } from 'ethers'; import { getAddress, isAddress } from 'ethers/lib/utils'; @@ -23,6 +23,7 @@ import { } from '../../../types'; import { buildSafeApiUrl, getAzoriusModuleFromModules } from '../../../utils'; import { getAverageBlockTime } from '../../../utils/contract'; +import useSafeContracts from '../../safe/useSafeContracts'; import useSignerOrProvider from '../../utils/useSignerOrProvider'; import { useFractalModules } from '../loaders/useFractalModules'; import { useDAOProposals } from '../loaders/useProposals'; @@ -64,12 +65,12 @@ export default function useSubmitProposal() { const { node: { safe, fractalModules }, - baseContracts, guardContracts: { freezeVotingContract }, - governanceContracts: { ozLinearVotingContract, erc721LinearVotingContract }, + governanceContracts: { ozLinearVotingContractAddress, erc721LinearVotingContractAddress }, governance: { type }, readOnly: { user }, } = useFractal(); + const baseContracts = useSafeContracts(); const safeAPI = useSafeAPI(); const globalAzoriusContract = useMemo(() => { @@ -105,7 +106,7 @@ export default function useSubmitProposal() { return !!owners?.includes(user.address || ''); }; - if (safeAddress) { + if (safeAddress && baseContracts) { const safeInfo = await safeAPI.getSafeInfo(utils.getAddress(safeAddress)); const safeModules = await lookupModules(safeInfo.modules); const azoriusModule = getAzoriusModuleFromModules(safeModules); @@ -116,10 +117,8 @@ export default function useSubmitProposal() { const votingContractAddress = ( await azoriusContract.getStrategies('0x0000000000000000000000000000000000000001', 0) )[1]; - const votingContract = BaseStrategy__factory.connect( - votingContractAddress, - signerOrProvider, - ); + const votingContract = + baseContracts.linearVotingMasterCopyContract.asProvider.attach(votingContractAddress); const isProposer = await votingContract.isProposer(user.address); return isProposer; } else { @@ -130,13 +129,23 @@ export default function useSubmitProposal() { const { owners } = safe || {}; return checkIsMultisigOwner(owners); } else if (type === GovernanceType.AZORIUS_ERC20) { - if (ozLinearVotingContract && user.address) { - return ozLinearVotingContract.asProvider.isProposer(user.address); - } - } else if (type === GovernanceType.AZORIUS_ERC721) { - if (erc721LinearVotingContract) { - return erc721LinearVotingContract.asProvider.isProposer(user.address); + if (ozLinearVotingContractAddress && user.address && baseContracts) { + const ozLinearVotingContract = + baseContracts.linearVotingMasterCopyContract.asProvider.attach( + ozLinearVotingContractAddress, + ); + return ozLinearVotingContract.isProposer(user.address); } + } else if ( + type === GovernanceType.AZORIUS_ERC721 && + baseContracts && + erc721LinearVotingContractAddress + ) { + const erc721LinearVotingContract = + baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + return erc721LinearVotingContract.isProposer(user.address); } else { return false; } @@ -147,11 +156,12 @@ export default function useSubmitProposal() { safe, type, user, - ozLinearVotingContract, - erc721LinearVotingContract, + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, lookupModules, safeAPI, signerOrProvider, + baseContracts, ], ); useEffect(() => { @@ -395,8 +405,8 @@ export default function useSubmitProposal() { } } else { const votingStrategyAddress = - ozLinearVotingContract?.asProvider.address || - erc721LinearVotingContract?.asProvider.address || + ozLinearVotingContractAddress || + erc721LinearVotingContractAddress || freezeVotingContract?.asProvider.address; if (!globalAzoriusContract || !votingStrategyAddress) { @@ -430,8 +440,8 @@ export default function useSubmitProposal() { safe, lookupModules, submitMultisigProposal, - ozLinearVotingContract, - erc721LinearVotingContract, + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, submitAzoriusProposal, safeAPI, ], diff --git a/src/hooks/DAO/proposal/useUpdateProposalState.ts b/src/hooks/DAO/proposal/useUpdateProposalState.ts index f7e9090fa4..eb00c9f0b2 100644 --- a/src/hooks/DAO/proposal/useUpdateProposalState.ts +++ b/src/hooks/DAO/proposal/useUpdateProposalState.ts @@ -6,6 +6,7 @@ import { } from '../../../providers/App/governance/action'; import { FractalGovernanceContracts } from '../../../types'; import { getAzoriusProposalState } from '../../../utils'; +import useSafeContracts from '../../safe/useSafeContracts'; interface IUseUpdateProposalState { governanceContracts: FractalGovernanceContracts; @@ -13,21 +14,25 @@ interface IUseUpdateProposalState { } export default function useUpdateProposalState({ - governanceContracts: { azoriusContract }, + governanceContracts: { azoriusContractAddress }, governanceDispatch, }: IUseUpdateProposalState) { + const baseContracts = useSafeContracts(); const updateProposalState = useCallback( async (proposalId: BigNumber) => { - if (!azoriusContract) { + if (!azoriusContractAddress || !baseContracts) { return; } - const newState = await getAzoriusProposalState(azoriusContract.asProvider, proposalId); + const azoriusContract = baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach( + azoriusContractAddress, + ); + const newState = await getAzoriusProposalState(azoriusContract, proposalId); governanceDispatch({ type: FractalGovernanceAction.UPDATE_PROPOSAL_STATE, payload: { proposalId: proposalId.toString(), state: newState }, }); }, - [azoriusContract, governanceDispatch], + [azoriusContractAddress, governanceDispatch, baseContracts], ); return updateProposalState; diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index dd9caaab46..4cc69b1a1e 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -5,11 +5,13 @@ import { } from '@fractal-framework/fractal-contracts'; import { utils, BigNumber } from 'ethers'; import { useState, useEffect, useCallback } from 'react'; +import { zeroAddress } from 'viem'; import { logError } from '../../../helpers/errorLogging'; import { useFractal } from '../../../providers/App/AppProvider'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; import { AzoriusGovernance } from '../../../types'; import { getAzoriusModuleFromModules } from '../../../utils'; +import useSafeContracts from '../../safe/useSafeContracts'; import useSignerOrProvider from '../../utils/useSignerOrProvider'; import { useFractalModules } from '../loaders/useFractalModules'; @@ -36,10 +38,11 @@ export default function useUserERC721VotingTokens( const signerOrProvider = useSignerOrProvider(); const { node: { daoAddress }, - governanceContracts: { erc721LinearVotingContract }, + governanceContracts: { erc721LinearVotingContractAddress }, governance, readOnly: { user }, } = useFractal(); + const baseContracts = useSafeContracts(); const lookupModules = useFractalModules(); const safeAPI = useSafeAPI(); @@ -49,7 +52,9 @@ export default function useUserERC721VotingTokens( const getUserERC721VotingTokens = useCallback( async (_proposalId?: string, _safeAddress?: string | null) => { let govTokens = erc721Tokens; - let votingContract = erc721LinearVotingContract?.asProvider; + let votingContract = baseContracts?.linearVotingERC721MasterCopyContract?.asProvider.attach( + erc721LinearVotingContractAddress || zeroAddress, + ); if (_safeAddress && daoAddress !== _safeAddress) { // Means getting these for any safe, primary use case - calculating user voting weight for freeze voting @@ -174,13 +179,14 @@ export default function useUserERC721VotingTokens( }; }, [ - erc721LinearVotingContract, + erc721LinearVotingContractAddress, erc721Tokens, signerOrProvider, lookupModules, safeAPI, daoAddress, user.address, + baseContracts, ], ); diff --git a/src/hooks/DAO/useBuildDAOTx.ts b/src/hooks/DAO/useBuildDAOTx.ts index 1185cdf8f6..24af6c17c4 100644 --- a/src/hooks/DAO/useBuildDAOTx.ts +++ b/src/hooks/DAO/useBuildDAOTx.ts @@ -25,7 +25,7 @@ const useBuildDAOTx = () => { baseContracts, readOnly: { user, dao }, governance, - governanceContracts: { erc721LinearVotingContract }, + governanceContracts: { erc721LinearVotingContractAddress }, } = useFractal(); const buildDao = useCallback( @@ -124,9 +124,9 @@ const useBuildDAOTx = () => { parentVotingStrategyType = azoriusGovernance.votingStrategy.strategyType; if ( parentVotingStrategyType === VotingStrategyType.LINEAR_ERC721 && - erc721LinearVotingContract + erc721LinearVotingContractAddress ) { - parentVotingStrategyAddress = erc721LinearVotingContract.asProvider.address; + parentVotingStrategyAddress = erc721LinearVotingContractAddress; } } @@ -152,7 +152,7 @@ const useBuildDAOTx = () => { user.address, signerOrProvider, baseContracts, - erc721LinearVotingContract, + erc721LinearVotingContractAddress, dao, governance, createOptions, diff --git a/src/utils/azorius.ts b/src/utils/azorius.ts index 3d79f1739c..a2f1c81466 100644 --- a/src/utils/azorius.ts +++ b/src/utils/azorius.ts @@ -13,7 +13,6 @@ import { ProposalVotesSummary, ProposalVote, VOTE_CHOICES, - ContractConnection, ProposalData, AzoriusProposal, ActivityEventType, @@ -113,7 +112,7 @@ export const mapProposalCreatedEventToProposal = async ( strategyType: VotingStrategyType, proposalId: BigNumber, proposer: string, - azoriusContract: ContractConnection, + azoriusContract: Azorius, provider: Providers, data?: ProposalData, ) => { @@ -122,7 +121,7 @@ export const mapProposalCreatedEventToProposal = async ( const quorum = await getQuorum(strategyContract, strategyType, proposalId); const deadlineSeconds = await getTimeStamp(endBlock, provider); - const state = await getAzoriusProposalState(azoriusContract.asProvider, proposalId); + const state = await getAzoriusProposalState(azoriusContract, proposalId); const votes = await getProposalVotes(strategyContract, proposalId); const block = await provider.getBlock(startBlock); const votesSummary = { @@ -136,9 +135,8 @@ export const mapProposalCreatedEventToProposal = async ( let transactionHash: string | undefined; if (state === FractalProposalState.EXECUTED) { - const proposalExecutedFilter = azoriusContract.asProvider.filters.ProposalExecuted(); - const proposalExecutedEvents = - await azoriusContract.asProvider.queryFilter(proposalExecutedFilter); + const proposalExecutedFilter = azoriusContract.filters.ProposalExecuted(); + const proposalExecutedEvents = await azoriusContract.queryFilter(proposalExecutedFilter); const executedEvent = proposalExecutedEvents.find(event => BigNumber.from(event.args[0]).eq(proposalId), ); From 06eb55097e2b81464acdd914d1e162d54acfe96d Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:20:50 -0400 Subject: [PATCH 03/13] remove old comment --- src/types/fractal.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/types/fractal.ts b/src/types/fractal.ts index 962f915330..9d8d5899fa 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -230,15 +230,6 @@ export interface FractalGovernanceContracts { underlyingTokenAddress?: string; isLoaded: boolean; } -// export interface FractalGovernanceContracts { -// ozLinearVotingContract: ContractConnection | null; -// erc721LinearVotingContract: ContractConnection | null; -// azoriusContract: ContractConnection | null; -// tokenContract: ContractConnection | null; -// lockReleaseContract: ContractConnection | null; -// underlyingTokenAddress?: string; -// isLoaded: boolean; -// } export interface FractalNode { daoName: string | null; From 357870af888a92d728bca649a798a14bc9c8e245 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:31:42 -0400 Subject: [PATCH 04/13] run prettier --- src/components/Proposals/ProposalSummary.tsx | 4 +++- .../DAOTreasury/hooks/useFormatTransfers.tsx | 1 - src/components/ui/modals/DelegateModal.tsx | 11 +++++----- src/components/ui/modals/UnwrapToken.tsx | 21 +++++++++++++++---- .../DAO/loaders/governance/useERC20Claim.ts | 10 +++------ .../DAO/loaders/governance/useERC721Tokens.ts | 9 ++++---- .../DAO/proposal/useUpdateProposalState.ts | 5 ++--- 7 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/components/Proposals/ProposalSummary.tsx b/src/components/Proposals/ProposalSummary.tsx index 2cf0a7f5e5..9f893aed7a 100644 --- a/src/components/Proposals/ProposalSummary.tsx +++ b/src/components/Proposals/ProposalSummary.tsx @@ -63,7 +63,9 @@ export default function ProposalSummary({ useEffect(() => { async function loadProposalVotingWeight() { if (address && baseContracts && votesToken) { - const tokenContract = baseContracts?.votesTokenMasterCopyContract.asProvider.attach(votesToken.address); + const tokenContract = baseContracts.votesTokenMasterCopyContract.asProvider.attach( + votesToken.address, + ); const pastVotingWeight = await tokenContract.getPastVotes(address, startBlock); setProposalsERC20VotingWeight( pastVotingWeight.div(votesTokenDecimalsDenominator).toString(), diff --git a/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx b/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx index 620cbda865..819f47eaaf 100644 --- a/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx +++ b/src/components/pages/DAOTreasury/hooks/useFormatTransfers.tsx @@ -2,7 +2,6 @@ import { useNetworkConfig } from '../../../../providers/NetworkConfig/NetworkCon import { TransferType, TokenInfo, AssetTransfer } from '../../../../types'; import { formatCoin } from '../../../../utils/numberFormats'; - export enum TokenEventType { DEPOSIT, WITHDRAW, diff --git a/src/components/ui/modals/DelegateModal.tsx b/src/components/ui/modals/DelegateModal.tsx index 4735e881ae..d177516cb4 100644 --- a/src/components/ui/modals/DelegateModal.tsx +++ b/src/components/ui/modals/DelegateModal.tsx @@ -27,7 +27,7 @@ export function DelegateModal({ close }: { close: Function }) { action: { loadReadOnlyValues }, } = useFractal(); - const baseContracts = useSafeContracts() + const baseContracts = useSafeContracts(); const signer = useEthersSigner(); const azoriusGovernance = governance as AzoriusGovernance; @@ -43,9 +43,10 @@ export function DelegateModal({ close }: { close: Function }) { if (couldBeENS(validAddress)) { validAddress = await signer!.resolveName(values.address); } - const votingTokenContract = baseContracts.votesERC20WrapperMasterCopyContract.asProvider.attach( - votesTokenContractAddress, - ); + const votingTokenContract = + baseContracts.votesERC20WrapperMasterCopyContract.asProvider.attach( + votesTokenContractAddress, + ); delegateVote({ delegatee: validAddress, votingTokenContract, @@ -60,7 +61,7 @@ export function DelegateModal({ close }: { close: Function }) { if (couldBeENS(validAddress)) { validAddress = await signer!.resolveName(values.address); } - const lockReleaseContract = LockRelease__factory.connect(lockReleaseContractAddress, signer) + const lockReleaseContract = LockRelease__factory.connect(lockReleaseContractAddress, signer); delegateVote({ delegatee: validAddress, votingTokenContract: lockReleaseContract, diff --git a/src/components/ui/modals/UnwrapToken.tsx b/src/components/ui/modals/UnwrapToken.tsx index 0b1b2a7e81..a518c4507f 100644 --- a/src/components/ui/modals/UnwrapToken.tsx +++ b/src/components/ui/modals/UnwrapToken.tsx @@ -32,10 +32,11 @@ export function UnwrapToken({ close }: { close: () => void }) { approveTransaction, pending: approvalPending, } = useApproval( - baseContracts?.votesTokenMasterCopyContract?.asSigner.attach(governanceContracts.underlyingTokenAddress!), + baseContracts?.votesTokenMasterCopyContract?.asSigner.attach( + governanceContracts.underlyingTokenAddress!, + ), azoriusGovernance.votesToken?.address, ); - const { t } = useTranslation(['modals', 'treasury']); const { restrictChars } = useFormHelpers(); @@ -44,7 +45,10 @@ export function UnwrapToken({ close }: { close: () => void }) { (amount: BigNumberValuePair) => { const { votesTokenContractAddress } = governanceContracts; if (!votesTokenContractAddress || !signer || !account) return; - const votesTokenContract = baseContracts?.votesERC20WrapperMasterCopyContract?.asSigner.attach(votesTokenContractAddress); + const votesTokenContract = + baseContracts?.votesERC20WrapperMasterCopyContract?.asSigner.attach( + votesTokenContractAddress, + ); const wrapperTokenContract = votesTokenContract as VotesERC20Wrapper; contractCall({ contractFn: () => wrapperTokenContract.withdrawTo(account, amount.bigNumberValue!), @@ -59,7 +63,16 @@ export function UnwrapToken({ close }: { close: () => void }) { }, }); }, - [account, contractCall, governanceContracts, signer, close, t, loadERC20TokenAccountData, baseContracts], + [ + account, + contractCall, + governanceContracts, + signer, + close, + t, + loadERC20TokenAccountData, + baseContracts, + ], ); if ( diff --git a/src/hooks/DAO/loaders/governance/useERC20Claim.ts b/src/hooks/DAO/loaders/governance/useERC20Claim.ts index d2398c3f2f..c3ad1ff3a6 100644 --- a/src/hooks/DAO/loaders/governance/useERC20Claim.ts +++ b/src/hooks/DAO/loaders/governance/useERC20Claim.ts @@ -17,9 +17,8 @@ export function useERC20Claim() { const loadTokenClaimContract = useCallback(async () => { if (!baseContracts || !votesTokenContractAddress) return; const { claimingMasterCopyContract } = baseContracts; - const votesTokenContract = baseContracts.votesTokenMasterCopyContract.asProvider.attach( - votesTokenContractAddress, - ); + const votesTokenContract = + baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress); const approvalFilter = votesTokenContract.filters.Approval(); const approvals = await votesTokenContract.queryFilter(approvalFilter); if (!approvals.length) return; @@ -31,10 +30,7 @@ export function useERC20Claim() { .queryFilter(tokenClaimFilter) .catch(() => []); - if ( - !tokenClaimArray.length || - tokenClaimArray[0].args[1] === votesTokenContractAddress - ) { + if (!tokenClaimArray.length || tokenClaimArray[0].args[1] === votesTokenContractAddress) { return; } // action to governance diff --git a/src/hooks/DAO/loaders/governance/useERC721Tokens.ts b/src/hooks/DAO/loaders/governance/useERC721Tokens.ts index c2ebe2d513..51bd2ab34a 100644 --- a/src/hooks/DAO/loaders/governance/useERC721Tokens.ts +++ b/src/hooks/DAO/loaders/governance/useERC721Tokens.ts @@ -14,14 +14,15 @@ export default function useERC721Tokens() { governanceContracts: { erc721LinearVotingContractAddress }, action, } = useFractal(); - const baseContracts = useSafeContracts() + const baseContracts = useSafeContracts(); const loadERC721Tokens = useCallback(async () => { if (!erc721LinearVotingContractAddress || !signerOrProvider || !baseContracts) { return; } - const erc721LinearVotingContract = baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( - erc721LinearVotingContractAddress, - ); + const erc721LinearVotingContract = + baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); const addresses = await erc721LinearVotingContract.getAllTokenAddresses(); const erc721Tokens: ERC721TokenData[] = await Promise.all( addresses.map(async address => { diff --git a/src/hooks/DAO/proposal/useUpdateProposalState.ts b/src/hooks/DAO/proposal/useUpdateProposalState.ts index eb00c9f0b2..e715b51a15 100644 --- a/src/hooks/DAO/proposal/useUpdateProposalState.ts +++ b/src/hooks/DAO/proposal/useUpdateProposalState.ts @@ -23,9 +23,8 @@ export default function useUpdateProposalState({ if (!azoriusContractAddress || !baseContracts) { return; } - const azoriusContract = baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach( - azoriusContractAddress, - ); + const azoriusContract = + baseContracts.fractalAzoriusMasterCopyContract.asProvider.attach(azoriusContractAddress); const newState = await getAzoriusProposalState(azoriusContract, proposalId); governanceDispatch({ type: FractalGovernanceAction.UPDATE_PROPOSAL_STATE, From 777eb00c0bd98fa4eeea885826472f8ddd864ca1 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Thu, 14 Mar 2024 23:24:19 -0400 Subject: [PATCH 05/13] fix large loader --- src/pages/daos/[daoAddress]/proposals/[proposalId]/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/daos/[daoAddress]/proposals/[proposalId]/index.tsx b/src/pages/daos/[daoAddress]/proposals/[proposalId]/index.tsx index 55971f1a9e..a91df7c946 100644 --- a/src/pages/daos/[daoAddress]/proposals/[proposalId]/index.tsx +++ b/src/pages/daos/[daoAddress]/proposals/[proposalId]/index.tsx @@ -1,3 +1,4 @@ +import { Box } from '@chakra-ui/react'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; @@ -67,7 +68,9 @@ export default function ProposalDetailsPage() { ]} /> {proposal === undefined ? ( - + + + ) : proposal === null ? ( ) : isSnapshotProposal ? ( From 0d55be3773dccde8ce7eec0e8a6f0c531a99aba2 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 15 Mar 2024 13:16:26 -0400 Subject: [PATCH 06/13] asProvider -> asSigner for DelegateModal --- src/components/ui/modals/DelegateModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/modals/DelegateModal.tsx b/src/components/ui/modals/DelegateModal.tsx index d177516cb4..c65bdceff1 100644 --- a/src/components/ui/modals/DelegateModal.tsx +++ b/src/components/ui/modals/DelegateModal.tsx @@ -44,7 +44,7 @@ export function DelegateModal({ close }: { close: Function }) { validAddress = await signer!.resolveName(values.address); } const votingTokenContract = - baseContracts.votesERC20WrapperMasterCopyContract.asProvider.attach( + baseContracts.votesERC20WrapperMasterCopyContract.asSigner.attach( votesTokenContractAddress, ); delegateVote({ From eaa5b7e80eea3b9a45115a31627d1456b0b3e3b1 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 15 Mar 2024 13:40:29 -0400 Subject: [PATCH 07/13] log sentry if no strategy found --- src/hooks/DAO/loaders/governance/useAzoriusProposals.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts index 86b6174dd0..25570533aa 100644 --- a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts +++ b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts @@ -5,6 +5,7 @@ import { VotedEvent as ERC20VotedEvent } from '@fractal-framework/fractal-contra import { VotedEvent as ERC721VotedEvent } from '@fractal-framework/fractal-contracts/dist/typechain-types/contracts/azorius/LinearERC721Voting'; import { BigNumber } from 'ethers'; import { useCallback, useEffect, useMemo } from 'react'; +import { logError } from '../../../../helpers/errorLogging'; import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; @@ -73,7 +74,7 @@ export const useAzoriusProposals = () => { erc721LinearVotingContractAddress, ); } else { - console.error('No strategy contract found'); + logError('No strategy contract found'); return []; } @@ -151,7 +152,7 @@ export const useAzoriusProposals = () => { strategyContract = baseContracts.linearVotingMasterCopyContract.asProvider.attach(strategyAddress); } else { - console.error('No strategy contract found'); + logError('No strategy contract found'); return []; } const func = async () => { From 0a151420bdccc69cd312d7ed3638e7896876ae35 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 15 Mar 2024 13:40:54 -0400 Subject: [PATCH 08/13] attach correct strategy --- src/hooks/DAO/loaders/governance/useAzoriusProposals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts index 25570533aa..fcd803def2 100644 --- a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts +++ b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts @@ -150,7 +150,7 @@ export const useAzoriusProposals = () => { baseContracts.linearVotingMasterCopyContract.asProvider.attach(strategyAddress); } else if (erc721LinearVotingContractAddress) { strategyContract = - baseContracts.linearVotingMasterCopyContract.asProvider.attach(strategyAddress); + baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach(strategyAddress); } else { logError('No strategy contract found'); return []; From ac518f7845021b054dddcf679bc0ea8c1386fcf7 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 15 Mar 2024 13:56:22 -0400 Subject: [PATCH 09/13] bugfix - Mulsig wasn't loading - the else was out of place --- src/hooks/DAO/loaders/useGovernanceContracts.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/hooks/DAO/loaders/useGovernanceContracts.ts b/src/hooks/DAO/loaders/useGovernanceContracts.ts index 1301a7052b..9ada3e3580 100644 --- a/src/hooks/DAO/loaders/useGovernanceContracts.ts +++ b/src/hooks/DAO/loaders/useGovernanceContracts.ts @@ -104,13 +104,15 @@ export const useGovernanceContracts = () => { lockReleaseContractAddress, }, }); - } else { - action.dispatch({ - type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, - payload: {}, - }); - currentValidAddress.current = null; + } + // else this has no governance token and can be assumed is a multi-sig + } else { + action.dispatch({ + type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, + payload: {}, + }); + currentValidAddress.current = null; } }, [action, provider, getZodiacModuleProxyMasterCopyData, baseContracts, fractalModules]); From aa4db65e1d738a38329589fdb2bcc037290a33f0 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:07:21 -0400 Subject: [PATCH 10/13] remove currentValidAddress = null --- src/hooks/DAO/loaders/useGovernanceContracts.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hooks/DAO/loaders/useGovernanceContracts.ts b/src/hooks/DAO/loaders/useGovernanceContracts.ts index 9ada3e3580..c05b72827c 100644 --- a/src/hooks/DAO/loaders/useGovernanceContracts.ts +++ b/src/hooks/DAO/loaders/useGovernanceContracts.ts @@ -112,7 +112,6 @@ export const useGovernanceContracts = () => { type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, payload: {}, }); - currentValidAddress.current = null; } }, [action, provider, getZodiacModuleProxyMasterCopyData, baseContracts, fractalModules]); From dfcca219ea79e43d26c8fc05e718d55dda53f972 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:18:43 -0400 Subject: [PATCH 11/13] run pretty --- src/components/ui/modals/DelegateModal.tsx | 4 +--- src/hooks/DAO/loaders/governance/useAzoriusProposals.ts | 2 +- src/hooks/DAO/loaders/useGovernanceContracts.ts | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/ui/modals/DelegateModal.tsx b/src/components/ui/modals/DelegateModal.tsx index c65bdceff1..ccca3240db 100644 --- a/src/components/ui/modals/DelegateModal.tsx +++ b/src/components/ui/modals/DelegateModal.tsx @@ -44,9 +44,7 @@ export function DelegateModal({ close }: { close: Function }) { validAddress = await signer!.resolveName(values.address); } const votingTokenContract = - baseContracts.votesERC20WrapperMasterCopyContract.asSigner.attach( - votesTokenContractAddress, - ); + baseContracts.votesERC20WrapperMasterCopyContract.asSigner.attach(votesTokenContractAddress); delegateVote({ delegatee: validAddress, votingTokenContract, diff --git a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts index fcd803def2..6928af6f11 100644 --- a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts +++ b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts @@ -152,7 +152,7 @@ export const useAzoriusProposals = () => { strategyContract = baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach(strategyAddress); } else { - logError('No strategy contract found'); + logError('No strategy contract found'); return []; } const func = async () => { diff --git a/src/hooks/DAO/loaders/useGovernanceContracts.ts b/src/hooks/DAO/loaders/useGovernanceContracts.ts index c05b72827c..adad0da411 100644 --- a/src/hooks/DAO/loaders/useGovernanceContracts.ts +++ b/src/hooks/DAO/loaders/useGovernanceContracts.ts @@ -104,7 +104,6 @@ export const useGovernanceContracts = () => { lockReleaseContractAddress, }, }); - } // else this has no governance token and can be assumed is a multi-sig } else { From 8e014e1f69aa9c00fd65adc4f5d5efdf98b600f8 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:31:14 -0400 Subject: [PATCH 12/13] fixes logic to remove reliance on zeroAddress --- .../DAO/proposal/useUserERC721VotingTokens.ts | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index 4cc69b1a1e..5192962dcf 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -2,10 +2,10 @@ import { ERC721__factory, Azorius, LinearERC721Voting__factory, + LinearERC721Voting, } from '@fractal-framework/fractal-contracts'; import { utils, BigNumber } from 'ethers'; import { useState, useEffect, useCallback } from 'react'; -import { zeroAddress } from 'viem'; import { logError } from '../../../helpers/errorLogging'; import { useFractal } from '../../../providers/App/AppProvider'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; @@ -51,10 +51,23 @@ export default function useUserERC721VotingTokens( const getUserERC721VotingTokens = useCallback( async (_proposalId?: string, _safeAddress?: string | null) => { + const totalTokenAddresses: string[] = []; + const totalTokenIds: string[] = []; + const tokenAddresses: string[] = []; + const tokenIds: string[] = []; + const userERC721Tokens = new Map>(); + let govTokens = erc721Tokens; - let votingContract = baseContracts?.linearVotingERC721MasterCopyContract?.asProvider.attach( - erc721LinearVotingContractAddress || zeroAddress, - ); + let votingContract: LinearERC721Voting | undefined; + + if (!baseContracts || !signerOrProvider || !daoAddress) { + return { + totalVotingTokenAddresses: totalTokenAddresses, + totalVotingTokenIds: totalTokenIds, + remainingTokenAddresses: tokenAddresses, + remainingTokenIds: tokenIds, + }; + } if (_safeAddress && daoAddress !== _safeAddress) { // Means getting these for any safe, primary use case - calculating user voting weight for freeze voting @@ -69,12 +82,12 @@ export default function useUserERC721VotingTokens( )[1]; votingContract = LinearERC721Voting__factory.connect( votingContractAddress, - signerOrProvider!, + signerOrProvider, ); const addresses = await votingContract.getAllTokenAddresses(); govTokens = await Promise.all( addresses.map(async tokenAddress => { - const tokenContract = ERC721__factory.connect(tokenAddress, signerOrProvider!); + const tokenContract = ERC721__factory.connect(tokenAddress, signerOrProvider); const votingWeight = await votingContract!.getTokenWeight(tokenAddress); const name = await tokenContract.name(); const symbol = await tokenContract.symbol(); @@ -92,12 +105,11 @@ export default function useUserERC721VotingTokens( ); } } - - const totalTokenAddresses: string[] = []; - const totalTokenIds: string[] = []; - const tokenAddresses: string[] = []; - const tokenIds: string[] = []; - const userERC721Tokens = new Map>(); + if (erc721LinearVotingContractAddress && !votingContract) { + votingContract = baseContracts.linearVotingERC721MasterCopyContract.asProvider.attach( + erc721LinearVotingContractAddress, + ); + } if (!govTokens || !votingContract || !user.address) { return { From 9fba7d4c9a70a48422c9f31d3d6288a53a21f603 Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Mon, 18 Mar 2024 14:42:33 -0400 Subject: [PATCH 13/13] empty commit to bump a build