Skip to content

Commit

Permalink
Remove votesTokenMasterCopyContract from useSafeContracts, fix downst…
Browse files Browse the repository at this point in the history
…ream typescript issues
  • Loading branch information
adamgall committed May 6, 2024
1 parent da58ac9 commit f907412
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 93 deletions.
26 changes: 18 additions & 8 deletions src/components/Proposals/ProposalSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { format } from 'date-fns';
import { formatInTimeZone } from 'date-fns-tz';
import { useMemo, useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { getAddress, getContract } from 'viem';
import { usePublicClient } from 'wagmi';
import VotesERC20Abi from '../../assets/abi/VotesERC20';
import { BACKGROUND_SEMI_TRANSPARENT } from '../../constants/common';
import useSafeContracts from '../../hooks/safe/useSafeContracts';
import useBlockTimestamp from '../../hooks/utils/useBlockTimestamp';
import { useFractal } from '../../providers/App/AppProvider';
import { AzoriusGovernance, AzoriusProposal, GovernanceType } from '../../types';
Expand Down Expand Up @@ -36,7 +38,7 @@ export default function ProposalSummary({
user: { votingWeight, address },
},
} = useFractal();
const baseContracts = useSafeContracts();

const azoriusGovernance = governance as AzoriusGovernance;
const { votesToken, type, erc721Tokens, votingStrategy } = azoriusGovernance;
const { t } = useTranslation(['proposal', 'common', 'navigation']);
Expand All @@ -59,21 +61,29 @@ export default function ProposalSummary({

const toggleShowVotingPower = () => setShowVotingPower(prevState => !prevState);

const publicClient = usePublicClient();

useEffect(() => {
async function loadProposalVotingWeight() {
if (address && baseContracts && votesToken) {
const tokenContract = baseContracts.votesTokenMasterCopyContract.asProvider.attach(
votesToken.address,
);
const pastVotingWeight = (await tokenContract.getPastVotes(address, startBlock)).toBigInt();
if (address && votesToken && publicClient) {
const tokenContract = getContract({
abi: VotesERC20Abi,
address: votesToken.address,
client: publicClient,
});

const pastVotingWeight = await tokenContract.read.getPastVotes([
getAddress(address),
startBlock,
]);
setProposalsERC20VotingWeight(
(pastVotingWeight / votesTokenDecimalsDenominator).toString(),
);
}
}

loadProposalVotingWeight();
}, [address, startBlock, votesTokenDecimalsDenominator, baseContracts, votesToken]);
}, [address, publicClient, startBlock, votesToken, votesTokenDecimalsDenominator]);

const isERC20 = type === GovernanceType.AZORIUS_ERC20;
const isERC721 = type === GovernanceType.AZORIUS_ERC721;
Expand Down
28 changes: 20 additions & 8 deletions src/hooks/DAO/loaders/governance/useERC20Claim.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { useEffect, useCallback, useRef } from 'react';
import { getContract, getAddress } from 'viem';
import { usePublicClient } from 'wagmi';
import VotesERC20Abi from '../../../../assets/abi/VotesERC20';
import { useFractal } from '../../../../providers/App/AppProvider';
import { FractalGovernanceAction } from '../../../../providers/App/governance/action';
import useSafeContracts from '../../../safe/useSafeContracts';
Expand All @@ -14,22 +17,30 @@ export function useERC20Claim() {
action,
} = useFractal();
const baseContracts = useSafeContracts();
const publicClient = usePublicClient();

const loadTokenClaimContract = useCallback(async () => {
if (!baseContracts || !votesTokenContractAddress) {
if (!baseContracts || !votesTokenContractAddress || !publicClient) {
return;
}
const { claimingMasterCopyContract } = baseContracts;

const votesTokenContract =
baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress);
const votesTokenContract = getContract({
abi: VotesERC20Abi,
address: getAddress(votesTokenContractAddress),
client: publicClient,
});

// TODO here be dark programming...

const approvalFilter = votesTokenContract.filters.Approval();
const approvals = await votesTokenContract.queryFilter(approvalFilter);
if (!approvals.length) {
const approvals = await votesTokenContract.getEvents.Approval();

if (approvals.length === 0 || !approvals[0].args.spender) {
return;
}

const possibleTokenClaimContract = claimingMasterCopyContract.asProvider.attach(
approvals[0].args[1],
getAddress(approvals[0].args.spender),
);
const tokenClaimFilter = possibleTokenClaimContract.filters.ERC20ClaimCreated();
const tokenClaimArray = await possibleTokenClaimContract
Expand All @@ -44,7 +55,8 @@ export function useERC20Claim() {
type: FractalGovernanceAction.SET_CLAIMING_CONTRACT,
payload: possibleTokenClaimContract,
});
}, [baseContracts, votesTokenContractAddress, action]);
}, [action, baseContracts, publicClient, votesTokenContractAddress]);

const loadKey = useRef<string>();

useEffect(() => {
Expand Down
139 changes: 87 additions & 52 deletions src/hooks/DAO/loaders/governance/useERC20LinearToken.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useCallback, useEffect, useRef } from 'react';
import { getAddress } from 'viem';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { getAddress, getContract } from 'viem';
import { usePublicClient } from 'wagmi';
import VotesERC20Abi from '../../../../assets/abi/VotesERC20';
import { useFractal } from '../../../../providers/App/AppProvider';
import { FractalGovernanceAction } from '../../../../providers/App/governance/action';
import useSafeContracts from '../../../safe/useSafeContracts';

export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) => {
const isTokenLoaded = useRef(false);
Expand All @@ -14,65 +15,84 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) =
readOnly: { user },
} = useFractal();
const account = user.address;
const baseContracts = useSafeContracts();
const publicClient = usePublicClient();

const tokenContract = useMemo(() => {
if (!votesTokenContractAddress || !publicClient) {
return;
}

return getContract({
abi: VotesERC20Abi,
address: getAddress(votesTokenContractAddress),
client: publicClient,
});
}, [publicClient, votesTokenContractAddress]);

const underlyingTokenContract = useMemo(() => {
if (!underlyingTokenAddress || !publicClient) {
return;
}

return getContract({
abi: VotesERC20Abi,
address: getAddress(underlyingTokenAddress),
client: publicClient,
});
}, [publicClient, underlyingTokenAddress]);

const loadERC20Token = useCallback(async () => {
if (!votesTokenContractAddress || !baseContracts) {
if (!tokenContract) {
return;
}
const tokenContract =
baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress);

const [tokenName, tokenSymbol, tokenDecimals, totalSupply] = await Promise.all([
tokenContract.name(),
tokenContract.symbol(),
tokenContract.decimals(),
(await tokenContract.totalSupply()).toBigInt(),
tokenContract.read.name(),
tokenContract.read.symbol(),
tokenContract.read.decimals(),
await tokenContract.read.totalSupply(),
]);
const tokenData = {
name: tokenName,
symbol: tokenSymbol,
decimals: tokenDecimals,
address: getAddress(votesTokenContractAddress),
address: tokenContract.address,
totalSupply,
};
isTokenLoaded.current = true;
action.dispatch({ type: FractalGovernanceAction.SET_TOKEN_DATA, payload: tokenData });
}, [votesTokenContractAddress, action, baseContracts]);
}, [tokenContract, action]);

const loadUnderlyingERC20Token = useCallback(async () => {
if (!underlyingTokenAddress || !baseContracts) {
if (!underlyingTokenContract) {
return;
}
const tokenContract =
baseContracts.votesTokenMasterCopyContract.asProvider.attach(underlyingTokenAddress);

const [tokenName, tokenSymbol] = await Promise.all([
tokenContract.name(),
tokenContract.symbol(),
underlyingTokenContract.read.name(),
underlyingTokenContract.read.symbol(),
]);
const tokenData = {
name: tokenName,
symbol: tokenSymbol,
address: getAddress(underlyingTokenAddress),
address: underlyingTokenContract.address,
};
action.dispatch({
type: FractalGovernanceAction.SET_UNDERLYING_TOKEN_DATA,
payload: tokenData,
});
}, [underlyingTokenAddress, action, baseContracts]);
}, [underlyingTokenContract, action]);

const loadERC20TokenAccountData = useCallback(async () => {
if (!votesTokenContractAddress || !account || !baseContracts) {
if (!account || !tokenContract) {
action.dispatch({ type: FractalGovernanceAction.RESET_TOKEN_ACCOUNT_DATA });
return;
}
const tokenContract =
baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress);
// @todo We could probably save on some requests here.

const [tokenBalance, tokenDelegatee, tokenVotingWeight] = await Promise.all([
(await tokenContract.balanceOf(account)).toBigInt(),
tokenContract.delegates(account),
(await tokenContract.getVotes(account)).toBigInt(),
tokenContract.read.balanceOf([getAddress(account)]),
tokenContract.read.delegates([getAddress(account)]),
tokenContract.read.getVotes([getAddress(account)]),
]);

const tokenAccountData = {
Expand All @@ -85,7 +105,7 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) =
type: FractalGovernanceAction.SET_TOKEN_ACCOUNT_DATA,
payload: tokenAccountData,
});
}, [votesTokenContractAddress, action, account, baseContracts]);
}, [account, tokenContract, action]);

useEffect(() => {
if (
Expand All @@ -100,49 +120,64 @@ export const useERC20LinearToken = ({ onMount = true }: { onMount?: boolean }) =
}, [account, votesTokenContractAddress, onMount, loadERC20TokenAccountData]);

useEffect(() => {
if (!votesTokenContractAddress || !onMount || !baseContracts) {
if (!onMount || !tokenContract || !account) {
return;
}
const tokenContract =
baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress);

const delegateVotesChangedfilter = tokenContract.filters.DelegateVotesChanged();
tokenContract.on(delegateVotesChangedfilter, loadERC20TokenAccountData);
const unwatch = tokenContract.watchEvent.DelegateVotesChanged(
{ delegate: getAddress(account) },
{ onLogs: loadERC20TokenAccountData },
);

return () => {
tokenContract.off(delegateVotesChangedfilter, loadERC20TokenAccountData);
unwatch();
};
}, [votesTokenContractAddress, loadERC20TokenAccountData, onMount, baseContracts]);
}, [loadERC20TokenAccountData, onMount, tokenContract, account]);

useEffect(() => {
if (!votesTokenContractAddress || !onMount || !baseContracts) {
if (!tokenContract || !onMount || !account) {
return;
}
const tokenContract =
baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress);
const delegateChangedfilter = tokenContract.filters.DelegateChanged();
tokenContract.on(delegateChangedfilter, loadERC20TokenAccountData);

const unwatchDelegator = tokenContract.watchEvent.DelegateChanged(
{ delegator: getAddress(account) },
{ onLogs: loadERC20TokenAccountData },
);
const unwatchFromDelegate = tokenContract.watchEvent.DelegateChanged(
{ fromDelegate: getAddress(account) },
{ onLogs: loadERC20TokenAccountData },
);
const unwatchToDelegate = tokenContract.watchEvent.DelegateChanged(
{ toDelegate: getAddress(account) },
{ onLogs: loadERC20TokenAccountData },
);

return () => {
tokenContract.off(delegateChangedfilter, loadERC20TokenAccountData);
unwatchDelegator();
unwatchFromDelegate();
unwatchToDelegate();
};
}, [votesTokenContractAddress, loadERC20TokenAccountData, onMount, baseContracts]);
}, [account, loadERC20TokenAccountData, onMount, tokenContract]);

useEffect(() => {
if (!votesTokenContractAddress || !onMount || !baseContracts) {
if (!onMount || !account || !tokenContract) {
return;
}
const tokenContract =
baseContracts.votesTokenMasterCopyContract.asProvider.attach(votesTokenContractAddress);
const filterTo = tokenContract.filters.Transfer(null, account);
const filterFrom = tokenContract.filters.Transfer(account, null);
tokenContract.on(filterTo, loadERC20TokenAccountData);
tokenContract.on(filterFrom, loadERC20TokenAccountData);

const unwatchTo = tokenContract.watchEvent.Transfer(
{ from: getAddress(account) },
{ onLogs: loadERC20TokenAccountData },
);
const unwatchFrom = tokenContract.watchEvent.Transfer(
{ to: getAddress(account) },
{ onLogs: loadERC20TokenAccountData },
);

return () => {
tokenContract.off(filterTo, loadERC20TokenAccountData);
tokenContract.off(filterFrom, loadERC20TokenAccountData);
unwatchTo();
unwatchFrom();
};
}, [votesTokenContractAddress, account, onMount, loadERC20TokenAccountData, baseContracts]);
}, [account, loadERC20TokenAccountData, onMount, tokenContract]);

return { loadERC20Token, loadUnderlyingERC20Token, loadERC20TokenAccountData };
};
Loading

0 comments on commit f907412

Please sign in to comment.