From 9749caf07e8d78f87bdcadfb40461b13c746518d Mon Sep 17 00:00:00 2001 From: Adam Gall Date: Mon, 6 May 2024 15:18:17 -0400 Subject: [PATCH] Merge pull request #1641 from decentdao/skip-usedelegatevote Skip useDelegateVote --- src/assets/abi/VotesERC20.ts | 757 +++++++++++++++++++++ src/components/ui/modals/DelegateModal.tsx | 30 +- src/hooks/DAO/useDelegateVote.ts | 3 +- 3 files changed, 780 insertions(+), 10 deletions(-) create mode 100644 src/assets/abi/VotesERC20.ts diff --git a/src/assets/abi/VotesERC20.ts b/src/assets/abi/VotesERC20.ts new file mode 100644 index 0000000000..9f8ba127d8 --- /dev/null +++ b/src/assets/abi/VotesERC20.ts @@ -0,0 +1,757 @@ +const VotesERC20Abi = [ + { + inputs: [], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'Approval', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'delegator', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'fromDelegate', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'toDelegate', + type: 'address', + }, + ], + name: 'DelegateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'delegate', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'previousBalance', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'newBalance', + type: 'uint256', + }, + ], + name: 'DelegateVotesChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint8', + name: 'version', + type: 'uint8', + }, + ], + name: 'Initialized', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferred', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'id', + type: 'uint256', + }, + ], + name: 'Snapshot', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, + { + inputs: [], + name: 'DOMAIN_SEPARATOR', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + ], + name: 'allowance', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'approve', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'balanceOf', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + { + internalType: 'uint256', + name: 'snapshotId', + type: 'uint256', + }, + ], + name: 'balanceOfAt', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'captureSnapShot', + outputs: [ + { + internalType: 'uint256', + name: 'snapId', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + { + internalType: 'uint32', + name: 'pos', + type: 'uint32', + }, + ], + name: 'checkpoints', + outputs: [ + { + components: [ + { + internalType: 'uint32', + name: 'fromBlock', + type: 'uint32', + }, + { + internalType: 'uint224', + name: 'votes', + type: 'uint224', + }, + ], + internalType: 'struct ERC20VotesUpgradeable.Checkpoint', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'decimals', + outputs: [ + { + internalType: 'uint8', + name: '', + type: 'uint8', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'subtractedValue', + type: 'uint256', + }, + ], + name: 'decreaseAllowance', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'delegatee', + type: 'address', + }, + ], + name: 'delegate', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'delegatee', + type: 'address', + }, + { + internalType: 'uint256', + name: 'nonce', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'expiry', + type: 'uint256', + }, + { + internalType: 'uint8', + name: 'v', + type: 'uint8', + }, + { + internalType: 'bytes32', + name: 'r', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 's', + type: 'bytes32', + }, + ], + name: 'delegateBySig', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'delegates', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + ], + name: 'getPastTotalSupply', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + ], + name: 'getPastVotes', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'getVotes', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'addedValue', + type: 'uint256', + }, + ], + name: 'increaseAllowance', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'name', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address', + }, + ], + name: 'nonces', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], + name: 'numCheckpoints', + outputs: [ + { + internalType: 'uint32', + name: '', + type: 'uint32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'owner', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { + internalType: 'uint8', + name: 'v', + type: 'uint8', + }, + { + internalType: 'bytes32', + name: 'r', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 's', + type: 'bytes32', + }, + ], + name: 'permit', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bytes', + name: 'initializeParams', + type: 'bytes', + }, + ], + name: 'setUp', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bytes4', + name: 'interfaceId', + type: 'bytes4', + }, + ], + name: 'supportsInterface', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'symbol', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'totalSupply', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'snapshotId', + type: 'uint256', + }, + ], + name: 'totalSupplyAt', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'transfer', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'from', + type: 'address', + }, + { + internalType: 'address', + name: 'to', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'transferFrom', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const; + +export default VotesERC20Abi; diff --git a/src/components/ui/modals/DelegateModal.tsx b/src/components/ui/modals/DelegateModal.tsx index 1dd792877d..abe4b5924f 100644 --- a/src/components/ui/modals/DelegateModal.tsx +++ b/src/components/ui/modals/DelegateModal.tsx @@ -2,13 +2,16 @@ import { Box, Button, Divider, Flex, SimpleGrid, Spacer, Text } from '@chakra-ui import { LabelWrapper } from '@decent-org/fractal-ui'; import { Field, FieldAttributes, Formik } from 'formik'; import { useTranslation } from 'react-i18next'; -import { zeroAddress, getAddress } from 'viem'; +import { zeroAddress, getAddress, getContract } from 'viem'; +import { useWalletClient } from 'wagmi'; import * as Yup from 'yup'; +import VotesERC20Abi from '../../../assets/abi/VotesERC20'; import { LockRelease__factory } from '../../../assets/typechain-types/dcnt'; import useDelegateVote from '../../../hooks/DAO/useDelegateVote'; import useSafeContracts from '../../../hooks/safe/useSafeContracts'; import { useValidationAddress } from '../../../hooks/schemas/common/useValidationAddress'; import useDisplayName from '../../../hooks/utils/useDisplayName'; +import { useTransaction } from '../../../hooks/utils/useTransaction'; import { useFractal } from '../../../providers/App/AppProvider'; import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { AzoriusGovernance, DecentGovernance } from '../../../types'; @@ -35,19 +38,28 @@ export function DelegateModal({ close }: { close: Function }) { const delegateeDisplayName = useDisplayName(azoriusGovernance?.votesToken?.delegatee); const lockedDelegateeDisplayName = useDisplayName(decentGovernance?.lockedVotesToken?.delegatee); const { delegateVote, contractCallPending } = useDelegateVote(); + const [, contractCallPendingViem, contractCallViem] = useTransaction(); const { addressValidationTest } = useValidationAddress(); + const { data: walletClient } = useWalletClient(); const submitDelegation = async (values: { address: string }) => { - if (!votesTokenContractAddress || !baseContracts) return; - let validAddress = values.address; + if (!votesTokenContractAddress || !baseContracts || !walletClient) return; + let validAddress = getAddress(values.address); if (couldBeENS(validAddress) && signer) { validAddress = getAddress(await signer.resolveName(values.address)); } - const votingTokenContract = - baseContracts.votesTokenMasterCopyContract.asSigner.attach(votesTokenContractAddress); - delegateVote({ - delegatee: validAddress, - votingTokenContract, + + const votingTokenContract = getContract({ + abi: VotesERC20Abi, + address: getAddress(votesTokenContractAddress), + client: walletClient, + }); + + contractCallViem({ + contractFn: () => votingTokenContract.write.delegate([validAddress]), + pendingMessage: t('pendingDelegateVote'), + failedMessage: t('failedDelegateVote'), + successMessage: t('successDelegateVote'), successCallback: () => { close(); }, @@ -207,6 +219,7 @@ export function DelegateModal({ close }: { close: Function }) { isDisabled={ !!errors.address || contractCallPending || + contractCallPendingViem || !values.address || values.address === azoriusGovernance.votesToken?.delegatee } @@ -222,6 +235,7 @@ export function DelegateModal({ close }: { close: Function }) { isDisabled={ !!errors.address || contractCallPending || + contractCallPendingViem || !values.address || values.address === decentGovernance.lockedVotesToken.delegatee } diff --git a/src/hooks/DAO/useDelegateVote.ts b/src/hooks/DAO/useDelegateVote.ts index eb80711927..f53b1c5f03 100644 --- a/src/hooks/DAO/useDelegateVote.ts +++ b/src/hooks/DAO/useDelegateVote.ts @@ -1,4 +1,3 @@ -import { VotesERC20 } from '@fractal-framework/fractal-contracts'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { LockRelease } from '../../assets/typechain-types/dcnt'; @@ -16,7 +15,7 @@ const useDelegateVote = () => { successCallback, }: { delegatee: string; - votingTokenContract: VotesERC20 | LockRelease; + votingTokenContract: LockRelease; successCallback?: () => void; }) => { contractCallDelegateVote({