Skip to content

Commit

Permalink
DRY "finding" strategy address into a hook
Browse files Browse the repository at this point in the history
  • Loading branch information
adamgall committed May 29, 2024
1 parent e0da54f commit 55f4dea
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 105 deletions.
1 change: 0 additions & 1 deletion src/components/ui/cards/DAOInfoCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export function DAOInfoCard() {
{!!user.address && (
<ManageDAOMenu
parentAddress={parentAddress}
fractalNode={node}
freezeGuard={guard}
guardContracts={guardContracts}
/>
Expand Down
48 changes: 13 additions & 35 deletions src/components/ui/menus/ManageDAO/ManageDAOMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import { ERC20FreezeVoting, MultisigFreezeVoting } from '@fractal-framework/frac
import { GearFine } from '@phosphor-icons/react';
import { useMemo, useCallback, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Address, getAddress, getContract } from 'viem';
import { usePublicClient } from 'wagmi';
import AzoriusAbi from '../../../../assets/abi/Azorius';
import { SENTINEL_ADDRESS } from '../../../../constants/common';
import { Address, getAddress } from 'viem';
import { DAO_ROUTES } from '../../../../constants/routes';
import {
isWithinFreezePeriod,
Expand All @@ -18,23 +15,21 @@ import useSafeContracts from '../../../../hooks/safe/useSafeContracts';
import useBlockTimestamp from '../../../../hooks/utils/useBlockTimestamp';
import { useCanUserCreateProposal } from '../../../../hooks/utils/useCanUserSubmitProposal';
import { useMasterCopy } from '../../../../hooks/utils/useMasterCopy';
import useVotingStrategyAddress from '../../../../hooks/utils/useVotingStrategyAddress';
import { useFractal } from '../../../../providers/App/AppProvider';
import { useNetworkConfig } from '../../../../providers/NetworkConfig/NetworkConfigProvider';
import {
FractalGuardContracts,
FractalNode,
FreezeGuard,
GovernanceType,
FreezeVotingType,
} from '../../../../types';
import { getAzoriusModuleFromModules } from '../../../../utils';
import { ModalType } from '../../modals/ModalProvider';
import { useFractalModal } from '../../modals/useFractalModal';
import { OptionMenu } from '../OptionMenu';

interface IManageDAOMenu {
parentAddress: Address | null;
fractalNode: FractalNode;
freezeGuard: FreezeGuard;
guardContracts: FractalGuardContracts;
}
Expand All @@ -48,52 +43,35 @@ interface IManageDAOMenu {
*
* All info for this menu should be supplied in the constructor.
*/
export function ManageDAOMenu({
parentAddress,
freezeGuard,
guardContracts,
fractalNode,
}: IManageDAOMenu) {
export function ManageDAOMenu({ parentAddress, freezeGuard, guardContracts }: IManageDAOMenu) {
const [governanceType, setGovernanceType] = useState(GovernanceType.MULTISIG);
const {
node: { safe },
node,
governance: { type },
} = useFractal();
const baseContracts = useSafeContracts();
const currentTime = BigInt(useBlockTimestamp());
const navigate = useNavigate();
const safeAddress = fractalNode.daoAddress;
const safeAddress = node.daoAddress;
const { getZodiacModuleProxyMasterCopyData } = useMasterCopy();
const { canUserCreateProposal } = useCanUserCreateProposal();
const { getUserERC721VotingTokens } = useUserERC721VotingTokens(safeAddress, undefined, false);
const { handleClawBack } = useClawBack({
parentAddress,
childSafeInfo: fractalNode,
childSafeInfo: node,
});
const publicClient = usePublicClient();
const votingContractAddress = useVotingStrategyAddress();

useEffect(() => {
const loadGovernanceType = async () => {
if (safe && safe.address && safe.address === safeAddress && type) {
if (node.safe && node.safe.address && node.safe.address === safeAddress && type) {
// Since safe.address (global scope DAO address) and safeAddress(Node provided to this component via props)
// are the same - we can simply grab governance type from global scope and avoid double-fetching
setGovernanceType(type);
} else {
if (fractalNode?.fractalModules) {
if (node?.fractalModules) {
let result = GovernanceType.MULTISIG;
const azoriusModule = getAzoriusModuleFromModules(fractalNode.fractalModules);

if (!!azoriusModule && publicClient) {
// @dev assumes the first strategy is the voting contract
const azoriusContract = getContract({
abi: AzoriusAbi,
address: getAddress(azoriusModule.moduleAddress),
client: publicClient,
});

const votingContractAddress = (
await azoriusContract.read.getStrategies([SENTINEL_ADDRESS, 0n])
)[1];
if (votingContractAddress) {
const masterCopyData = await getZodiacModuleProxyMasterCopyData(
getAddress(votingContractAddress),
);
Expand All @@ -112,12 +90,12 @@ export function ManageDAOMenu({

loadGovernanceType();
}, [
fractalNode?.fractalModules,
getZodiacModuleProxyMasterCopyData,
publicClient,
safe,
node?.fractalModules,
node.safe,
safeAddress,
type,
votingContractAddress,
]);
const { addressPrefix } = useNetworkConfig();

Expand Down
28 changes: 12 additions & 16 deletions src/hooks/DAO/loaders/useGovernanceContracts.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
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';
import { SENTINEL_ADDRESS } from '../../../constants/common';
import { useFractal } from '../../../providers/App/AppProvider';
import { GovernanceContractAction } from '../../../providers/App/governanceContracts/action';
import { getAzoriusModuleFromModules } from '../../../utils';
import useSafeContracts from '../../safe/useSafeContracts';
import { useMasterCopy } from '../../utils/useMasterCopy';
import useVotingStrategyAddress from '../../utils/useVotingStrategyAddress';

export const useGovernanceContracts = () => {
// tracks the current valid DAO address; helps prevent unnecessary calls
Expand All @@ -20,6 +19,8 @@ export const useGovernanceContracts = () => {
const { getZodiacModuleProxyMasterCopyData } = useMasterCopy();
const publicClient = usePublicClient();

const votingStrategyAddress = useVotingStrategyAddress();

const { fractalModules, isModulesLoaded, daoAddress } = node;

const loadGovernanceContracts = useCallback(async () => {
Expand All @@ -28,31 +29,20 @@ export const useGovernanceContracts = () => {
}
const azoriusModule = getAzoriusModuleFromModules(fractalModules);

if (!azoriusModule) {
if (!azoriusModule || !votingStrategyAddress) {
action.dispatch({
type: GovernanceContractAction.SET_GOVERNANCE_CONTRACT_ADDRESSES,
payload: {},
});
return;
}

const azoriusContract = getContract({
abi: AzoriusAbi,
address: getAddress(azoriusModule.moduleAddress),
client: publicClient,
});

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.read.getStrategies([SENTINEL_ADDRESS, 0n])
)[1];

const masterCopyData = await getZodiacModuleProxyMasterCopyData(
getAddress(votingStrategyAddress),
);
Expand Down Expand Up @@ -121,8 +111,14 @@ export const useGovernanceContracts = () => {
},
});
}
// else this has no governance token and can be assumed is a multi-sig
}, [action, getZodiacModuleProxyMasterCopyData, baseContracts, fractalModules, publicClient]);
}, [
action,
baseContracts,
fractalModules,
getZodiacModuleProxyMasterCopyData,
publicClient,
votingStrategyAddress,
]);

useEffect(() => {
if (currentValidAddress.current !== daoAddress && isModulesLoaded) {
Expand Down
19 changes: 7 additions & 12 deletions src/hooks/DAO/proposal/useSubmitProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
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 { ADDRESS_MULTISIG_METADATA } from '../../../constants/common';
import { buildSafeAPIPost, encodeMultiSend } from '../../../helpers';
import { logError } from '../../../helpers/errorLogging';
import { useFractal } from '../../../providers/App/AppProvider';
Expand All @@ -24,6 +24,7 @@ import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfig
import { MetaTransaction, ProposalExecuteData, CreateProposalMetadata } from '../../../types';
import { buildSafeApiUrl, getAzoriusModuleFromModules } from '../../../utils';
import useSignerOrProvider from '../../utils/useSignerOrProvider';
import useVotingStrategyAddress from '../../utils/useVotingStrategyAddress';
import { useFractalModules } from '../loaders/useFractalModules';
import { useDAOProposals } from '../loaders/useProposals';

Expand All @@ -48,6 +49,8 @@ export default function useSubmitProposal() {
const { data: walletClient } = useWalletClient();
const publicClient = usePublicClient();

const votingContractAddress = useVotingStrategyAddress();

const {
node: { safe, fractalModules },
guardContracts: { freezeVotingContractAddress },
Expand Down Expand Up @@ -288,16 +291,7 @@ export default function useSubmitProposal() {
successCallback,
safeAddress,
});
} 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.read.getStrategies([SENTINEL_ADDRESS, 0n])
)[1];
} else if (walletClient && votingContractAddress) {
await submitAzoriusProposal({
proposalData,
pendingToastMessage,
Expand All @@ -307,7 +301,7 @@ export default function useSubmitProposal() {
successCallback,
safeAddress,
azoriusAddress: getAddress(azoriusModule.moduleAddress),
votingStrategyAddress,
votingStrategyAddress: votingContractAddress,
});
}
} else {
Expand Down Expand Up @@ -351,6 +345,7 @@ export default function useSubmitProposal() {
safeAPI,
submitAzoriusProposal,
submitMultisigProposal,
votingContractAddress,
walletClient,
],
);
Expand Down
25 changes: 5 additions & 20 deletions src/hooks/DAO/proposal/useUserERC721VotingTokens.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
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';
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';
import useVotingStrategyAddress from '../../utils/useVotingStrategyAddress';

/**
* Retrieves list of ERC-721 voting tokens for the supplied `address`(aka `user.address`) param
Expand Down Expand Up @@ -40,10 +37,11 @@ export default function useUserERC721VotingTokens(
readOnly: { user },
} = useFractal();
const baseContracts = useSafeContracts();
const lookupModules = useFractalModules();
const safeAPI = useSafeAPI();
const publicClient = usePublicClient();

const votingContractAddress = useVotingStrategyAddress();

const azoriusGovernance = governance as AzoriusGovernance;
const { erc721Tokens } = azoriusGovernance;

Expand Down Expand Up @@ -71,21 +69,8 @@ export default function useUserERC721VotingTokens(

if (_safeAddress && daoAddress !== _safeAddress) {
// Means getting these for any safe, primary use case - calculating user voting weight for freeze voting
const safeInfo = await safeAPI.getSafeInfo(getAddress(_safeAddress));
const safeModules = await lookupModules(safeInfo.modules);
const azoriusModule = getAzoriusModuleFromModules(safeModules);

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.read.getStrategies([SENTINEL_ADDRESS, 0n])
)[1];
if (votingContractAddress) {
votingContract = getContract({
abi: LinearERC721VotingAbi,
address: getAddress(votingContractAddress),
Expand Down Expand Up @@ -219,11 +204,11 @@ export default function useUserERC721VotingTokens(
daoAddress,
erc721LinearVotingContractAddress,
erc721Tokens,
lookupModules,
publicClient,
safeAPI,
signerOrProvider,
user.address,
votingContractAddress,
],
);

Expand Down
Loading

0 comments on commit 55f4dea

Please sign in to comment.