diff --git a/src/components/pages/DaoHierarchy/useFetchNodes.tsx b/src/components/pages/DaoHierarchy/useFetchNodes.tsx index ef4ad4d74b..eaffa7a439 100644 --- a/src/components/pages/DaoHierarchy/useFetchNodes.tsx +++ b/src/components/pages/DaoHierarchy/useFetchNodes.tsx @@ -1,7 +1,9 @@ import { useQuery } from '@apollo/client'; import { useCallback, useEffect, useState } from 'react'; -import { getAddress, zeroAddress } from 'viem'; +import { getAddress, getContract, zeroAddress } from 'viem'; +import { usePublicClient } from 'wagmi'; import { DAOQueryDocument } from '../../../../.graphclient'; +import AzoriusAbi from '../../../assets/abi/Azorius'; import { logError } from '../../../helpers/errorLogging'; import { useFractalModules } from '../../../hooks/DAO/loaders/useFractalModules'; import { useAsyncRetry } from '../../../hooks/utils/useAsyncRetry'; @@ -23,6 +25,7 @@ export function useFetchNodes(address?: string) { const { requestWithRetries } = useAsyncRetry(); const { subgraph } = useNetworkConfig(); + const publicClient = usePublicClient(); const { data, error } = useQuery(DAOQueryDocument, { variables: { daoAddress: address }, skip: address === safe?.address || !address, // If address === safe.address - we already have hierarchy obtained in the context @@ -38,11 +41,8 @@ export function useFetchNodes(address?: string) { const getDAOOwner = useCallback( async (safeInfo?: Partial) => { if (safeInfo && safeInfo.guard && baseContracts) { - const { - multisigFreezeGuardMasterCopyContract, - azoriusFreezeGuardMasterCopyContract, - fractalAzoriusMasterCopyContract, - } = baseContracts; + const { multisigFreezeGuardMasterCopyContract, azoriusFreezeGuardMasterCopyContract } = + baseContracts; if (safeInfo.guard !== zeroAddress) { const guard = multisigFreezeGuardMasterCopyContract.asProvider.attach(safeInfo.guard); const guardOwner = await guard.owner(); @@ -53,15 +53,13 @@ export function useFetchNodes(address?: string) { const modules = await lookupModules(safeInfo.modules || []); if (!modules) return; const azoriusModule = getAzoriusModuleFromModules(modules); - if ( - azoriusModule && - azoriusFreezeGuardMasterCopyContract && - fractalAzoriusMasterCopyContract - ) { - const azoriusContract = fractalAzoriusMasterCopyContract?.asProvider.attach( - azoriusModule.moduleAddress, - ); - const azoriusGuardAddress = await azoriusContract.getGuard(); + if (azoriusModule && azoriusFreezeGuardMasterCopyContract && publicClient) { + const azoriusContract = getContract({ + abi: AzoriusAbi, + address: getAddress(azoriusModule.moduleAddress), + client: publicClient, + }); + const azoriusGuardAddress = await azoriusContract.read.getGuard(); if (azoriusGuardAddress !== zeroAddress) { const guard = azoriusFreezeGuardMasterCopyContract.asProvider.attach(azoriusGuardAddress); @@ -75,7 +73,7 @@ export function useFetchNodes(address?: string) { } return undefined; }, - [baseContracts, lookupModules], + [baseContracts, lookupModules, publicClient], ); const fetchDAOInfo = useCallback( diff --git a/src/hooks/DAO/loaders/useFractalGuardContracts.ts b/src/hooks/DAO/loaders/useFractalGuardContracts.ts index b8b6be1438..2fb722a4ab 100644 --- a/src/hooks/DAO/loaders/useFractalGuardContracts.ts +++ b/src/hooks/DAO/loaders/useFractalGuardContracts.ts @@ -1,10 +1,8 @@ -import { - Azorius, - AzoriusFreezeGuard, - MultisigFreezeGuard, -} from '@fractal-framework/fractal-contracts'; +import { AzoriusFreezeGuard, MultisigFreezeGuard } from '@fractal-framework/fractal-contracts'; import { useCallback, useEffect, useRef } from 'react'; -import { getAddress, zeroAddress } from 'viem'; +import { getAddress, getContract, zeroAddress } from 'viem'; +import { usePublicClient } from 'wagmi'; +import AzoriusAbi from '../../../assets/abi/Azorius'; import { useFractal } from '../../../providers/App/AppProvider'; import { GuardContractAction } from '../../../providers/App/guardContracts/action'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; @@ -31,6 +29,8 @@ export const useFractalGuardContracts = ({ loadOnMount = true }: { loadOnMount?: const { getZodiacModuleProxyMasterCopyData } = useMasterCopy(); + const publicClient = usePublicClient(); + const loadFractalGuardContracts = useCallback( async ( _daoAddress: string, @@ -52,9 +52,13 @@ export const useFractalGuardContracts = ({ loadOnMount = true }: { loadOnMount?: const azoriusModule = _fractalModules?.find( module => module.moduleType === FractalModuleType.AZORIUS, ); - if (!!azoriusModule && azoriusModule.moduleContract) { - const azoriusGuardAddress = await (azoriusModule.moduleContract as Azorius).getGuard(); - + if (azoriusModule && publicClient) { + const azoriusContract = getContract({ + abi: AzoriusAbi, + address: getAddress(azoriusModule.moduleAddress), + client: publicClient, + }); + const azoriusGuardAddress = await azoriusContract.read.getGuard(); if (azoriusGuardAddress === zeroAddress) { return { freezeGuardContractAddress: '', @@ -109,7 +113,7 @@ export const useFractalGuardContracts = ({ loadOnMount = true }: { loadOnMount?: }; } }, - [baseContracts, getZodiacModuleProxyMasterCopyData], + [baseContracts, getZodiacModuleProxyMasterCopyData, publicClient], ); const setGuardContracts = useCallback(async () => { diff --git a/src/hooks/DAO/loaders/useFractalModules.ts b/src/hooks/DAO/loaders/useFractalModules.ts index a278a4a62f..b0b66e2c28 100644 --- a/src/hooks/DAO/loaders/useFractalModules.ts +++ b/src/hooks/DAO/loaders/useFractalModules.ts @@ -1,13 +1,10 @@ import { useCallback } from 'react'; -import { getAddress, getContract } from 'viem'; +import { getAddress } from 'viem'; import { usePublicClient } from 'wagmi'; -import FractalModuleAbi from '../../../assets/abi/FractalModule'; -import { useFractal } from '../../../providers/App/AppProvider'; import { FractalModuleData, FractalModuleType } from '../../../types'; import { useMasterCopy } from '../../utils/useMasterCopy'; export const useFractalModules = () => { - const { baseContracts } = useFractal(); const { getZodiacModuleProxyMasterCopyData } = useMasterCopy(); const publicClient = usePublicClient(); const lookupModules = useCallback( @@ -20,26 +17,18 @@ export const useFractalModules = () => { let safeModule: FractalModuleData; - if (masterCopyData.isAzorius && baseContracts) { + if (masterCopyData.isAzorius && publicClient) { safeModule = { - moduleContract: - baseContracts.fractalAzoriusMasterCopyContract.asSigner.attach(moduleAddress), moduleAddress: moduleAddress, moduleType: FractalModuleType.AZORIUS, }; } else if (masterCopyData.isFractalModule && publicClient) { safeModule = { - moduleContract: getContract({ - abi: FractalModuleAbi, - address: getAddress(moduleAddress), - client: publicClient, - }), moduleAddress: moduleAddress, moduleType: FractalModuleType.FRACTAL, }; } else { safeModule = { - moduleContract: undefined, moduleAddress: moduleAddress, moduleType: FractalModuleType.UNKNOWN, }; @@ -50,7 +39,7 @@ export const useFractalModules = () => { ); return modules; }, - [baseContracts, getZodiacModuleProxyMasterCopyData, publicClient], + [getZodiacModuleProxyMasterCopyData, publicClient], ); return lookupModules; }; diff --git a/src/hooks/DAO/loaders/useGovernanceContracts.ts b/src/hooks/DAO/loaders/useGovernanceContracts.ts index 5fc4c4df79..1ed8d83a61 100644 --- a/src/hooks/DAO/loaders/useGovernanceContracts.ts +++ b/src/hooks/DAO/loaders/useGovernanceContracts.ts @@ -1,7 +1,7 @@ -import { Azorius } from '@fractal-framework/fractal-contracts'; import { useCallback, useEffect, useRef } from 'react'; import { getContract, getAddress } from 'viem'; import { usePublicClient } from 'wagmi'; +import AzoriusAbi from '../../../assets/abi/Azorius'; import LinearERC20VotingAbi from '../../../assets/abi/LinearERC20Voting'; import LockReleaseAbi from '../../../assets/abi/LockRelease'; import VotesERC20WrapperAbi from '../../../assets/abi/VotesERC20Wrapper'; @@ -28,96 +28,102 @@ export const useGovernanceContracts = () => { } const { fractalAzoriusMasterCopyContract } = baseContracts; const azoriusModule = getAzoriusModuleFromModules(fractalModules); - const azoriusModuleContract = azoriusModule?.moduleContract as Azorius; - - if (!!azoriusModuleContract) { - const azoriusContract = fractalAzoriusMasterCopyContract.asProvider.attach( - azoriusModuleContract.address, - ); - let ozLinearVotingContractAddress: string | undefined; - let erc721LinearVotingContractAddress: string | undefined; - let votesTokenContractAddress: string | undefined; - let underlyingTokenAddress: string | undefined; - let lockReleaseContractAddress: string | undefined; - - // @dev assumes the first strategy is the voting contract - const votingStrategyAddress = (await azoriusContract.getStrategies(SENTINEL_ADDRESS, 0))[1]; - - const masterCopyData = await getZodiacModuleProxyMasterCopyData( - getAddress(votingStrategyAddress), - ); - const isOzLinearVoting = masterCopyData.isOzLinearVoting; - const isOzLinearVotingERC721 = masterCopyData.isOzLinearVotingERC721; - - if (isOzLinearVoting) { - ozLinearVotingContractAddress = votingStrategyAddress; - - const ozLinearVotingContract = getContract({ - abi: LinearERC20VotingAbi, - address: getAddress(ozLinearVotingContractAddress), - client: publicClient, - }); - const govTokenAddress = await ozLinearVotingContract.read.governanceToken(); - - const possibleERC20Wrapper = getContract({ - abi: VotesERC20WrapperAbi, - address: getAddress(govTokenAddress), - client: publicClient, - }); - - underlyingTokenAddress = await possibleERC20Wrapper.read.underlying().catch(() => { - // if the underlying token is not an ERC20Wrapper, this will throw an error, - // so we catch it and return undefined - return undefined; - }); - const possibleLockRelease = getContract({ - address: getAddress(govTokenAddress), - abi: LockReleaseAbi, - client: { public: publicClient }, - }); - - let lockedTokenAddress = undefined; - try { - lockedTokenAddress = await possibleLockRelease.read.token(); - } catch { - // no-op - // if the underlying token is not an ERC20Wrapper, this will throw an error, - // so we catch it and do nothing - } - - if (lockedTokenAddress) { - lockReleaseContractAddress = govTokenAddress; - // @dev if the underlying token is an ERC20Wrapper, we use the underlying token as the token contract - votesTokenContractAddress = lockedTokenAddress; - } else { - // @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 (!azoriusModule) { + action.dispatch({ + type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, + payload: {}, + }); + return; + } + + const azoriusModuleContract = getContract({ + abi: AzoriusAbi, + address: getAddress(azoriusModule.moduleAddress), + client: publicClient, + }); + + const azoriusContract = fractalAzoriusMasterCopyContract.asProvider.attach( + azoriusModuleContract.address, + ); + let ozLinearVotingContractAddress: string | undefined; + let erc721LinearVotingContractAddress: string | undefined; + let votesTokenContractAddress: string | undefined; + let underlyingTokenAddress: string | undefined; + let lockReleaseContractAddress: string | undefined; + + // @dev assumes the first strategy is the voting contract + const votingStrategyAddress = (await azoriusContract.getStrategies(SENTINEL_ADDRESS, 0))[1]; + + const masterCopyData = await getZodiacModuleProxyMasterCopyData( + getAddress(votingStrategyAddress), + ); + const isOzLinearVoting = masterCopyData.isOzLinearVoting; + const isOzLinearVotingERC721 = masterCopyData.isOzLinearVotingERC721; + + if (isOzLinearVoting) { + ozLinearVotingContractAddress = votingStrategyAddress; + + const ozLinearVotingContract = getContract({ + abi: LinearERC20VotingAbi, + address: getAddress(ozLinearVotingContractAddress), + client: publicClient, + }); + const govTokenAddress = await ozLinearVotingContract.read.governanceToken(); + + const possibleERC20Wrapper = getContract({ + abi: VotesERC20WrapperAbi, + address: getAddress(govTokenAddress), + client: publicClient, + }); + + underlyingTokenAddress = await possibleERC20Wrapper.read.underlying().catch(() => { + // if the underlying token is not an ERC20Wrapper, this will throw an error, + // so we catch it and return undefined + return undefined; + }); + const possibleLockRelease = getContract({ + address: getAddress(govTokenAddress), + abi: LockReleaseAbi, + client: { public: publicClient }, + }); + + let lockedTokenAddress = undefined; + try { + lockedTokenAddress = await possibleLockRelease.read.token(); + } catch { + // no-op + // if the underlying token is not an ERC20Wrapper, this will throw an error, + // so we catch it and do nothing } - if (votesTokenContractAddress || erc721LinearVotingContractAddress) { - action.dispatch({ - type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, - payload: { - ozLinearVotingContractAddress, - erc721LinearVotingContractAddress, - azoriusContractAddress: azoriusModuleContract.address, - votesTokenContractAddress, - underlyingTokenAddress, - lockReleaseContractAddress, - }, - }); + if (lockedTokenAddress) { + lockReleaseContractAddress = govTokenAddress; + // @dev if the underlying token is an ERC20Wrapper, we use the underlying token as the token contract + votesTokenContractAddress = lockedTokenAddress; + } else { + // @dev if the no underlying token, we use the governance token as the token contract + votesTokenContractAddress = govTokenAddress; } - // else this has no governance token and can be assumed is a multi-sig - } else { + } else if (isOzLinearVotingERC721) { + // @dev for use with the ERC721 voting contract + erc721LinearVotingContractAddress = votingStrategyAddress; + } + + if (votesTokenContractAddress || erc721LinearVotingContractAddress) { action.dispatch({ type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT, - payload: {}, + payload: { + ozLinearVotingContractAddress, + erc721LinearVotingContractAddress, + azoriusContractAddress: azoriusModuleContract.address, + votesTokenContractAddress, + underlyingTokenAddress, + lockReleaseContractAddress, + }, }); } + // else this has no governance token and can be assumed is a multi-sig }, [action, getZodiacModuleProxyMasterCopyData, baseContracts, fractalModules, publicClient]); useEffect(() => { diff --git a/src/hooks/DAO/proposal/useSubmitProposal.ts b/src/hooks/DAO/proposal/useSubmitProposal.ts index 58f8fc7789..6347997bfa 100644 --- a/src/hooks/DAO/proposal/useSubmitProposal.ts +++ b/src/hooks/DAO/proposal/useSubmitProposal.ts @@ -1,4 +1,3 @@ -import { Azorius } from '@fractal-framework/fractal-contracts'; import axios from 'axios'; import { useCallback, useMemo, useState } from 'react'; import { toast } from 'react-toastify'; @@ -9,8 +8,11 @@ import { parseAbiParameters, isHex, encodeFunctionData, + getContract, + Address, } from 'viem'; -import { useWalletClient } from 'wagmi'; +import { usePublicClient, useWalletClient } from 'wagmi'; +import AzoriusAbi from '../../../assets/abi/Azorius'; import MultiSendCallOnlyAbi from '../../../assets/abi/MultiSendCallOnly'; import { ADDRESS_MULTISIG_METADATA, SENTINEL_ADDRESS } from '../../../constants/common'; import { buildSafeAPIPost, encodeMultiSend } from '../../../helpers'; @@ -18,7 +20,6 @@ import { logError } from '../../../helpers/errorLogging'; import { useFractal } from '../../../providers/App/AppProvider'; import useIPFSClient from '../../../providers/App/hooks/useIPFSClient'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; -import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { MetaTransaction, ProposalExecuteData, CreateProposalMetadata } from '../../../types'; import { buildSafeApiUrl, getAzoriusModuleFromModules } from '../../../utils'; @@ -33,32 +34,19 @@ interface ISubmitProposal { failedToastMessage: string; successToastMessage: string; successCallback?: (addressPrefix: string, daoAddress: string) => void; - /** - * @param safeAddress - provided address of DAO to which proposal will be submitted - */ safeAddress?: string; } interface ISubmitAzoriusProposal extends ISubmitProposal { - /** - * @param azoriusContract - provided Azorius contract. - * Depending on safeAddress it's either picked from global context - * either grabbed from the safe info from Safe API. - */ - azoriusContract: Azorius; - /** - * @param votingStrategyAddress - provided voting strategy address for proposal submission. - * Depending on safeAddress it's either picked from global context - * either grabbed from the safe info from Safe API & provided Azorius contract. - */ + azoriusAddress: Address; votingStrategyAddress: string; } export default function useSubmitProposal() { const [pendingCreateTx, setPendingCreateTx] = useState(false); const loadDAOProposals = useDAOProposals(); - const signer = useEthersSigner(); const { data: walletClient } = useWalletClient(); + const publicClient = usePublicClient(); const { node: { safe, fractalModules }, @@ -68,16 +56,17 @@ export default function useSubmitProposal() { const safeAPI = useSafeAPI(); const globalAzoriusContract = useMemo(() => { - if (!signer) { - return undefined; - } const azoriusModule = getAzoriusModuleFromModules(fractalModules); - if (!azoriusModule) { - return undefined; + if (!azoriusModule || !walletClient) { + return; } - const moduleContract = azoriusModule.moduleContract as Azorius; - return moduleContract.connect(signer); - }, [fractalModules, signer]); + + return getContract({ + abi: AzoriusAbi, + address: getAddress(azoriusModule.moduleAddress), + client: walletClient, + }); + }, [fractalModules, walletClient]); const lookupModules = useFractalModules(); const signerOrProvider = useSignerOrProvider(); @@ -206,7 +195,7 @@ export default function useSubmitProposal() { const submitAzoriusProposal = useCallback( async ({ proposalData, - azoriusContract, + azoriusAddress, votingStrategyAddress, pendingToastMessage, successToastMessage, @@ -214,7 +203,7 @@ export default function useSubmitProposal() { failedToastMessage, safeAddress, }: ISubmitAzoriusProposal) => { - if (!proposalData) { + if (!proposalData || !walletClient || !publicClient) { return; } const toastId = toast(pendingToastMessage, { @@ -234,19 +223,26 @@ export default function useSubmitProposal() { operation: 0, })); + const azoriusContract = getContract({ + abi: AzoriusAbi, + address: azoriusAddress, + client: walletClient, + }); + // @todo: Implement voting strategy proposal selection when/if we will support multiple strategies on single Azorius instance - await ( - await azoriusContract.submitProposal( - votingStrategyAddress, - '0x', - transactions, - JSON.stringify({ - title: proposalData.metaData.title, - description: proposalData.metaData.description, - documentationUrl: proposalData.metaData.documentationUrl, - }), - ) - ).wait(); + const txHash = await azoriusContract.write.submitProposal([ + getAddress(votingStrategyAddress), + '0x', + transactions, + JSON.stringify({ + title: proposalData.metaData.title, + description: proposalData.metaData.description, + documentationUrl: proposalData.metaData.documentationUrl, + }), + ]); + + await publicClient.waitForTransactionReceipt({ hash: txHash }); + toast.dismiss(toastId); toast(successToastMessage); if (successCallback) { @@ -260,7 +256,7 @@ export default function useSubmitProposal() { setPendingCreateTx(false); } }, - [addressPrefix], + [addressPrefix, publicClient, walletClient], ); const submitProposal = useCallback( @@ -292,13 +288,17 @@ export default function useSubmitProposal() { successCallback, safeAddress, }); - } else { - const azoriusModuleContract = azoriusModule.moduleContract as Azorius; + } else if (walletClient) { + const azoriusModuleContract = getContract({ + abi: AzoriusAbi, + address: getAddress(azoriusModule.moduleAddress), + client: walletClient, + }); // @dev assumes the first strategy is the voting contract const votingStrategyAddress = ( - await azoriusModuleContract.getStrategies(SENTINEL_ADDRESS, 0) + await azoriusModuleContract.read.getStrategies([SENTINEL_ADDRESS, 0n]) )[1]; - submitAzoriusProposal({ + await submitAzoriusProposal({ proposalData, pendingToastMessage, successToastMessage, @@ -306,7 +306,7 @@ export default function useSubmitProposal() { nonce, successCallback, safeAddress, - azoriusContract: azoriusModule.moduleContract as Azorius, + azoriusAddress: getAddress(azoriusModule.moduleAddress), votingStrategyAddress, }); } @@ -335,22 +335,23 @@ export default function useSubmitProposal() { nonce, successCallback, votingStrategyAddress, - azoriusContract: globalAzoriusContract, + azoriusAddress: globalAzoriusContract.address, safeAddress: safe?.address, }); } } }, [ - globalAzoriusContract, + erc721LinearVotingContractAddress, freezeVotingContractAddress, - safe, + globalAzoriusContract, lookupModules, - submitMultisigProposal, ozLinearVotingContractAddress, - erc721LinearVotingContractAddress, - submitAzoriusProposal, + safe?.address, safeAPI, + submitAzoriusProposal, + submitMultisigProposal, + walletClient, ], ); diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index f4edf2e918..fc787d1b58 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -1,7 +1,7 @@ -import { Azorius } from '@fractal-framework/fractal-contracts'; import { useState, useEffect, useCallback } from 'react'; import { GetContractReturnType, PublicClient, erc721Abi, getAddress, getContract } from 'viem'; import { usePublicClient } from 'wagmi'; +import AzoriusAbi from '../../../assets/abi/Azorius'; import LinearERC721VotingAbi from '../../../assets/abi/LinearERC721Voting'; import { SENTINEL_ADDRESS } from '../../../constants/common'; import { useFractal } from '../../../providers/App/AppProvider'; @@ -74,11 +74,17 @@ export default function useUserERC721VotingTokens( const safeInfo = await safeAPI.getSafeInfo(getAddress(_safeAddress)); const safeModules = await lookupModules(safeInfo.modules); const azoriusModule = getAzoriusModuleFromModules(safeModules); - if (azoriusModule && azoriusModule.moduleContract) { - const azoriusContract = azoriusModule.moduleContract as Azorius; + + if (azoriusModule) { + const azoriusContract = getContract({ + abi: AzoriusAbi, + address: getAddress(azoriusModule.moduleAddress), + client: publicClient, + }); + // @dev assumes the first strategy is the voting contract const votingContractAddress = ( - await azoriusContract.getStrategies(SENTINEL_ADDRESS, 0) + await azoriusContract.read.getStrategies([SENTINEL_ADDRESS, 0n]) )[1]; votingContract = getContract({ abi: LinearERC721VotingAbi, diff --git a/src/hooks/DAO/useBuildDAOTx.ts b/src/hooks/DAO/useBuildDAOTx.ts index f4d317e33c..35613f5b6c 100644 --- a/src/hooks/DAO/useBuildDAOTx.ts +++ b/src/hooks/DAO/useBuildDAOTx.ts @@ -32,6 +32,7 @@ const useBuildDAOTx = () => { fractalModuleMasterCopy, linearVotingMasterCopy: linearERC20VotingMasterCopy, linearVotingERC721MasterCopy: linearERC721VotingMasterCopy, + fractalAzoriusMasterCopy: azoriusMasterCopy, }, } = useNetworkConfig(); @@ -55,7 +56,6 @@ const useBuildDAOTx = () => { return; } const { - fractalAzoriusMasterCopyContract, multisigFreezeGuardMasterCopyContract, azoriusFreezeGuardMasterCopyContract, freezeMultisigVotingMasterCopyContract, @@ -67,12 +67,11 @@ const useBuildDAOTx = () => { daoData.governance === GovernanceType.AZORIUS_ERC20 || daoData.governance === GovernanceType.AZORIUS_ERC721 ) { - if (!fractalAzoriusMasterCopyContract || !azoriusFreezeGuardMasterCopyContract) { + if (!azoriusFreezeGuardMasterCopyContract) { return; } azoriusContracts = { - fractalAzoriusMasterCopyContract: fractalAzoriusMasterCopyContract.asSigner, azoriusFreezeGuardMasterCopyContract: azoriusFreezeGuardMasterCopyContract.asSigner, }; } @@ -103,6 +102,7 @@ const useBuildDAOTx = () => { fractalModuleMasterCopy, linearERC20VotingMasterCopy, linearERC721VotingMasterCopy, + azoriusMasterCopy, parentAddress, parentTokenAddress, ); @@ -161,6 +161,7 @@ const useBuildDAOTx = () => { fractalModuleMasterCopy, linearERC20VotingMasterCopy, linearERC721VotingMasterCopy, + azoriusMasterCopy, ], ); diff --git a/src/hooks/DAO/useDeployAzorius.ts b/src/hooks/DAO/useDeployAzorius.ts index 420fed011b..360de264eb 100644 --- a/src/hooks/DAO/useDeployAzorius.ts +++ b/src/hooks/DAO/useDeployAzorius.ts @@ -38,6 +38,7 @@ const useDeployAzorius = () => { fractalModuleMasterCopy, linearVotingMasterCopy: linearERC20VotingMasterCopy, linearVotingERC721MasterCopy: linearERC721VotingMasterCopy, + fractalAzoriusMasterCopy: azoriusMasterCopy, }, addressPrefix, } = useNetworkConfig(); @@ -61,7 +62,6 @@ const useDeployAzorius = () => { return; } const { - fractalAzoriusMasterCopyContract, multisigFreezeGuardMasterCopyContract, azoriusFreezeGuardMasterCopyContract, freezeMultisigVotingMasterCopyContract, @@ -71,7 +71,6 @@ const useDeployAzorius = () => { let azoriusContracts: AzoriusContracts; azoriusContracts = { - fractalAzoriusMasterCopyContract: fractalAzoriusMasterCopyContract.asProvider, azoriusFreezeGuardMasterCopyContract: azoriusFreezeGuardMasterCopyContract.asProvider, }; @@ -101,6 +100,7 @@ const useDeployAzorius = () => { fractalModuleMasterCopy, linearERC20VotingMasterCopy, linearERC721VotingMasterCopy, + azoriusMasterCopy, undefined, undefined, ); @@ -172,6 +172,7 @@ const useDeployAzorius = () => { fractalModuleMasterCopy, linearERC20VotingMasterCopy, linearERC721VotingMasterCopy, + azoriusMasterCopy, ], ); diff --git a/src/hooks/utils/useCanUserSubmitProposal.ts b/src/hooks/utils/useCanUserSubmitProposal.ts index 9ac47054ac..64d067a4f6 100644 --- a/src/hooks/utils/useCanUserSubmitProposal.ts +++ b/src/hooks/utils/useCanUserSubmitProposal.ts @@ -1,7 +1,7 @@ -import { Azorius } from '@fractal-framework/fractal-contracts'; import { useState, useCallback, useEffect } from 'react'; import { getAddress, getContract } from 'viem'; import { usePublicClient } from 'wagmi'; +import AzoriusAbi from '../../assets/abi/Azorius'; import LinearERC20VotingAbi from '../../assets/abi/LinearERC20Voting'; import LinearERC721VotingAbi from '../../assets/abi/LinearERC721Voting'; import { SENTINEL_ADDRESS } from '../../constants/common'; @@ -45,11 +45,15 @@ export function useCanUserCreateProposal() { const safeModules = await lookupModules(safeInfo.modules); const azoriusModule = getAzoriusModuleFromModules(safeModules); - if (azoriusModule && azoriusModule.moduleContract) { - const azoriusContract = azoriusModule.moduleContract as Azorius; + if (azoriusModule) { + const azoriusContract = getContract({ + abi: AzoriusAbi, + address: getAddress(azoriusModule.moduleAddress), + client: publicClient, + }); // @dev assumes the first strategy is the voting contract const votingContractAddress = ( - await azoriusContract.getStrategies(SENTINEL_ADDRESS, 0) + await azoriusContract.read.getStrategies([SENTINEL_ADDRESS, 0n]) )[1]; const votingContract = getContract({ abi: LinearERC20VotingAbi, diff --git a/src/hooks/utils/useMasterCopy.ts b/src/hooks/utils/useMasterCopy.ts index b1dcc8cbf7..e938b8af8e 100644 --- a/src/hooks/utils/useMasterCopy.ts +++ b/src/hooks/utils/useMasterCopy.ts @@ -16,6 +16,7 @@ export function useMasterCopy() { linearVotingMasterCopy, linearVotingERC721MasterCopy, fractalModuleMasterCopy, + fractalAzoriusMasterCopy, }, } = useNetworkConfig(); const publicClient = usePublicClient(); @@ -45,9 +46,8 @@ export function useMasterCopy() { [baseContracts], ); const isAzorius = useCallback( - (masterCopyAddress: Address) => - masterCopyAddress === baseContracts?.fractalAzoriusMasterCopyContract.asProvider.address, - [baseContracts], + (masterCopyAddress: Address) => masterCopyAddress === fractalAzoriusMasterCopy, + [fractalAzoriusMasterCopy], ); const isFractalModule = useCallback( (masterCopyAddress: Address) => masterCopyAddress === fractalModuleMasterCopy, diff --git a/src/models/AzoriusTxBuilder.ts b/src/models/AzoriusTxBuilder.ts index c73070d48d..3b02928277 100644 --- a/src/models/AzoriusTxBuilder.ts +++ b/src/models/AzoriusTxBuilder.ts @@ -9,11 +9,11 @@ import { parseAbiParameters, getAddress, isAddress, - isHex, encodeFunctionData, PublicClient, getContract, } from 'viem'; +import AzoriusAbi from '../assets/abi/Azorius'; import ERC20ClaimAbi from '../assets/abi/ERC20Claim'; import GnosisSafeL2Abi from '../assets/abi/GnosisSafeL2'; import LinearERC20VotingAbi from '../assets/abi/LinearERC20Voting'; @@ -61,6 +61,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { private erc20ClaimMasterCopyAddress: Address; private linearERC20VotingMasterCopyAddress: Address; private linearERC721VotingMasterCopyAddress: Address; + private azoriusMasterCopyAddress: Address; private tokenNonce: bigint; private strategyNonce: bigint; @@ -81,6 +82,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { erc20ClaimMasterCopyAddress: Address, linearERC20VotingMasterCopyAddress: Address, linearERC721VotingMasterCopyAddress: Address, + azoriusMasterCopyAddress: Address, parentAddress?: Address, parentTokenAddress?: Address, ) { @@ -108,6 +110,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { this.erc20ClaimMasterCopyAddress = erc20ClaimMasterCopyAddress; this.linearERC20VotingMasterCopyAddress = linearERC20VotingMasterCopyAddress; this.linearERC721VotingMasterCopyAddress = linearERC721VotingMasterCopyAddress; + this.azoriusMasterCopyAddress = azoriusMasterCopyAddress; if (daoData.votingStrategyType === VotingStrategyType.LINEAR_ERC20) { daoData = daoData as AzoriusERC20DAO; @@ -254,11 +257,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { ModuleProxyFactoryAbi, this.moduleProxyFactoryAddress, 'deployModule', - [ - this.azoriusContracts!.fractalAzoriusMasterCopyContract.address, - this.encodedSetupAzoriusData, - this.azoriusNonce, - ], + [this.azoriusMasterCopyAddress, this.encodedSetupAzoriusData, this.azoriusNonce], 0, false, ); @@ -555,19 +554,13 @@ export class AzoriusTxBuilder extends BaseTxBuilder { ], ); - const encodedSetupAzoriusData = - this.azoriusContracts!.fractalAzoriusMasterCopyContract.interface.encodeFunctionData( - 'setUp', - [encodedInitAzoriusData], - ); - - if (!isHex(encodedSetupAzoriusData)) { - throw new Error('Error encoding setup azorius data'); - } + const encodedSetupAzoriusData = encodeFunctionData({ + abi: AzoriusAbi, + functionName: 'setUp', + args: [encodedInitAzoriusData], + }); - const azoriusByteCodeLinear = generateContractByteCodeLinear( - getAddress(this.azoriusContracts!.fractalAzoriusMasterCopyContract.address), - ); + const azoriusByteCodeLinear = generateContractByteCodeLinear(this.azoriusMasterCopyAddress); const azoriusSalt = generateSalt(encodedSetupAzoriusData, this.azoriusNonce); this.encodedSetupAzoriusData = encodedSetupAzoriusData; diff --git a/src/models/TxBuilderFactory.ts b/src/models/TxBuilderFactory.ts index 5fa528cd23..31a0826a0e 100644 --- a/src/models/TxBuilderFactory.ts +++ b/src/models/TxBuilderFactory.ts @@ -41,6 +41,7 @@ export class TxBuilderFactory extends BaseTxBuilder { private fractalModuleMasterCopyAddress: string; private linearERC20VotingMasterCopyAddress: string; private linearERC721VotingMasterCopyAddress: string; + private azoriusMasterCopyAddress: string; constructor( signerOrProvider: ethers.Signer | any, @@ -61,6 +62,7 @@ export class TxBuilderFactory extends BaseTxBuilder { fractalModuleMasterCopyAddress: string, linearERC20VotingMasterCopyAddress: string, linearERC721VotingMasterCopyAddress: string, + azoriusMasterCopyAddress: string, parentAddress?: string, parentTokenAddress?: string, ) { @@ -88,6 +90,7 @@ export class TxBuilderFactory extends BaseTxBuilder { this.fractalModuleMasterCopyAddress = fractalModuleMasterCopyAddress; this.linearERC20VotingMasterCopyAddress = linearERC20VotingMasterCopyAddress; this.linearERC721VotingMasterCopyAddress = linearERC721VotingMasterCopyAddress; + this.azoriusMasterCopyAddress = azoriusMasterCopyAddress; } public setSafeContract(safeAddress: Address) { @@ -194,6 +197,7 @@ export class TxBuilderFactory extends BaseTxBuilder { getAddress(this.erc20ClaimMasterCopyAddress), getAddress(this.linearERC20VotingMasterCopyAddress), getAddress(this.linearERC721VotingMasterCopyAddress), + getAddress(this.azoriusMasterCopyAddress), this.parentAddress ? getAddress(this.parentAddress) : undefined, this.parentTokenAddress ? getAddress(this.parentTokenAddress) : undefined, ); diff --git a/src/types/fractal.ts b/src/types/fractal.ts index b1d2841f0b..b6da31d3d7 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -1,5 +1,4 @@ import { - Azorius, AzoriusFreezeGuard, ERC20FreezeVoting, MultisigFreezeVoting, @@ -14,8 +13,7 @@ import { SafeCollectibleResponse, } from '@safe-global/safe-service-client'; import { Dispatch } from 'react'; -import { Address, GetContractReturnType, PublicClient } from 'viem'; -import FractalModuleAbi from '../assets/abi/FractalModule'; +import { Address } from 'viem'; import { FractalGovernanceActions } from '../providers/App/governance/action'; import { GovernanceContractActions } from '../providers/App/governanceContracts/action'; import { FractalGuardActions } from '../providers/App/guard/action'; @@ -235,10 +233,6 @@ export interface Node extends Omit {} export interface FractalModuleData { - moduleContract: - | Azorius - | GetContractReturnType - | undefined; moduleAddress: string; moduleType: FractalModuleType; } @@ -319,7 +313,6 @@ export interface NodeHierarchy { } export interface FractalContracts { - fractalAzoriusMasterCopyContract: ContractConnection; multisigFreezeGuardMasterCopyContract: ContractConnection; azoriusFreezeGuardMasterCopyContract: ContractConnection; freezeMultisigVotingMasterCopyContract: ContractConnection; diff --git a/src/types/strategyAzorius.ts b/src/types/strategyAzorius.ts index a81fe8b6c8..5d695add40 100644 --- a/src/types/strategyAzorius.ts +++ b/src/types/strategyAzorius.ts @@ -1,6 +1,5 @@ -import { Azorius, AzoriusFreezeGuard } from '@fractal-framework/fractal-contracts'; +import { AzoriusFreezeGuard } from '@fractal-framework/fractal-contracts'; export interface AzoriusContracts { - fractalAzoriusMasterCopyContract: Azorius; azoriusFreezeGuardMasterCopyContract: AzoriusFreezeGuard; }