diff --git a/src/components/pages/DaoDashboard/ERC20Claim.tsx b/src/components/pages/DaoDashboard/ERC20Claim.tsx index 1ef2d47c42..cf6fc49eb1 100644 --- a/src/components/pages/DaoDashboard/ERC20Claim.tsx +++ b/src/components/pages/DaoDashboard/ERC20Claim.tsx @@ -2,6 +2,9 @@ import { Alert, AlertTitle, Button, Flex, Text } from '@chakra-ui/react'; import { Alert as AlertIcon } from '@decent-org/fractal-ui'; import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { getAddress, getContract } from 'viem'; +import { usePublicClient, useWalletClient } from 'wagmi'; +import ERC20ClaimAbi from '../../../assets/abi/ERC20Claim'; import { useTransaction } from '../../../hooks/utils/useTransaction'; import { useFractal } from '../../../providers/App/AppProvider'; import { AzoriusGovernance } from '../../../types'; @@ -14,25 +17,32 @@ export function ERCO20Claim() { readOnly: { user }, } = useFractal(); const account = user.address; - const { tokenClaimContract, type } = governance; + const { tokenClaimContractAddress, type } = governance; const { t } = useTranslation(['dashboard', 'transaction']); - const [contractCall, pending] = useTransaction(); + const [, pending, contractCallViem] = useTransaction(); const azoriusGovernance = governance as AzoriusGovernance; + const publicClient = usePublicClient(); + const { data: walletClient } = useWalletClient(); const loadClaim = useCallback(async () => { - if (!tokenClaimContract || !type || !account) { + if (!tokenClaimContractAddress || !type || !account || !publicClient) { return; } - const claimableAmount = (await tokenClaimContract.getClaimAmount(account)).toBigInt(); + const tokenClaimContract = getContract({ + abi: ERC20ClaimAbi, + address: tokenClaimContractAddress, + client: publicClient, + }); + const claimableAmount = await tokenClaimContract.read.getClaimAmount([getAddress(account)]); setUserClaimable(claimableAmount); - }, [tokenClaimContract, type, account]); + }, [account, publicClient, tokenClaimContractAddress, type]); useEffect(() => { loadClaim(); }, [loadClaim]); const claimToken = async () => { - if (!tokenClaimContract || !azoriusGovernance.votesToken || !account) { + if (!tokenClaimContractAddress || !azoriusGovernance.votesToken || !account || !walletClient) { return; } const claimableString = formatCoin( @@ -41,8 +51,13 @@ export function ERCO20Claim() { azoriusGovernance.votesToken.decimals, azoriusGovernance.votesToken.symbol, ); - contractCall({ - contractFn: () => tokenClaimContract.claimTokens(account), + const tokenClaimContract = getContract({ + abi: ERC20ClaimAbi, + address: tokenClaimContractAddress, + client: walletClient, + }); + contractCallViem({ + contractFn: () => tokenClaimContract.write.claimTokens([getAddress(account)]), pendingMessage: t('pendingTokenClaim', { symbol: azoriusGovernance.votesToken.symbol, ns: 'transaction', diff --git a/src/hooks/DAO/loaders/governance/useERC20Claim.ts b/src/hooks/DAO/loaders/governance/useERC20Claim.ts index 0e16c201ec..129d61d955 100644 --- a/src/hooks/DAO/loaders/governance/useERC20Claim.ts +++ b/src/hooks/DAO/loaders/governance/useERC20Claim.ts @@ -1,10 +1,10 @@ import { useEffect, useCallback, useRef } from 'react'; import { getContract, getAddress } from 'viem'; import { usePublicClient } from 'wagmi'; +import ERC20ClaimAbi from '../../../../assets/abi/ERC20Claim'; import VotesERC20Abi from '../../../../assets/abi/VotesERC20'; 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; @@ -16,14 +16,12 @@ export function useERC20Claim() { governanceContracts: { votesTokenContractAddress }, action, } = useFractal(); - const baseContracts = useSafeContracts(); const publicClient = usePublicClient(); const loadTokenClaimContract = useCallback(async () => { - if (!baseContracts || !votesTokenContractAddress || !publicClient) { + if (!votesTokenContractAddress || !publicClient) { return; } - const { claimingMasterCopyContract } = baseContracts; const votesTokenContract = getContract({ abi: VotesERC20Abi, @@ -39,23 +37,27 @@ export function useERC20Claim() { return; } - const possibleTokenClaimContract = claimingMasterCopyContract.asProvider.attach( - getAddress(approvals[0].args.spender), - ); - const tokenClaimFilter = possibleTokenClaimContract.filters.ERC20ClaimCreated(); - const tokenClaimArray = await possibleTokenClaimContract - .queryFilter(tokenClaimFilter) + const possibleTokenClaimContract = getContract({ + abi: ERC20ClaimAbi, + address: getAddress(approvals[0].args.spender), + client: publicClient, + }); + + const tokenClaimArray = await possibleTokenClaimContract.getEvents + .ERC20ClaimCreated() .catch(() => []); - if (!tokenClaimArray.length || tokenClaimArray[0].args[1] === votesTokenContractAddress) { + const childToken = tokenClaimArray[0].args.childToken; + + if (!tokenClaimArray.length || !childToken || childToken === votesTokenContractAddress) { return; } // action to governance action.dispatch({ type: FractalGovernanceAction.SET_CLAIMING_CONTRACT, - payload: possibleTokenClaimContract, + payload: getAddress(approvals[0].args.spender), }); - }, [action, baseContracts, publicClient, votesTokenContractAddress]); + }, [action, publicClient, votesTokenContractAddress]); const loadKey = useRef(); diff --git a/src/hooks/DAO/useBuildDAOTx.ts b/src/hooks/DAO/useBuildDAOTx.ts index 4806daa218..20db2302d4 100644 --- a/src/hooks/DAO/useBuildDAOTx.ts +++ b/src/hooks/DAO/useBuildDAOTx.ts @@ -29,6 +29,7 @@ const useBuildDAOTx = () => { safe: safeSingleton, zodiacModuleProxyFactory, multisend: multiSendCallOnly, + claimingMasterCopy: erc20ClaimMasterCopy, }, } = useNetworkConfig(); @@ -61,7 +62,6 @@ const useBuildDAOTx = () => { freezeMultisigVotingMasterCopyContract, freezeERC20VotingMasterCopyContract, freezeERC721VotingMasterCopyContract, - claimingMasterCopyContract, } = baseContracts; if ( @@ -77,8 +77,7 @@ const useBuildDAOTx = () => { if ( !fractalAzoriusMasterCopyContract || !linearVotingMasterCopyContract || - !azoriusFreezeGuardMasterCopyContract || - !claimingMasterCopyContract + !azoriusFreezeGuardMasterCopyContract ) { return; } @@ -88,7 +87,6 @@ const useBuildDAOTx = () => { linearVotingMasterCopyContract: linearVotingMasterCopyContract.asSigner, linearVotingERC721MasterCopyContract: linearVotingERC721MasterCopyContract.asSigner, azoriusFreezeGuardMasterCopyContract: azoriusFreezeGuardMasterCopyContract.asSigner, - claimingMasterCopyContract: claimingMasterCopyContract.asSigner, }; } @@ -115,6 +113,7 @@ const useBuildDAOTx = () => { safeSingleton, zodiacModuleProxyFactory, multiSendCallOnly, + erc20ClaimMasterCopy, parentAddress, parentTokenAddress, ); @@ -170,6 +169,7 @@ const useBuildDAOTx = () => { safeSingleton, zodiacModuleProxyFactory, multiSendCallOnly, + erc20ClaimMasterCopy, ], ); diff --git a/src/hooks/DAO/useDeployAzorius.ts b/src/hooks/DAO/useDeployAzorius.ts index 836fe5b999..7ac058fc6e 100644 --- a/src/hooks/DAO/useDeployAzorius.ts +++ b/src/hooks/DAO/useDeployAzorius.ts @@ -34,6 +34,7 @@ const useDeployAzorius = () => { safe: safeSingleton, zodiacModuleProxyFactory, multisend: multiSendCallOnly, + claimingMasterCopy: erc20ClaimMasterCopy, }, addressPrefix, } = useNetworkConfig(); @@ -66,7 +67,6 @@ const useDeployAzorius = () => { freezeMultisigVotingMasterCopyContract, freezeERC20VotingMasterCopyContract, freezeERC721VotingMasterCopyContract, - claimingMasterCopyContract, } = baseContracts; let azoriusContracts: AzoriusContracts; @@ -75,7 +75,6 @@ const useDeployAzorius = () => { linearVotingMasterCopyContract: linearVotingMasterCopyContract.asProvider, linearVotingERC721MasterCopyContract: linearVotingERC721MasterCopyContract.asProvider, azoriusFreezeGuardMasterCopyContract: azoriusFreezeGuardMasterCopyContract.asProvider, - claimingMasterCopyContract: claimingMasterCopyContract.asProvider, }; const builderBaseContracts: BaseContracts = { @@ -101,6 +100,7 @@ const useDeployAzorius = () => { safeSingleton, zodiacModuleProxyFactory, multiSendCallOnly, + erc20ClaimMasterCopy, undefined, undefined, ); @@ -168,6 +168,7 @@ const useDeployAzorius = () => { safeSingleton, zodiacModuleProxyFactory, multiSendCallOnly, + erc20ClaimMasterCopy, ], ); diff --git a/src/hooks/safe/useSafeContracts.ts b/src/hooks/safe/useSafeContracts.ts index 55d1a669a8..0522311cc5 100644 --- a/src/hooks/safe/useSafeContracts.ts +++ b/src/hooks/safe/useSafeContracts.ts @@ -6,7 +6,6 @@ import { MultisigFreezeVoting__factory, LinearERC20Voting__factory, Azorius__factory, - ERC20Claim__factory, LinearERC721Voting__factory, ERC721FreezeVoting__factory, } from '@fractal-framework/fractal-contracts'; @@ -29,7 +28,6 @@ export default function useSafeContracts() { multisigFreezeVotingMasterCopy, erc20FreezeVotingMasterCopy, erc721FreezeVotingMasterCopy, - claimingMasterCopy, linearVotingERC721MasterCopy, }, } = useNetworkConfig(); @@ -89,11 +87,6 @@ export default function useSafeContracts() { asProvider: ERC721FreezeVoting__factory.connect(erc721FreezeVotingMasterCopy, provider), }; - const claimingMasterCopyContract = { - asSigner: ERC20Claim__factory.connect(claimingMasterCopy, signerOrProvider), - asProvider: ERC20Claim__factory.connect(claimingMasterCopy, provider), - }; - return { fractalAzoriusMasterCopyContract, linearVotingMasterCopyContract, @@ -103,7 +96,6 @@ export default function useSafeContracts() { freezeMultisigVotingMasterCopyContract, freezeERC20VotingMasterCopyContract, freezeERC721VotingMasterCopyContract, - claimingMasterCopyContract, linearVotingERC721MasterCopyContract, }; }, [ @@ -114,7 +106,6 @@ export default function useSafeContracts() { azoriusFreezeGuardMasterCopy, multisigFreezeVotingMasterCopy, erc20FreezeVotingMasterCopy, - claimingMasterCopy, linearVotingERC721MasterCopy, erc721FreezeVotingMasterCopy, signerOrProvider, diff --git a/src/models/AzoriusTxBuilder.ts b/src/models/AzoriusTxBuilder.ts index 975f59f5ac..e0e5c34017 100644 --- a/src/models/AzoriusTxBuilder.ts +++ b/src/models/AzoriusTxBuilder.ts @@ -20,6 +20,7 @@ import { encodeFunctionData, PublicClient, } from 'viem'; +import ERC20ClaimAbi from '../assets/abi/ERC20Claim'; import GnosisSafeL2Abi from '../assets/abi/GnosisSafeL2'; import ModuleProxyFactoryAbi from '../assets/abi/ModuleProxyFactory'; import VotesERC20Abi from '../assets/abi/VotesERC20'; @@ -61,6 +62,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { private votesERC20MasterCopyAddress: string; private moduleProxyFactoryAddress: Address; private multiSendCallOnlyAddress: Address; + private erc20ClaimMasterCopyAddress: Address; private tokenNonce: bigint; private strategyNonce: bigint; @@ -78,6 +80,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { votesERC20MasterCopyAddress: string, moduleProxyFactoryAddress: Address, multiSendCallOnlyAddress: Address, + erc20ClaimMasterCopyAddress: Address, parentAddress?: Address, parentTokenAddress?: Address, ) { @@ -102,6 +105,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { this.votesERC20MasterCopyAddress = votesERC20MasterCopyAddress; this.moduleProxyFactoryAddress = moduleProxyFactoryAddress; this.multiSendCallOnlyAddress = multiSendCallOnlyAddress; + this.erc20ClaimMasterCopyAddress = erc20ClaimMasterCopyAddress; if (daoData.votingStrategyType === VotingStrategyType.LINEAR_ERC20) { daoData = daoData as AzoriusERC20DAO; @@ -250,11 +254,7 @@ export class AzoriusTxBuilder extends BaseTxBuilder { ModuleProxyFactoryAbi, this.moduleProxyFactoryAddress, 'deployModule', - [ - this.azoriusContracts!.claimingMasterCopyContract.address, - this.encodedSetupTokenClaimData, - this.claimNonce, - ], + [this.erc20ClaimMasterCopyAddress, this.encodedSetupTokenClaimData, this.claimNonce], 0, false, ); @@ -404,20 +404,17 @@ export class AzoriusTxBuilder extends BaseTxBuilder { azoriusGovernanceDaoData.parentAllocationAmount, ], ); - const encodedSetupTokenClaimData = - this.azoriusContracts!.claimingMasterCopyContract.interface.encodeFunctionData('setUp', [ - encodedInitTokenData, - ]); - if (!isHex(encodedSetupTokenClaimData)) { - throw new Error('Error ecnoding setup token claim data'); - } + const encodedSetupTokenClaimData = encodeFunctionData({ + abi: ERC20ClaimAbi, + functionName: 'setUp', + args: [encodedInitTokenData], + }); + this.encodedSetupTokenClaimData = encodedSetupTokenClaimData; } private setPredictedTokenClaimAddress() { - const tokenByteCodeLinear = generateContractByteCodeLinear( - getAddress(this.azoriusContracts!.claimingMasterCopyContract.address), - ); + const tokenByteCodeLinear = generateContractByteCodeLinear(this.erc20ClaimMasterCopyAddress); const tokenSalt = generateSalt(this.encodedSetupTokenClaimData!, this.claimNonce); diff --git a/src/models/TxBuilderFactory.ts b/src/models/TxBuilderFactory.ts index 0d16e3ec99..c09100022d 100644 --- a/src/models/TxBuilderFactory.ts +++ b/src/models/TxBuilderFactory.ts @@ -37,6 +37,7 @@ export class TxBuilderFactory extends BaseTxBuilder { private gnosisSafeSingletonAddress: string; private moduleProxyFactoryAddress: string; private multiSendCallOnlyAddress: string; + private erc20ClaimMasterCopyAddress: string; constructor( signerOrProvider: ethers.Signer | any, @@ -53,6 +54,7 @@ export class TxBuilderFactory extends BaseTxBuilder { gnosisSafeSingletonAddress: string, moduleProxyFactoryAddress: string, multiSendCallOnlyAddress: string, + erc20ClaimMasterCopyAddress: string, parentAddress?: string, parentTokenAddress?: string, ) { @@ -76,6 +78,7 @@ export class TxBuilderFactory extends BaseTxBuilder { this.gnosisSafeSingletonAddress = gnosisSafeSingletonAddress; this.moduleProxyFactoryAddress = moduleProxyFactoryAddress; this.multiSendCallOnlyAddress = multiSendCallOnlyAddress; + this.erc20ClaimMasterCopyAddress = erc20ClaimMasterCopyAddress; } public setSafeContract(safeAddress: Address) { @@ -179,6 +182,7 @@ export class TxBuilderFactory extends BaseTxBuilder { this.votesERC20MasterCopyAddress, getAddress(this.moduleProxyFactoryAddress), getAddress(this.multiSendCallOnlyAddress), + getAddress(this.erc20ClaimMasterCopyAddress), this.parentAddress ? getAddress(this.parentAddress) : undefined, this.parentTokenAddress ? getAddress(this.parentTokenAddress) : undefined, ); diff --git a/src/providers/App/governance/action.ts b/src/providers/App/governance/action.ts index 7e1baab1d3..e8074b5428 100644 --- a/src/providers/App/governance/action.ts +++ b/src/providers/App/governance/action.ts @@ -1,4 +1,4 @@ -import { ERC20Claim } from '@fractal-framework/fractal-contracts'; +import { Address } from 'viem'; import { FractalProposal, ProposalVotesSummary, @@ -111,7 +111,10 @@ export type FractalGovernanceActions = type: FractalGovernanceAction.SET_TOKEN_ACCOUNT_DATA; payload: VotesData; } - | { type: FractalGovernanceAction.SET_CLAIMING_CONTRACT; payload: ERC20Claim } + | { + type: FractalGovernanceAction.SET_CLAIMING_CONTRACT; + payload: Address; + } | { type: FractalGovernanceAction.RESET_TOKEN_ACCOUNT_DATA; } diff --git a/src/types/fractal.ts b/src/types/fractal.ts index b8eeefbbb5..8235c72523 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -3,7 +3,6 @@ import { LinearERC20Voting, Azorius, AzoriusFreezeGuard, - ERC20Claim, ERC20FreezeVoting, MultisigFreezeVoting, MultisigFreezeGuard, @@ -284,18 +283,11 @@ 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; proposalTemplates?: ProposalTemplate[] | null; - tokenClaimContract?: ERC20Claim; + tokenClaimContractAddress?: Address; } export interface VotingStrategyAzorius extends VotingStrategy { @@ -335,7 +327,6 @@ export interface FractalContracts { freezeMultisigVotingMasterCopyContract: ContractConnection; freezeERC20VotingMasterCopyContract: ContractConnection; freezeERC721VotingMasterCopyContract: ContractConnection; - claimingMasterCopyContract: ContractConnection; } export type FractalProposal = AzoriusProposal | MultisigProposal | SnapshotProposal; diff --git a/src/types/strategyAzorius.ts b/src/types/strategyAzorius.ts index 135c059083..d140342323 100644 --- a/src/types/strategyAzorius.ts +++ b/src/types/strategyAzorius.ts @@ -2,7 +2,6 @@ import { Azorius, LinearERC20Voting, AzoriusFreezeGuard, - ERC20Claim, LinearERC721Voting, } from '@fractal-framework/fractal-contracts'; @@ -11,5 +10,4 @@ export interface AzoriusContracts { linearVotingMasterCopyContract: LinearERC20Voting; linearVotingERC721MasterCopyContract: LinearERC721Voting; azoriusFreezeGuardMasterCopyContract: AzoriusFreezeGuard; - claimingMasterCopyContract: ERC20Claim; }