From 00d39a712bb3729094f119784f811b88676c419e Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 27 Nov 2024 19:03:03 +0000 Subject: [PATCH 1/8] Fix pill external link styling --- src/components/ui/links/ExternalLink.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/ui/links/ExternalLink.tsx b/src/components/ui/links/ExternalLink.tsx index f3e8d72db..abb9e2d83 100644 --- a/src/components/ui/links/ExternalLink.tsx +++ b/src/components/ui/links/ExternalLink.tsx @@ -65,7 +65,6 @@ export default function ExternalLink({ grey: { hover: { bg: 'neutral-2', - borderColor: 'neutral-4', }, active: { bg: 'neutral-5', @@ -112,7 +111,6 @@ export default function ExternalLink({ gap="0.25rem" borderRadius="625rem" borderColor="transparent" - borderWidth="1px" _hover={ isTextLink ? textLinkStyles[styleVariant].hover : pillLinkStyles[styleVariant].hover } @@ -126,6 +124,7 @@ export default function ExternalLink({ {...rest} > Date: Wed, 27 Nov 2024 19:10:53 +0000 Subject: [PATCH 2/8] Extract `NumberStepperInput` component. Use in multisig threshold input --- .../formComponents/AzoriusGovernance.tsx | 45 ++----------------- .../DaoCreator/formComponents/Multisig.tsx | 21 +++------ .../ui/forms/NumberStepperInput.tsx | 44 ++++++++++++++++++ 3 files changed, 53 insertions(+), 57 deletions(-) create mode 100644 src/components/ui/forms/NumberStepperInput.tsx diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index c5cbf401b..b3a10bc2e 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -1,27 +1,22 @@ import { Alert, Box, - Button, Flex, FormControl, - HStack, InputGroup, InputRightElement, - NumberDecrementStepper, - NumberIncrementStepper, - NumberInput, - NumberInputField, Switch, Text, } from '@chakra-ui/react'; -import { Minus, Plus, WarningCircle } from '@phosphor-icons/react'; -import { useCallback, useEffect, useMemo, useState, memo } from 'react'; +import { WarningCircle } from '@phosphor-icons/react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDaoInfoStore } from '../../../store/daoInfo/useDaoInfoStore'; import { FractalModuleType, ICreationStepProps, VotingStrategyType } from '../../../types'; import { BigIntInput } from '../../ui/forms/BigIntInput'; import { CustomNonceInput } from '../../ui/forms/CustomNonceInput'; import { LabelComponent } from '../../ui/forms/InputComponent'; +import { NumberStepperInput } from '../../ui/forms/NumberStepperInput'; import { StepButtons } from '../StepButtons'; import { StepWrapper } from '../StepWrapper'; import useStepRedirect from '../hooks/useStepRedirect'; @@ -34,38 +29,6 @@ function DayStepperInput({ inputValue: number; onInputChange: (val: number) => void; }) { - const MemoizedNumberStepperInput = memo( - ({ value, onChange }: { value?: string | number; onChange: (val: string) => void }) => { - const stepperButton = (direction: 'inc' | 'dec') => ( - - ); - - return ( - - - {stepperButton('dec')} - - {stepperButton('inc')} - - - ); - }, - ); - MemoizedNumberStepperInput.displayName = 'MemoizedNumberInput'; - const { t } = useTranslation('common'); return ( @@ -76,7 +39,7 @@ function DayStepperInput({ gap="0.5rem" > {t('days', { ns: 'common' })} - onInputChange(Number(val))} /> diff --git a/src/components/DaoCreator/formComponents/Multisig.tsx b/src/components/DaoCreator/formComponents/Multisig.tsx index 2e607d1aa..b61019317 100644 --- a/src/components/DaoCreator/formComponents/Multisig.tsx +++ b/src/components/DaoCreator/formComponents/Multisig.tsx @@ -1,13 +1,4 @@ -import { - Text, - Flex, - Grid, - IconButton, - NumberInput, - NumberInputField, - Icon, - Button, -} from '@chakra-ui/react'; +import { Text, Flex, Grid, IconButton, Icon, Button } from '@chakra-ui/react'; import { MinusCircle, Plus } from '@phosphor-icons/react'; import { Field, FieldAttributes } from 'formik'; import { useTranslation } from 'react-i18next'; @@ -15,6 +6,7 @@ import { ICreationStepProps } from '../../../types'; import { AddressInput } from '../../ui/forms/EthAddressInput'; import { LabelComponent } from '../../ui/forms/InputComponent'; import LabelWrapper from '../../ui/forms/LabelWrapper'; +import { NumberStepperInput } from '../../ui/forms/NumberStepperInput'; import { StepButtons } from '../StepButtons'; import { StepWrapper } from '../StepWrapper'; import useStepRedirect from '../hooks/useStepRedirect'; @@ -139,13 +131,10 @@ export function Multisig(props: ICreationStepProps) { isRequired > {/* @todo replace with stepper input */} - validateNumber(value, 'multisig.signatureThreshold')} - isInvalid={!!errors.multisig?.signatureThreshold} - > - - + value={values.multisig.signatureThreshold} + /> diff --git a/src/components/ui/forms/NumberStepperInput.tsx b/src/components/ui/forms/NumberStepperInput.tsx new file mode 100644 index 000000000..169f767ae --- /dev/null +++ b/src/components/ui/forms/NumberStepperInput.tsx @@ -0,0 +1,44 @@ +import { + Button, + HStack, + NumberDecrementStepper, + NumberIncrementStepper, + NumberInput, + NumberInputField, +} from '@chakra-ui/react'; +import { Plus, Minus } from '@phosphor-icons/react'; + +export function NumberStepperInput({ + value, + onChange, +}: { + value?: string | number; + onChange: (val: string) => void; +}) { + const stepperButton = (direction: 'inc' | 'dec') => ( + + ); + + return ( + + + {stepperButton('dec')} + + {stepperButton('inc')} + + + ); +} From 7564c4faac7ce4ffed704e8a2c5692c6e0b50a51 Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 27 Nov 2024 19:12:50 +0000 Subject: [PATCH 3/8] Auto adjust threshold if removing an owner causes owner count to be less than current threshold --- src/components/DaoCreator/formComponents/Multisig.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/DaoCreator/formComponents/Multisig.tsx b/src/components/DaoCreator/formComponents/Multisig.tsx index b61019317..2569ae1e1 100644 --- a/src/components/DaoCreator/formComponents/Multisig.tsx +++ b/src/components/DaoCreator/formComponents/Multisig.tsx @@ -111,6 +111,17 @@ export function Multisig(props: ICreationStepProps) { (_, index) => index !== i, ), }); + + // If this removal causes the threshold to be higher than the number of signers, adjust the threshold + if ( + values.multisig.signatureThreshold! > + values.multisig.numOfSigners! - 1 + ) { + setFieldValue( + 'multisig.signatureThreshold', + values.multisig.numOfSigners! - 1, + ); + } }} data-testid={'multisig.numOfSigners-' + i} /> From 21de6ac41c01552c3ac843a8fdc2d96b750d199f Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 27 Nov 2024 19:30:15 +0000 Subject: [PATCH 4/8] Rip out wrap/unwrap functionality --- .../formComponents/AzoriusTokenDetails.tsx | 34 +--- src/components/ui/modals/ModalProvider.tsx | 14 -- src/components/ui/modals/UnwrapToken.tsx | 168 ------------------ .../DAO/loaders/useGovernanceContracts.ts | 11 +- src/hooks/utils/useAddressContractType.ts | 7 - src/i18n/locales/en/common.json | 2 - src/i18n/locales/en/daoCreate.json | 3 +- src/i18n/locales/en/modals.json | 16 -- 8 files changed, 9 insertions(+), 246 deletions(-) delete mode 100644 src/components/ui/modals/UnwrapToken.tsx diff --git a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx index 5d161b30e..3d1e2caa7 100644 --- a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx @@ -1,12 +1,10 @@ -import { Box, Flex, Input, RadioGroup, Text } from '@chakra-ui/react'; -import { Info } from '@phosphor-icons/react'; +import { Box, Flex, Input, RadioGroup } from '@chakra-ui/react'; import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { erc20Abi, getContract, isAddress, zeroAddress } from 'viem'; import { usePublicClient, useWalletClient } from 'wagmi'; import { createAccountSubstring } from '../../../hooks/utils/useGetAccountName'; import { ICreationStepProps, TokenCreationType } from '../../../types'; -import SupportTooltip from '../../ui/badges/SupportTooltip'; import ContentBoxTitle from '../../ui/containers/ContentBox/ContentBoxTitle'; import LabelWrapper from '../../ui/forms/LabelWrapper'; import { RadioWithText } from '../../ui/forms/Radio/RadioWithText'; @@ -107,9 +105,10 @@ export function AzoriusTokenDetails(props: ICreationStepProps) { }, [updateImportFields]); const tokenImportAddressErrorMessage = - values.erc20Token.tokenImportAddress && errors?.erc20Token?.tokenImportAddress - ? errors.erc20Token.tokenImportAddress - : undefined; + values.erc20Token.tokenImportAddress && errors?.erc20Token?.tokenImportAddress; + + const tokenErrorMsg = + tokenImportAddressErrorMessage || (!isImportedVotesToken ? t('errorNotVotingToken') : ''); return ( <> @@ -162,35 +161,16 @@ export function AzoriusTokenDetails(props: ICreationStepProps) { {values.erc20Token.tokenCreationType === TokenCreationType.IMPORTED && ( <> - + - {isImportedVotesToken === false && !errors.erc20Token?.tokenImportAddress && ( - - - - {t('warningExistingToken')} - - - )} )} diff --git a/src/components/ui/modals/ModalProvider.tsx b/src/components/ui/modals/ModalProvider.tsx index ac26928ae..6c980be5a 100644 --- a/src/components/ui/modals/ModalProvider.tsx +++ b/src/components/ui/modals/ModalProvider.tsx @@ -19,15 +19,11 @@ import PaymentWithdrawModal from './PaymentWithdrawModal'; import ProposalTemplateModal from './ProposalTemplateModal'; import StakeModal from './Stake'; import { UnsavedChangesWarningContent } from './UnsavedChangesWarningContent'; -import { UnwrapToken } from './UnwrapToken'; -import { WrapToken } from './WrapToken'; export enum ModalType { NONE, DELEGATE, STAKE, - WRAP_TOKEN, - UNWRAP_TOKEN, CONFIRM_URL, REMOVE_SIGNER, ADD_SIGNER, @@ -50,8 +46,6 @@ export type ModalPropsTypes = { [ModalType.NONE]: {}; [ModalType.DELEGATE]: {}; [ModalType.STAKE]: {}; - [ModalType.WRAP_TOKEN]: {}; - [ModalType.UNWRAP_TOKEN]: {}; [ModalType.ADD_PERMISSION]: {}; [ModalType.CONFIRM_DELETE_STRATEGY]: {}; [ModalType.CONFIRM_URL]: { url: string }; @@ -151,14 +145,6 @@ export function ModalProvider({ children }: { children: ReactNode }) { modalTitle = t('stakeTitle'); modalContent = ; break; - case ModalType.WRAP_TOKEN: - modalTitle = t('wrapTokenTitle'); - modalContent = ; - break; - case ModalType.UNWRAP_TOKEN: - modalTitle = t('unwrapTokenTitle'); - modalContent = ; - break; case ModalType.CONFIRM_URL: modalTitle = t('confirmUrlTitle'); hasWarning = true; diff --git a/src/components/ui/modals/UnwrapToken.tsx b/src/components/ui/modals/UnwrapToken.tsx deleted file mode 100644 index c4965ad0e..000000000 --- a/src/components/ui/modals/UnwrapToken.tsx +++ /dev/null @@ -1,168 +0,0 @@ -import { Button, Flex, Input } from '@chakra-ui/react'; -import { abis } from '@fractal-framework/fractal-contracts'; -import { Formik, FormikProps } from 'formik'; -import { useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; -import { getContract } from 'viem'; -import { useAccount, useWalletClient } from 'wagmi'; -import * as Yup from 'yup'; -import { useERC20LinearToken } from '../../../hooks/DAO/loaders/governance/useERC20LinearToken'; -import useApproval from '../../../hooks/utils/useApproval'; -import { useFormHelpers } from '../../../hooks/utils/useFormHelpers'; -import { useTransaction } from '../../../hooks/utils/useTransaction'; -import { useFractal } from '../../../providers/App/AppProvider'; -import { AzoriusGovernance, BigIntValuePair } from '../../../types'; -import { formatCoin } from '../../../utils'; -import { BigIntInput } from '../forms/BigIntInput'; -import LabelWrapper from '../forms/LabelWrapper'; - -export function UnwrapToken({ close }: { close: () => void }) { - const { governance, governanceContracts } = useFractal(); - const azoriusGovernance = governance as AzoriusGovernance; - const { address: account } = useAccount(); - const { loadERC20TokenAccountData } = useERC20LinearToken({ onMount: false }); - - const [contractCall, pending] = useTransaction(); - const { - approved, - approveTransaction, - pending: approvalPending, - } = useApproval( - governanceContracts.underlyingTokenAddress, - azoriusGovernance.votesToken?.address, - ); - - const { t } = useTranslation(['modals', 'treasury']); - const { restrictChars } = useFormHelpers(); - - const { data: walletClient } = useWalletClient(); - - const handleFormSubmit = useCallback( - (amount: BigIntValuePair) => { - const { votesTokenAddress } = governanceContracts; - if (!votesTokenAddress || !account || !walletClient) return; - - const wrapperTokenContract = getContract({ - abi: abis.VotesERC20Wrapper, - address: votesTokenAddress, - client: walletClient, - }); - - contractCall({ - contractFn: () => wrapperTokenContract.write.withdrawTo([account, amount.bigintValue!]), - pendingMessage: t('unwrapTokenPendingMessage'), - failedMessage: t('unwrapTokenFailedMessage'), - successMessage: t('unwrapTokenSuccessMessage'), - successCallback: async () => { - loadERC20TokenAccountData(); - }, - completedCallback: () => { - close(); - }, - }); - }, - [account, contractCall, governanceContracts, walletClient, close, t, loadERC20TokenAccountData], - ); - - if ( - !azoriusGovernance.votesToken?.balance || - !azoriusGovernance.votesToken.decimals || - azoriusGovernance.votesToken.balance === 0n - ) { - return null; - } - - return ( - { - const { amount } = values; - handleFormSubmit(amount); - }} - validationSchema={Yup.object().shape({ - amount: Yup.object({ - value: Yup.string().required(), - bigintValue: Yup.mixed().required(), - }).test({ - name: 'Unwrap Token Validation', - message: t('unwrapTokenError'), - test: amount => { - const amountBi = amount.bigintValue as bigint; - if (amountBi === 0n) return false; - if ( - !azoriusGovernance.votesToken || - azoriusGovernance.votesToken.balance === null || - azoriusGovernance.votesToken.balance === undefined || - azoriusGovernance.votesToken.balance === 0n - ) - return false; - if (amountBi > azoriusGovernance.votesToken.balance) return false; - return true; - }, - }), - })} - > - {({ handleSubmit, values, setFieldValue, errors }: FormikProps) => { - return ( -
- - - - - - - setFieldValue('amount', valuePair)} - data-testid="unWrapToken-amount" - onKeyDown={restrictChars} - maxValue={azoriusGovernance.votesToken?.balance!} - isDisabled={!approved} - /> - - - {approved ? ( - - ) : ( - - )} - -
- ); - }} -
- ); -} diff --git a/src/hooks/DAO/loaders/useGovernanceContracts.ts b/src/hooks/DAO/loaders/useGovernanceContracts.ts index bec6c2849..cbe7b63c0 100644 --- a/src/hooks/DAO/loaders/useGovernanceContracts.ts +++ b/src/hooks/DAO/loaders/useGovernanceContracts.ts @@ -61,22 +61,13 @@ export const useGovernanceContracts = () => { const govTokenAddress = await ozLinearVotingContract.read.governanceToken(); // govTokenAddress might be either // - a valid VotesERC20 contract - // - a valid VotesERC20Wrapper contract // - a valid LockRelease contract // - or none of these which is against business logic - const { isVotesErc20, isVotesErc20Wrapper } = await getAddressContractType(govTokenAddress); + const { isVotesErc20 } = await getAddressContractType(govTokenAddress); if (isVotesErc20) { votesTokenAddress = govTokenAddress; - } else if (isVotesErc20Wrapper) { - const wrapperContract = getContract({ - abi: abis.VotesERC20Wrapper, - address: govTokenAddress, - client: publicClient, - }); - underlyingTokenAddress = await wrapperContract.read.underlying(); - votesTokenAddress = govTokenAddress; } else { const possibleLockRelease = getContract({ address: govTokenAddress, diff --git a/src/hooks/utils/useAddressContractType.ts b/src/hooks/utils/useAddressContractType.ts index 717a87e7f..29350f45f 100644 --- a/src/hooks/utils/useAddressContractType.ts +++ b/src/hooks/utils/useAddressContractType.ts @@ -19,7 +19,6 @@ type ContractType = { isModuleAzorius: boolean; isModuleFractal: boolean; isVotesErc20: boolean; - isVotesErc20Wrapper: boolean; }; const defaultContractType: ContractType = { @@ -34,7 +33,6 @@ const defaultContractType: ContractType = { isModuleAzorius: false, isModuleFractal: false, isVotesErc20: false, - isVotesErc20Wrapper: false, isLinearVotingErc20WithHatsProposalCreation: false, isLinearVotingErc721WithHatsProposalCreation: false, }; @@ -219,11 +217,6 @@ const contractTests: ContractFunctionTest[] = [ revertFunctionNames: ['underlying'], resultKey: 'isVotesErc20', }, - { - abi: abis.VotesERC20Wrapper, - functionNames: ['decimals', 'name', 'owner', 'symbol', 'totalSupply', 'underlying'], - resultKey: 'isVotesErc20Wrapper', - }, ]; export function useAddressContractType() { diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 2a473beb8..f5d6197f8 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -96,8 +96,6 @@ "signersRequired": "Signers Required", "signersDescription": "The number of signers required to execute a proposal. Adding or removing a signer will require a proposal.", "etherscanTip": "Open in Etherscan", - "wrapToken": "Wrap Token", - "unwrapToken": "Unwrap Token", "max": "Max", "favoriteTooltip": "Toggle your favorite Safes.", "isMeSuffix": " (you)", diff --git a/src/i18n/locales/en/daoCreate.json b/src/i18n/locales/en/daoCreate.json index bcc6afc85..c8d9c0944 100644 --- a/src/i18n/locales/en/daoCreate.json +++ b/src/i18n/locales/en/daoCreate.json @@ -93,8 +93,7 @@ "radioLabelExistingToken": "Token Contract Address", "helperNewToken": "Create a new ERC-20 token to vote with.", "helperExistingToken": "Use an existing ERC-20 token contract for voting.", - "warningExistingToken": "This token must be wrapped in order to be used as a voting token", - "warningExistingTokenTooltip": "Decent will deploy a new ERC-20 governance token to wrap this one. Holders can deposit their tokens to vote with or withdraw them at any time.", + "errorNotVotingToken": "This token cannot be used for voting.", "snapshot": "Snapshot Space", "snapshotHelper": "Link a Snapshot Space via ENS to include offchain proposals and voting.", "tooltipMultisig": "<1>Learn more", diff --git a/src/i18n/locales/en/modals.json b/src/i18n/locales/en/modals.json index 6863bbab9..4ba9161e0 100644 --- a/src/i18n/locales/en/modals.json +++ b/src/i18n/locales/en/modals.json @@ -45,24 +45,8 @@ "signersRequired1": "out of", "signersRequired2": "signers required", "alreadySigner": "Address is already a signer", - "wrapTokenTitle": "Wrap your token", - "assetWrapTitle": "Asset to wrap", - "assetWrapAmountLabel": "How much would you like to wrap?", - "assetWrapSubLabel": "Wrap your ERC-20 token as an ERC-20 governance voting token.", - "wrapTokenPendingMessage": "Wrapping tokens...", - "wrapTokenFailedMessage": "Failed to wrap tokens", - "wrapTokenSuccessMessage": "Tokens wrapped", "wrapTokenError": "Invalid amount", "wrapTokenButton": "Wrap", - "unwrapTokenTitle": "Unwrap your token", - "assetUnwrapTitle": "Asset to unwrap", - "assetUnwrapAmountLabel": "How much would you like to unwrap?", - "assetUnwrapSubLabel": "Unwrap your ERC-20 governance voting token.", - "unwrapTokenPendingMessage": "Unwrapping tokens...", - "unwrapTokenFailedMessage": "Failed to unwrap tokens", - "unwrapTokenSuccessMessage": "Tokens unwrapped", - "unwrapTokenError": "Invalid amount", - "unwrapTokenButton": "Unwrap", "updateSignersTooltip": "The number of signers required to pass future proposals", "confirmModifyGovernanceTitle": "Heads up, this is a big deal!", "confirmModifyGovernanceDescription": "Modifying your Safe's governance will have significant implications. Please be sure before proceeding.", From 0d483269e23eadba58320c039ad94b30b4820008 Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 27 Nov 2024 20:03:51 +0000 Subject: [PATCH 5/8] Fix import token field showing error before first input --- .../formComponents/AzoriusTokenDetails.tsx | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx index 3d1e2caa7..88c1a06c7 100644 --- a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx @@ -1,10 +1,11 @@ import { Box, Flex, Input, RadioGroup } from '@chakra-ui/react'; +import { useFormikContext } from 'formik'; import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { erc20Abi, getContract, isAddress, zeroAddress } from 'viem'; import { usePublicClient, useWalletClient } from 'wagmi'; import { createAccountSubstring } from '../../../hooks/utils/useGetAccountName'; -import { ICreationStepProps, TokenCreationType } from '../../../types'; +import { CreatorFormState, ICreationStepProps, TokenCreationType } from '../../../types'; import ContentBoxTitle from '../../ui/containers/ContentBox/ContentBoxTitle'; import LabelWrapper from '../../ui/forms/LabelWrapper'; import { RadioWithText } from '../../ui/forms/Radio/RadioWithText'; @@ -28,23 +29,17 @@ function TokenConfigDisplay(props: ICreationStepProps) { } export function AzoriusTokenDetails(props: ICreationStepProps) { - const { - transactionPending, - isSubDAO, - setFieldValue, - values, - errors, - handleChange, - isSubmitting, - mode, - } = props; + const { transactionPending, isSubDAO, setFieldValue, errors, handleChange, isSubmitting, mode } = + props; const { t } = useTranslation('daoCreate'); const { data: walletClient } = useWalletClient(); const publicClient = usePublicClient(); + const { values, touched, setTouched } = useFormikContext(); + const { checkVotesToken } = usePrepareFormData(); - const [isImportedVotesToken, setIsImportedVotesToken] = useState(); + const [isImportedVotesToken, setIsValidERC20VotesToken] = useState(); useStepRedirect({ values }); const updateImportFields = useCallback(async () => { @@ -82,14 +77,14 @@ export function AzoriusTokenDetails(props: ICreationStepProps) { if (!isVotesToken) { setFieldValue('erc20Token.tokenName', 'Wrapped ' + name, true); setFieldValue('erc20Token.tokenSymbol', 'W' + symbol, true); - setIsImportedVotesToken(false); + setIsValidERC20VotesToken(false); } else { - setIsImportedVotesToken(true); + setIsValidERC20VotesToken(true); setFieldValue('erc20Token.tokenName', name, true); setFieldValue('erc20Token.tokenSymbol', symbol, true); } } else { - setIsImportedVotesToken(undefined); + setIsValidERC20VotesToken(undefined); } }, [ checkVotesToken, @@ -104,11 +99,15 @@ export function AzoriusTokenDetails(props: ICreationStepProps) { updateImportFields(); }, [updateImportFields]); - const tokenImportAddressErrorMessage = - values.erc20Token.tokenImportAddress && errors?.erc20Token?.tokenImportAddress; + let tokenErrorMsg = ''; - const tokenErrorMsg = - tokenImportAddressErrorMessage || (!isImportedVotesToken ? t('errorNotVotingToken') : ''); + if (touched.erc20Token?.tokenImportAddress) { + console.log(errors?.erc20Token?.tokenImportAddress); + + tokenErrorMsg = + errors?.erc20Token?.tokenImportAddress || + (!isImportedVotesToken ? t('errorNotVotingToken') : ''); + } return ( <> @@ -164,7 +163,16 @@ export function AzoriusTokenDetails(props: ICreationStepProps) { { + setTouched({ + erc20Token: { + tokenImportAddress: true, + }, + ...touched, + }); + + handleChange(e); + }} value={values.erc20Token.tokenImportAddress} placeholder={createAccountSubstring(zeroAddress)} isInvalid={!!tokenErrorMsg} From ef499410b1dc9529505d1e0de34cb51d6f9bb1f2 Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 27 Nov 2024 20:39:18 +0000 Subject: [PATCH 6/8] Fix allocation input spacing --- .../DaoCreator/formComponents/AzoriusTokenAllocations.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/DaoCreator/formComponents/AzoriusTokenAllocations.tsx b/src/components/DaoCreator/formComponents/AzoriusTokenAllocations.tsx index 02bc39329..36f838940 100644 --- a/src/components/DaoCreator/formComponents/AzoriusTokenAllocations.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusTokenAllocations.tsx @@ -40,7 +40,7 @@ export function AzoriusTokenAllocations(props: ICreationStepProps) { {t('titleAddress')} @@ -80,9 +80,11 @@ export function AzoriusTokenAllocations(props: ICreationStepProps) { ); })} + {t('helperAllocations')} From 8bdf189290cb7dba41b1374f07d9d138f465a939 Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 27 Nov 2024 21:01:37 +0000 Subject: [PATCH 7/8] Increase `AddressInput` debounce time --- src/components/ui/forms/EthAddressInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/forms/EthAddressInput.tsx b/src/components/ui/forms/EthAddressInput.tsx index cc443aaa2..83c09bec1 100644 --- a/src/components/ui/forms/EthAddressInput.tsx +++ b/src/components/ui/forms/EthAddressInput.tsx @@ -15,7 +15,7 @@ export function AddressInput({ value, onChange, ...rest }: InputProps) { () => debounce((event: ChangeEvent) => { if (onChange) onChange(event); - }, 300), + }, 500), [onChange], ); From 686528e537800502f89f45e2f4d40fe170c3207a Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 4 Dec 2024 15:37:57 +0000 Subject: [PATCH 8/8] Go cyberpsycho and RIPPP out every last innard of Wrap functionality and code --- .../formComponents/AzoriusTokenDetails.tsx | 6 +- src/hooks/DAO/useBuildDAOTx.ts | 3 - src/hooks/DAO/useDeployAzorius.ts | 11 ---- src/models/AzoriusTxBuilder.ts | 63 +------------------ src/models/DaoTxBuilder.ts | 6 +- src/models/TxBuilderFactory.ts | 4 -- src/providers/NetworkConfig/networks/base.ts | 2 - .../NetworkConfig/networks/mainnet.ts | 2 - .../NetworkConfig/networks/optimism.ts | 2 - .../NetworkConfig/networks/polygon.ts | 2 - .../NetworkConfig/networks/sepolia.ts | 2 - src/types/network.ts | 2 - 12 files changed, 4 insertions(+), 101 deletions(-) diff --git a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx index 88c1a06c7..1d47f8b3a 100644 --- a/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusTokenDetails.tsx @@ -74,11 +74,7 @@ export function AzoriusTokenDetails(props: ICreationStepProps) { }, true, ); - if (!isVotesToken) { - setFieldValue('erc20Token.tokenName', 'Wrapped ' + name, true); - setFieldValue('erc20Token.tokenSymbol', 'W' + symbol, true); - setIsValidERC20VotesToken(false); - } else { + if (isVotesToken) { setIsValidERC20VotesToken(true); setFieldValue('erc20Token.tokenName', name, true); setFieldValue('erc20Token.tokenSymbol', symbol, true); diff --git a/src/hooks/DAO/useBuildDAOTx.ts b/src/hooks/DAO/useBuildDAOTx.ts index 911c11fd5..3075365a1 100644 --- a/src/hooks/DAO/useBuildDAOTx.ts +++ b/src/hooks/DAO/useBuildDAOTx.ts @@ -18,7 +18,6 @@ const useBuildDAOTx = () => { const { contracts: { compatibilityFallbackHandler, - votesErc20WrapperMasterCopy, votesErc20MasterCopy, keyValuePairs, gnosisSafeProxyFactory, @@ -69,7 +68,6 @@ const useBuildDAOTx = () => { isAzorius, daoData, compatibilityFallbackHandler, - votesErc20WrapperMasterCopy, votesErc20MasterCopy, keyValuePairs, gnosisSafeProxyFactory, @@ -128,7 +126,6 @@ const useBuildDAOTx = () => { user.address, publicClient, compatibilityFallbackHandler, - votesErc20WrapperMasterCopy, votesErc20MasterCopy, keyValuePairs, gnosisSafeProxyFactory, diff --git a/src/hooks/DAO/useDeployAzorius.ts b/src/hooks/DAO/useDeployAzorius.ts index 6b74ab05c..c646c41ae 100644 --- a/src/hooks/DAO/useDeployAzorius.ts +++ b/src/hooks/DAO/useDeployAzorius.ts @@ -33,7 +33,6 @@ const useDeployAzorius = () => { const { contracts: { compatibilityFallbackHandler, - votesErc20WrapperMasterCopy, votesErc20MasterCopy, keyValuePairs, gnosisSafeProxyFactory, @@ -80,7 +79,6 @@ const useDeployAzorius = () => { return; } - let parentTokenAddress: Address | undefined; let parentStrategyAddress: Address | undefined; let parentStrategyType: VotingStrategyType | undefined; let attachFractalModule = false; @@ -110,12 +108,6 @@ const useDeployAzorius = () => { const masterCopyData = await getAddressContractType(parentStrategyAddress); if (masterCopyData.isLinearVotingErc20) { - const votingStrategyContract = getContract({ - abi: abis.LinearERC20Voting, - client: publicClient, - address: parentStrategyAddress, - }); - parentTokenAddress = await votingStrategyContract.read.governanceToken(); parentStrategyType = VotingStrategyType.LINEAR_ERC20; } else if (masterCopyData.isLinearVotingErc721) { parentStrategyType = VotingStrategyType.LINEAR_ERC721; @@ -137,7 +129,6 @@ const useDeployAzorius = () => { true, daoData, compatibilityFallbackHandler, - votesErc20WrapperMasterCopy, votesErc20MasterCopy, keyValuePairs, gnosisSafeProxyFactory, @@ -155,7 +146,6 @@ const useDeployAzorius = () => { linearVotingErc721MasterCopy, moduleAzoriusMasterCopy, parentAddress || undefined, - parentTokenAddress, ); txBuilderFactory.setSafeContract(safeAddress); @@ -218,7 +208,6 @@ const useDeployAzorius = () => { publicClient, parentAddress, compatibilityFallbackHandler, - votesErc20WrapperMasterCopy, votesErc20MasterCopy, keyValuePairs, gnosisSafeProxyFactory, diff --git a/src/models/AzoriusTxBuilder.ts b/src/models/AzoriusTxBuilder.ts index f2aa85d58..b4ddb411b 100644 --- a/src/models/AzoriusTxBuilder.ts +++ b/src/models/AzoriusTxBuilder.ts @@ -9,7 +9,6 @@ import { getAddress, getContract, getCreate2Address, - isAddress, keccak256, parseAbiParameters, } from 'viem'; @@ -31,7 +30,6 @@ export class AzoriusTxBuilder extends BaseTxBuilder { private readonly safeContractAddress: Address; private encodedSetupTokenData: Hex | undefined; - private encodedSetupERC20WrapperData: Hex | undefined; private encodedStrategySetupData: Hex | undefined; private encodedSetupAzoriusData: Hex | undefined; private encodedSetupTokenClaimData: Hex | undefined; @@ -44,8 +42,6 @@ export class AzoriusTxBuilder extends BaseTxBuilder { public linearERC20VotingAddress: Address | undefined; public linearERC721VotingAddress: Address | undefined; public votesTokenAddress: Address | undefined; - - private votesErc20WrapperMasterCopy: Address; private votesErc20MasterCopy: Address; private zodiacModuleProxyFactory: Address; private multiSendCallOnly: Address; @@ -63,8 +59,6 @@ export class AzoriusTxBuilder extends BaseTxBuilder { publicClient: PublicClient, daoData: AzoriusERC20DAO | AzoriusERC721DAO, safeContractAddress: Address, - - votesErc20WrapperMasterCopy: Address, votesErc20MasterCopy: Address, zodiacModuleProxyFactory: Address, multiSendCallOnly: Address, @@ -84,8 +78,6 @@ export class AzoriusTxBuilder extends BaseTxBuilder { this.claimNonce = getRandomBytes(); this.strategyNonce = getRandomBytes(); this.azoriusNonce = getRandomBytes(); - - this.votesErc20WrapperMasterCopy = votesErc20WrapperMasterCopy; this.votesErc20MasterCopy = votesErc20MasterCopy; this.zodiacModuleProxyFactory = zodiacModuleProxyFactory; this.multiSendCallOnly = multiSendCallOnly; @@ -96,16 +88,8 @@ export class AzoriusTxBuilder extends BaseTxBuilder { if (daoData.votingStrategyType === VotingStrategyType.LINEAR_ERC20) { daoData = daoData as AzoriusERC20DAO; - if (!daoData.isTokenImported) { - this.setEncodedSetupTokenData(); - this.setPredictedTokenAddress(); - } else { - if (daoData.isVotesToken) { - this.predictedTokenAddress = daoData.tokenImportAddress as Address; - } else { - this.setEncodedSetupERC20WrapperData(); - this.setPredictedERC20WrapperAddress(); - } + if (daoData.isVotesToken) { + this.predictedTokenAddress = daoData.tokenImportAddress as Address; } } } @@ -280,49 +264,6 @@ export class AzoriusTxBuilder extends BaseTxBuilder { ); } - public buildCreateTokenWrapperTx(): SafeTransaction { - return buildContractCall( - ZodiacModuleProxyFactoryAbi, - this.zodiacModuleProxyFactory, - 'deployModule', - [this.votesErc20WrapperMasterCopy, this.encodedSetupERC20WrapperData, this.tokenNonce], - 0, - false, - ); - } - - public setEncodedSetupERC20WrapperData() { - const { tokenImportAddress } = this.daoData as AzoriusERC20DAO; - - if (!tokenImportAddress || !isAddress(tokenImportAddress)) { - throw new Error( - 'Error encoding setup ERC-20 Wrapper data - provided token import address is not an address', - ); - } - - const encodedInitTokenData = encodeAbiParameters(parseAbiParameters('address'), [ - tokenImportAddress, - ]); - - this.encodedSetupERC20WrapperData = encodeFunctionData({ - abi: abis.VotesERC20Wrapper, - functionName: 'setUp', - args: [encodedInitTokenData], - }); - } - - public setPredictedERC20WrapperAddress() { - const tokenByteCodeLinear = generateContractByteCodeLinear(this.votesErc20WrapperMasterCopy); - - const tokenSalt = generateSalt(this.encodedSetupERC20WrapperData!, this.tokenNonce); - - this.predictedTokenAddress = getCreate2Address({ - from: this.zodiacModuleProxyFactory, - salt: tokenSalt, - bytecodeHash: keccak256(encodePacked(['bytes'], [tokenByteCodeLinear])), - }); - } - public signatures = (): string => { return ( '0x000000000000000000000000' + diff --git a/src/models/DaoTxBuilder.ts b/src/models/DaoTxBuilder.ts index 9d69c1fe8..b3db7d9c7 100644 --- a/src/models/DaoTxBuilder.ts +++ b/src/models/DaoTxBuilder.ts @@ -135,12 +135,8 @@ export class DaoTxBuilder extends BaseTxBuilder { azoriusTxBuilder.buildRemoveMultiSendOwnerTx(), ]); - // build token wrapper if token is imported and not votes token (votes token contracts is already deployed) - if (data.isTokenImported && !data.isVotesToken && data.tokenImportAddress) { - txs.push(azoriusTxBuilder.buildCreateTokenWrapperTx()); - } // build token if token is not imported - if (!data.isTokenImported && data.votingStrategyType === VotingStrategyType.LINEAR_ERC20) { + if (data.isVotesToken && data.votingStrategyType === VotingStrategyType.LINEAR_ERC20) { txs.push(azoriusTxBuilder.buildCreateTokenTx()); } diff --git a/src/models/TxBuilderFactory.ts b/src/models/TxBuilderFactory.ts index 38856448d..49f6700f3 100644 --- a/src/models/TxBuilderFactory.ts +++ b/src/models/TxBuilderFactory.ts @@ -25,7 +25,6 @@ export class TxBuilderFactory extends BaseTxBuilder { public createSafeTx: SafeTransaction | undefined; private safeContractAddress: Address | undefined; private compatibilityFallbackHandler: Address; - private votesErc20WrapperMasterCopy: Address; private votesErc20MasterCopy: Address; private keyValuePairs: Address; private gnosisSafeProxyFactory: Address; @@ -48,7 +47,6 @@ export class TxBuilderFactory extends BaseTxBuilder { isAzorius: boolean, daoData: SafeMultisigDAO | AzoriusERC20DAO | AzoriusERC721DAO | SubDAO, compatibilityFallbackHandler: Address, - votesErc20WrapperMasterCopy: Address, votesErc20MasterCopy: Address, keyValuePairs: Address, gnosisSafeProxyFactory: Address, @@ -72,7 +70,6 @@ export class TxBuilderFactory extends BaseTxBuilder { this.saltNum = getRandomBytes(); this.compatibilityFallbackHandler = compatibilityFallbackHandler; - this.votesErc20WrapperMasterCopy = votesErc20WrapperMasterCopy; this.votesErc20MasterCopy = votesErc20MasterCopy; this.keyValuePairs = keyValuePairs; this.gnosisSafeProxyFactory = gnosisSafeProxyFactory; @@ -191,7 +188,6 @@ export class TxBuilderFactory extends BaseTxBuilder { this.publicClient, this.daoData as AzoriusERC20DAO, this.safeContractAddress!, - this.votesErc20WrapperMasterCopy, this.votesErc20MasterCopy, this.zodiacModuleProxyFactory, this.multiSendCallOnly, diff --git a/src/providers/NetworkConfig/networks/base.ts b/src/providers/NetworkConfig/networks/base.ts index 76ae5d430..0ccb3258d 100644 --- a/src/providers/NetworkConfig/networks/base.ts +++ b/src/providers/NetworkConfig/networks/base.ts @@ -59,7 +59,6 @@ export const baseConfig: NetworkConfig = { zodiacModuleProxyFactory: '0x000000000000aDdB49795b0f9bA5BC298cDda236', linearVotingErc20MasterCopy: getAddress(a.LinearERC20Voting), - linearVotingErc20WrappedMasterCopy: getAddress(a.LinearERC20WrappedVoting), linearVotingErc20HatsWhitelistingMasterCopy: getAddress( a.LinearERC20VotingWithHatsProposalCreation, ), @@ -79,7 +78,6 @@ export const baseConfig: NetworkConfig = { freezeVotingMultisigMasterCopy: getAddress(a.MultisigFreezeVoting), votesErc20MasterCopy: getAddress(a.VotesERC20), - votesErc20WrapperMasterCopy: getAddress(a.VotesERC20Wrapper), claimErc20MasterCopy: getAddress(a.ERC20Claim), diff --git a/src/providers/NetworkConfig/networks/mainnet.ts b/src/providers/NetworkConfig/networks/mainnet.ts index febf3d670..09f931615 100644 --- a/src/providers/NetworkConfig/networks/mainnet.ts +++ b/src/providers/NetworkConfig/networks/mainnet.ts @@ -59,7 +59,6 @@ export const mainnetConfig: NetworkConfig = { zodiacModuleProxyFactory: '0x000000000000aDdB49795b0f9bA5BC298cDda236', linearVotingErc20MasterCopy: getAddress(a.LinearERC20Voting), - linearVotingErc20WrappedMasterCopy: getAddress(a.LinearERC20WrappedVoting), linearVotingErc20HatsWhitelistingMasterCopy: getAddress( a.LinearERC20VotingWithHatsProposalCreation, ), @@ -79,7 +78,6 @@ export const mainnetConfig: NetworkConfig = { freezeVotingMultisigMasterCopy: getAddress(a.MultisigFreezeVoting), votesErc20MasterCopy: getAddress(a.VotesERC20), - votesErc20WrapperMasterCopy: getAddress(a.VotesERC20Wrapper), claimErc20MasterCopy: getAddress(a.ERC20Claim), diff --git a/src/providers/NetworkConfig/networks/optimism.ts b/src/providers/NetworkConfig/networks/optimism.ts index b054795b8..9fdee2438 100644 --- a/src/providers/NetworkConfig/networks/optimism.ts +++ b/src/providers/NetworkConfig/networks/optimism.ts @@ -59,7 +59,6 @@ export const optimismConfig: NetworkConfig = { zodiacModuleProxyFactory: '0x000000000000aDdB49795b0f9bA5BC298cDda236', linearVotingErc20MasterCopy: getAddress(a.LinearERC20Voting), - linearVotingErc20WrappedMasterCopy: getAddress(a.LinearERC20WrappedVoting), linearVotingErc20HatsWhitelistingMasterCopy: getAddress( a.LinearERC20VotingWithHatsProposalCreation, ), @@ -79,7 +78,6 @@ export const optimismConfig: NetworkConfig = { freezeVotingMultisigMasterCopy: getAddress(a.MultisigFreezeVoting), votesErc20MasterCopy: getAddress(a.VotesERC20), - votesErc20WrapperMasterCopy: getAddress(a.VotesERC20Wrapper), claimErc20MasterCopy: getAddress(a.ERC20Claim), diff --git a/src/providers/NetworkConfig/networks/polygon.ts b/src/providers/NetworkConfig/networks/polygon.ts index a155c45f4..84d6da1fb 100644 --- a/src/providers/NetworkConfig/networks/polygon.ts +++ b/src/providers/NetworkConfig/networks/polygon.ts @@ -59,7 +59,6 @@ export const polygonConfig: NetworkConfig = { zodiacModuleProxyFactory: '0x000000000000aDdB49795b0f9bA5BC298cDda236', linearVotingErc20MasterCopy: getAddress(a.LinearERC20Voting), - linearVotingErc20WrappedMasterCopy: getAddress(a.LinearERC20WrappedVoting), linearVotingErc20HatsWhitelistingMasterCopy: getAddress( a.LinearERC20VotingWithHatsProposalCreation, ), @@ -79,7 +78,6 @@ export const polygonConfig: NetworkConfig = { freezeVotingMultisigMasterCopy: getAddress(a.MultisigFreezeVoting), votesErc20MasterCopy: getAddress(a.VotesERC20), - votesErc20WrapperMasterCopy: getAddress(a.VotesERC20Wrapper), claimErc20MasterCopy: getAddress(a.ERC20Claim), diff --git a/src/providers/NetworkConfig/networks/sepolia.ts b/src/providers/NetworkConfig/networks/sepolia.ts index 4854d2b51..6db0dc938 100644 --- a/src/providers/NetworkConfig/networks/sepolia.ts +++ b/src/providers/NetworkConfig/networks/sepolia.ts @@ -59,7 +59,6 @@ export const sepoliaConfig: NetworkConfig = { zodiacModuleProxyFactory: '0x000000000000aDdB49795b0f9bA5BC298cDda236', linearVotingErc20MasterCopy: getAddress(a.LinearERC20Voting), - linearVotingErc20WrappedMasterCopy: getAddress(a.LinearERC20WrappedVoting), linearVotingErc20HatsWhitelistingMasterCopy: getAddress( a.LinearERC20VotingWithHatsProposalCreation, ), @@ -79,7 +78,6 @@ export const sepoliaConfig: NetworkConfig = { freezeVotingMultisigMasterCopy: getAddress(a.MultisigFreezeVoting), votesErc20MasterCopy: getAddress(a.VotesERC20), - votesErc20WrapperMasterCopy: getAddress(a.VotesERC20Wrapper), claimErc20MasterCopy: getAddress(a.ERC20Claim), diff --git a/src/types/network.ts b/src/types/network.ts index 8d2f1c983..879daf910 100644 --- a/src/types/network.ts +++ b/src/types/network.ts @@ -35,7 +35,6 @@ export type NetworkConfig = { linearVotingErc20MasterCopy: Address; linearVotingErc20HatsWhitelistingMasterCopy: Address; - linearVotingErc20WrappedMasterCopy: Address; linearVotingErc721MasterCopy: Address; linearVotingErc721HatsWhitelistingMasterCopy: Address; @@ -50,7 +49,6 @@ export type NetworkConfig = { freezeVotingMultisigMasterCopy: Address; votesErc20MasterCopy: Address; - votesErc20WrapperMasterCopy: Address; claimErc20MasterCopy: Address;