From 5dca763d2bc3a5a121627b9957134929d169cc4e Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 8 Feb 2025 01:34:18 -0500 Subject: [PATCH 1/5] Refactor useUserERC721VotingTokens to streamline voting contract retrieval and enhance user voting token data handling --- .../DAO/proposal/useUserERC721VotingTokens.ts | 148 +++++++++++------- 1 file changed, 92 insertions(+), 56 deletions(-) diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index b16efea85..7bceaa15e 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -1,6 +1,6 @@ import { abis } from '@fractal-framework/fractal-contracts'; import { useCallback, useEffect, useState } from 'react'; -import { Address, GetContractReturnType, PublicClient, erc721Abi, getContract } from 'viem'; +import { Address, erc721Abi, getContract } from 'viem'; import { useAccount } from 'wagmi'; import { useFractal } from '../../../providers/App/AppProvider'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; @@ -40,6 +40,78 @@ export default function useUserERC721VotingTokens( const { getVotingStrategies } = useVotingStrategiesAddresses(); + const getLinearVotingContract = useCallback( + (_address: Address) => { + return getContract({ + abi: abis.LinearERC721Voting, + address: _address, + client: publicClient, + }); + }, + [publicClient], + ); + + const getLinearVotingContractWithHats = useCallback( + (_address: Address) => { + return getContract({ + abi: abis.LinearERC721VotingWithHatsProposalCreation, + address: _address, + client: publicClient, + }); + }, + [publicClient], + ); + + // Means getting these for any safe, primary use case - calculating user voting weight for freeze voting + const getUserVotingTokenData = useCallback( + async (_safeAddress: Address) => { + const votingStrategies = await getVotingStrategies(_safeAddress); + if (votingStrategies) { + const votingStrategy = votingStrategies.find( + strategy => + strategy.isLinearVotingErc721 || strategy.isLinearVotingErc721WithHatsProposalCreation, + ); + if (votingStrategy) { + const linear721VotingAddress = votingStrategy.strategyAddress; + const votingContract = votingStrategy.isLinearVotingErc721 + ? getLinearVotingContract(linear721VotingAddress) + : getLinearVotingContractWithHats(linear721VotingAddress); + + const addresses = await votingContract.read.getAllTokenAddresses(); + const governanceTokens = await Promise.all( + addresses.map(async tokenAddress => { + if (!votingContract) { + throw new Error('Voting contract is undefined'); + } + + const tokenContract = getContract({ + abi: erc721Abi, + address: tokenAddress, + client: publicClient, + }); + + const [votingWeight, name, symbol] = await Promise.all([ + votingContract.read.getTokenWeight([tokenAddress]), + tokenContract.read.name(), + tokenContract.read.symbol(), + ]); + + return { name, symbol, address: tokenAddress, votingWeight }; + }), + ); + return { + isLinearVotingErc721: votingStrategy.isLinearVotingErc721, + isLinearVotingErc721WithHatsProposalCreation: + votingStrategy.isLinearVotingErc721WithHatsProposalCreation, + governanceTokens, + }; + } + } + return undefined; + }, + [getLinearVotingContract, getLinearVotingContractWithHats, getVotingStrategies, publicClient], + ); + const azoriusGovernance = governance as AzoriusGovernance; const { erc721Tokens } = azoriusGovernance; @@ -54,9 +126,7 @@ export default function useUserERC721VotingTokens( const userERC721Tokens = new Map>(); let governanceTokens = erc721Tokens; - let votingContract: - | GetContractReturnType - | undefined; + let votingType: 'erc721' | 'erc721WithHats'; if (!globalContextSafeAddress || !safeAPI) { return { @@ -68,55 +138,18 @@ export default function useUserERC721VotingTokens( } if (_safeAddress && globalContextSafeAddress !== _safeAddress) { - // Means getting these for any safe, primary use case - calculating user voting weight for freeze voting - const votingStrategies = await getVotingStrategies(_safeAddress); - if (votingStrategies) { - const votingStrategyAddress = votingStrategies.find( - strategy => - strategy.isLinearVotingErc721 || - strategy.isLinearVotingErc721WithHatsProposalCreation, - )?.strategyAddress; - if (votingStrategyAddress) { - votingContract = getContract({ - abi: abis.LinearERC721Voting, - address: votingStrategyAddress, - client: publicClient, - }); - const addresses = await votingContract.read.getAllTokenAddresses(); - governanceTokens = await Promise.all( - addresses.map(async tokenAddress => { - if (!votingContract) { - throw new Error('Voting contract is undefined'); - } - - const tokenContract = getContract({ - abi: erc721Abi, - address: tokenAddress, - client: publicClient, - }); - - const [votingWeight, name, symbol] = await Promise.all([ - votingContract.read.getTokenWeight([tokenAddress]), - tokenContract.read.name(), - tokenContract.read.symbol(), - ]); - - return { name, symbol, address: tokenAddress, votingWeight }; - }), - ); - } + const userVotingTokenData = await getUserVotingTokenData(_safeAddress); + if (userVotingTokenData) { + governanceTokens = userVotingTokenData.governanceTokens; + votingType = userVotingTokenData.isLinearVotingErc721 ? 'erc721' : 'erc721WithHats'; } + } else if (linearVotingErc721Address) { + votingType = 'erc721'; + } else if (!linearVotingErc721Address) { + votingType = 'erc721WithHats'; } - if (linearVotingErc721Address && !votingContract) { - votingContract = getContract({ - abi: abis.LinearERC721Voting, - address: linearVotingErc721Address, - client: publicClient, - }); - } - - if (!governanceTokens || !votingContract || !user.address) { + if (!governanceTokens || !user.address) { return { totalVotingTokenAddresses: totalTokenAddresses, totalVotingTokenIds: totalTokenIds, @@ -182,9 +215,10 @@ export default function useUserERC721VotingTokens( // Maybe, if we will encounter need to wider support of ERC-1155 - we will bring it and improve this piece of crap as well :D await Promise.all( [...tokenIdsSet.values()].map(async tokenId => { - if (!votingContract) { - throw new Error('Voting contract is undefined'); - } + const votingContract = + votingType === 'erc721' + ? getLinearVotingContract(tokenAddress) + : getLinearVotingContractWithHats(tokenAddress); totalTokenAddresses.push(tokenAddress); totalTokenIds.push(tokenId); @@ -213,12 +247,14 @@ export default function useUserERC721VotingTokens( }, [ erc721Tokens, - getVotingStrategies, - publicClient, - safeAPI, globalContextSafeAddress, + safeAPI, linearVotingErc721Address, user.address, + getUserVotingTokenData, + publicClient, + getLinearVotingContract, + getLinearVotingContractWithHats, ], ); From 6768111081b4f36af7c892e49b418b71ee89dd07 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 8 Feb 2025 02:03:18 -0500 Subject: [PATCH 2/5] Refactor useUserERC721VotingTokens to extract getUserERC721Tokens for improved token retrieval and code clarity --- .../DAO/proposal/useUserERC721VotingTokens.ts | 111 ++++++++++-------- 1 file changed, 63 insertions(+), 48 deletions(-) diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index 7bceaa15e..249fc00b6 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -5,7 +5,7 @@ import { useAccount } from 'wagmi'; import { useFractal } from '../../../providers/App/AppProvider'; import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; import { useDaoInfoStore } from '../../../store/daoInfo/useDaoInfoStore'; -import { AzoriusGovernance } from '../../../types'; +import { AzoriusGovernance, ERC721TokenData } from '../../../types'; import useNetworkPublicClient from '../../useNetworkPublicClient'; import useVotingStrategiesAddresses from '../../utils/useVotingStrategiesAddresses'; @@ -30,7 +30,10 @@ export default function useUserERC721VotingTokens( const [remainingTokenAddresses, setRemainingTokenAddresses] = useState([]); const { - governanceContracts: { linearVotingErc721Address }, + governanceContracts: { + linearVotingErc721Address, + linearVotingErc721WithHatsWhitelistingAddress, + }, governance, } = useFractal(); const user = useAccount(); @@ -112,53 +115,12 @@ export default function useUserERC721VotingTokens( [getLinearVotingContract, getLinearVotingContractWithHats, getVotingStrategies, publicClient], ); - const azoriusGovernance = governance as AzoriusGovernance; - const { erc721Tokens } = azoriusGovernance; - - const globalContextSafeAddress = safe?.address; - - const getUserERC721VotingTokens = useCallback( - async (_safeAddress: Address | null, _proposalId: number | null) => { - const totalTokenAddresses: Address[] = []; - const totalTokenIds: string[] = []; - const tokenAddresses: Address[] = []; - const tokenIds: string[] = []; + const getUserERC721Tokens = useCallback( + async (userAddress: Address, governanceTokens: ERC721TokenData[] | undefined) => { const userERC721Tokens = new Map>(); - - let governanceTokens = erc721Tokens; - let votingType: 'erc721' | 'erc721WithHats'; - - if (!globalContextSafeAddress || !safeAPI) { - return { - totalVotingTokenAddresses: totalTokenAddresses, - totalVotingTokenIds: totalTokenIds, - remainingTokenAddresses: tokenAddresses, - remainingTokenIds: tokenIds, - }; + if (!governanceTokens || !userAddress) { + return userERC721Tokens; } - - if (_safeAddress && globalContextSafeAddress !== _safeAddress) { - const userVotingTokenData = await getUserVotingTokenData(_safeAddress); - if (userVotingTokenData) { - governanceTokens = userVotingTokenData.governanceTokens; - votingType = userVotingTokenData.isLinearVotingErc721 ? 'erc721' : 'erc721WithHats'; - } - } else if (linearVotingErc721Address) { - votingType = 'erc721'; - } else if (!linearVotingErc721Address) { - votingType = 'erc721WithHats'; - } - - if (!governanceTokens || !user.address) { - return { - totalVotingTokenAddresses: totalTokenAddresses, - totalVotingTokenIds: totalTokenIds, - remainingTokenAddresses: tokenAddresses, - remainingTokenIds: tokenIds, - }; - } - - const userAddress = user.address; await Promise.all( // Using `map` instead of `forEach` to simplify usage of `Promise.all` // and guarantee syncronous contractFn assignment @@ -202,6 +164,58 @@ export default function useUserERC721VotingTokens( } }), ); + return userERC721Tokens; + }, + [publicClient], + ); + + const azoriusGovernance = governance as AzoriusGovernance; + const { erc721Tokens } = azoriusGovernance; + + const globalContextSafeAddress = safe?.address; + + const getUserERC721VotingTokens = useCallback( + async (_safeAddress: Address | null, _proposalId: number | null) => { + const totalTokenAddresses: Address[] = []; + const totalTokenIds: string[] = []; + const tokenAddresses: Address[] = []; + const tokenIds: string[] = []; + + let governanceTokens = erc721Tokens; + let votingType: 'erc721' | 'erc721WithHats'; + + if (!globalContextSafeAddress || !safeAPI) { + return { + totalVotingTokenAddresses: totalTokenAddresses, + totalVotingTokenIds: totalTokenIds, + remainingTokenAddresses: tokenAddresses, + remainingTokenIds: tokenIds, + }; + } + + if (_safeAddress && globalContextSafeAddress !== _safeAddress) { + const userVotingTokenData = await getUserVotingTokenData(_safeAddress); + if (userVotingTokenData) { + governanceTokens = userVotingTokenData.governanceTokens; + votingType = userVotingTokenData.isLinearVotingErc721 ? 'erc721' : 'erc721WithHats'; + } + } else if (linearVotingErc721Address) { + votingType = 'erc721'; + } else if (linearVotingErc721WithHatsWhitelistingAddress) { + votingType = 'erc721WithHats'; + } + + if (!governanceTokens || !user.address) { + return { + totalVotingTokenAddresses: totalTokenAddresses, + totalVotingTokenIds: totalTokenIds, + remainingTokenAddresses: tokenAddresses, + remainingTokenIds: tokenIds, + }; + } + + const userAddress = user.address; + const userERC721Tokens = await getUserERC721Tokens(userAddress, governanceTokens); const tokenIdsSets = [...userERC721Tokens.values()]; const tokenAddressesKeys = [...userERC721Tokens.keys()]; @@ -250,9 +264,10 @@ export default function useUserERC721VotingTokens( globalContextSafeAddress, safeAPI, linearVotingErc721Address, + linearVotingErc721WithHatsWhitelistingAddress, user.address, + getUserERC721Tokens, getUserVotingTokenData, - publicClient, getLinearVotingContract, getLinearVotingContractWithHats, ], From a9425a84b6670161275bc53a17705f2e10a0a821 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 8 Feb 2025 02:14:22 -0500 Subject: [PATCH 3/5] Refactor useUserERC721VotingTokens to remove unnecessary dependency on linearVotingErc721Address in useEffect --- src/hooks/DAO/proposal/useUserERC721VotingTokens.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index 249fc00b6..6b9a20516 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -285,10 +285,10 @@ export default function useUserERC721VotingTokens( }, [getUserERC721VotingTokens, proposalId, safeAddress]); useEffect(() => { - if (loadOnMount && linearVotingErc721Address) { + if (loadOnMount) { loadUserERC721VotingTokens(); } - }, [loadUserERC721VotingTokens, loadOnMount, linearVotingErc721Address]); + }, [loadUserERC721VotingTokens, loadOnMount]); return { totalVotingTokenIds, From ddd3440c459ca1e942b271be881b3b24f555b785 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 8 Feb 2025 02:42:54 -0500 Subject: [PATCH 4/5] Refactor useUserERC721VotingTokens to consolidate voting contract retrieval and improve token data handling --- .../DAO/proposal/useUserERC721VotingTokens.ts | 158 ++++++++---------- 1 file changed, 72 insertions(+), 86 deletions(-) diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index 6b9a20516..5fcc28f5b 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -9,6 +9,15 @@ import { AzoriusGovernance, ERC721TokenData } from '../../../types'; import useNetworkPublicClient from '../../useNetworkPublicClient'; import useVotingStrategiesAddresses from '../../utils/useVotingStrategiesAddresses'; +const DEFAULT_RETURN = { + totalVotingTokenAddresses: [], + totalVotingTokenIds: [], + remainingTokenAddresses: [], + remainingTokenIds: [], +}; + +type ERC721VotingType = 'erc721' | 'erc721WithHats'; + /** * Retrieves list of ERC-721 voting tokens for the supplied `address`(aka `user.address`) param * @param {string|null} [proposalId] - Proposal ID. When it's provided - calculates `remainingTokenIds` and `remainingTokenAddresses` that user can use for voting on specific proposal. @@ -44,20 +53,12 @@ export default function useUserERC721VotingTokens( const { getVotingStrategies } = useVotingStrategiesAddresses(); const getLinearVotingContract = useCallback( - (_address: Address) => { + (_address: Address, _voting: ERC721VotingType) => { return getContract({ - abi: abis.LinearERC721Voting, - address: _address, - client: publicClient, - }); - }, - [publicClient], - ); - - const getLinearVotingContractWithHats = useCallback( - (_address: Address) => { - return getContract({ - abi: abis.LinearERC721VotingWithHatsProposalCreation, + abi: + _voting === 'erc721' + ? abis.LinearERC721Voting + : abis.LinearERC721VotingWithHatsProposalCreation, address: _address, client: publicClient, }); @@ -77,8 +78,8 @@ export default function useUserERC721VotingTokens( if (votingStrategy) { const linear721VotingAddress = votingStrategy.strategyAddress; const votingContract = votingStrategy.isLinearVotingErc721 - ? getLinearVotingContract(linear721VotingAddress) - : getLinearVotingContractWithHats(linear721VotingAddress); + ? getLinearVotingContract(linear721VotingAddress, 'erc721') + : getLinearVotingContract(linear721VotingAddress, 'erc721WithHats'); const addresses = await votingContract.read.getAllTokenAddresses(); const governanceTokens = await Promise.all( @@ -103,16 +104,17 @@ export default function useUserERC721VotingTokens( }), ); return { - isLinearVotingErc721: votingStrategy.isLinearVotingErc721, - isLinearVotingErc721WithHatsProposalCreation: - votingStrategy.isLinearVotingErc721WithHatsProposalCreation, + votingType: votingStrategy.isLinearVotingErc721 + ? 'erc721' + : ('erc721WithHats' as ERC721VotingType), governanceTokens, + linear721VotingAddress, }; } } return undefined; }, - [getLinearVotingContract, getLinearVotingContractWithHats, getVotingStrategies, publicClient], + [getLinearVotingContract, getVotingStrategies, publicClient], ); const getUserERC721Tokens = useCallback( @@ -176,100 +178,84 @@ export default function useUserERC721VotingTokens( const getUserERC721VotingTokens = useCallback( async (_safeAddress: Address | null, _proposalId: number | null) => { - const totalTokenAddresses: Address[] = []; - const totalTokenIds: string[] = []; - const tokenAddresses: Address[] = []; - const tokenIds: string[] = []; - let governanceTokens = erc721Tokens; - let votingType: 'erc721' | 'erc721WithHats'; - if (!globalContextSafeAddress || !safeAPI) { - return { - totalVotingTokenAddresses: totalTokenAddresses, - totalVotingTokenIds: totalTokenIds, - remainingTokenAddresses: tokenAddresses, - remainingTokenIds: tokenIds, - }; + // @dev global is set as defaults + let votingType: ERC721VotingType | undefined = linearVotingErc721Address + ? 'erc721' + : linearVotingErc721WithHatsWhitelistingAddress + ? 'erc721WithHats' + : undefined; + + let linearVotingAddress = + linearVotingErc721Address ?? linearVotingErc721WithHatsWhitelistingAddress; + + if (!globalContextSafeAddress || !safeAPI || !user.address) { + return DEFAULT_RETURN; } if (_safeAddress && globalContextSafeAddress !== _safeAddress) { const userVotingTokenData = await getUserVotingTokenData(_safeAddress); if (userVotingTokenData) { governanceTokens = userVotingTokenData.governanceTokens; - votingType = userVotingTokenData.isLinearVotingErc721 ? 'erc721' : 'erc721WithHats'; + votingType = userVotingTokenData.votingType; + linearVotingAddress = userVotingTokenData.linear721VotingAddress; } - } else if (linearVotingErc721Address) { - votingType = 'erc721'; - } else if (linearVotingErc721WithHatsWhitelistingAddress) { - votingType = 'erc721WithHats'; } - if (!governanceTokens || !user.address) { - return { - totalVotingTokenAddresses: totalTokenAddresses, - totalVotingTokenIds: totalTokenIds, - remainingTokenAddresses: tokenAddresses, - remainingTokenIds: tokenIds, - }; + if (!governanceTokens || !votingType || !linearVotingAddress) { + return DEFAULT_RETURN; } - const userAddress = user.address; + const userAddress = '0xAf3ee09F37ead9F28a05AeF0d09841BC9A6Fe8e9'; const userERC721Tokens = await getUserERC721Tokens(userAddress, governanceTokens); - const tokenIdsSets = [...userERC721Tokens.values()]; - const tokenAddressesKeys = [...userERC721Tokens.keys()]; - await Promise.all( - // Same here - tokenIdsSets.map(async (tokenIdsSet, setIndex) => { - const tokenAddress = tokenAddressesKeys[setIndex]; - // Damn, this is so ugly - // Probably using Moralis API might improve this - // But I also don't want to intruduce another API for this single thing - // Maybe, if we will encounter need to wider support of ERC-1155 - we will bring it and improve this piece of crap as well :D - await Promise.all( - [...tokenIdsSet.values()].map(async tokenId => { - const votingContract = - votingType === 'erc721' - ? getLinearVotingContract(tokenAddress) - : getLinearVotingContractWithHats(tokenAddress); - - totalTokenAddresses.push(tokenAddress); - totalTokenIds.push(tokenId); + const votingContract = + votingType === 'erc721' + ? getLinearVotingContract(linearVotingAddress, 'erc721') + : getLinearVotingContract(linearVotingAddress, 'erc721WithHats'); - if (_proposalId !== null) { - const tokenVoted = await votingContract.read.hasVoted([ - _proposalId, - tokenAddress, - BigInt(tokenId), - ]); - if (!tokenVoted) { - tokenAddresses.push(tokenAddress); - tokenIds.push(tokenId); - } - } - }), - ); - }), + const tokenDataPromises = Array.from(userERC721Tokens.entries()).flatMap( + ([tokenAddress, tokenIdsSet]) => { + return Array.from(tokenIdsSet).map(async tokenId => { + let hasVoted = false; + if (_proposalId !== null) { + hasVoted = await votingContract.read.hasVoted([ + _proposalId, + tokenAddress, + BigInt(tokenId), + ]); + } + return { tokenAddress, tokenId, hasVoted }; + }); + }, ); + + const tokenData = await Promise.all(tokenDataPromises); + return { - totalVotingTokenAddresses: totalTokenAddresses, - totalVotingTokenIds: totalTokenIds, - remainingTokenAddresses: tokenAddresses, - remainingTokenIds: tokenIds, + totalVotingTokenAddresses: tokenData.map(data => data.tokenAddress), + totalVotingTokenIds: tokenData.map(data => data.tokenId), + remainingTokenAddresses: + _proposalId !== null + ? tokenData.filter(data => !data.hasVoted).map(data => data.tokenAddress) + : [], + remainingTokenIds: + _proposalId !== null + ? tokenData.filter(data => !data.hasVoted).map(data => data.tokenId) + : [], }; }, [ erc721Tokens, - globalContextSafeAddress, - safeAPI, linearVotingErc721Address, linearVotingErc721WithHatsWhitelistingAddress, + globalContextSafeAddress, + safeAPI, user.address, getUserERC721Tokens, - getUserVotingTokenData, getLinearVotingContract, - getLinearVotingContractWithHats, + getUserVotingTokenData, ], ); From 2c858c9147582fb976abea7d97441e98040b2390 Mon Sep 17 00:00:00 2001 From: David Colon <38386583+Da-Colon@users.noreply.github.com> Date: Sat, 8 Feb 2025 12:42:13 -0500 Subject: [PATCH 5/5] remove hardcoded address --- src/hooks/DAO/proposal/useUserERC721VotingTokens.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts index 5fcc28f5b..0e857cbe2 100644 --- a/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts +++ b/src/hooks/DAO/proposal/useUserERC721VotingTokens.ts @@ -28,6 +28,7 @@ type ERC721VotingType = 'erc721' | 'erc721WithHats'; * @returns {string[]} `remainingTokenIds - list of tokens that `address` can use for proposal under `proposalId` param. This covers the case when user already voted for proposal but received more tokens, that weren't used in this proposal. * @returns {string[]} `remainingTokenAddresses` - same as `totalVotingTokenAddresses` - repeats contract address of NFT for each token ID in `remainingTokenIds` array. */ + export default function useUserERC721VotingTokens( safeAddress: Address | null, proposalId: string | null, @@ -207,7 +208,7 @@ export default function useUserERC721VotingTokens( return DEFAULT_RETURN; } - const userAddress = '0xAf3ee09F37ead9F28a05AeF0d09841BC9A6Fe8e9'; + const userAddress = user.address; const userERC721Tokens = await getUserERC721Tokens(userAddress, governanceTokens); const votingContract =