From 83fa276180a4b32c04611c1b7e46c631f66d32cd Mon Sep 17 00:00:00 2001 From: Kellar Date: Mon, 27 Jan 2025 14:03:05 +0000 Subject: [PATCH 01/25] Add GasslessVotingToggleCard --- src/components/DaoCreator/constants.ts | 1 + .../formComponents/AzoriusGovernance.tsx | 7 ++ .../ui/cards/GasslessVotingToggleCard.tsx | 107 ++++++++++++++++++ src/i18n/locales/en/daoCreate.json | 5 +- src/types/createDAO.ts | 1 + 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/components/ui/cards/GasslessVotingToggleCard.tsx diff --git a/src/components/DaoCreator/constants.ts b/src/components/DaoCreator/constants.ts index 056c9c4adc..6ead0041a1 100644 --- a/src/components/DaoCreator/constants.ts +++ b/src/components/DaoCreator/constants.ts @@ -14,6 +14,7 @@ export const initialState: CreatorFormState = { daoName: '', governance: GovernanceType.AZORIUS_ERC20, snapshotENS: '', + gasslessVoting: false, }, erc20Token: { tokenCreationType: TokenCreationType.IMPORTED, diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index fd43641a60..9aa65ae30c 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -14,6 +14,7 @@ import { useTranslation } from 'react-i18next'; import { isFeatureEnabled } from '../../../helpers/featureFlags'; import { useDaoInfoStore } from '../../../store/daoInfo/useDaoInfoStore'; import { FractalModuleType, ICreationStepProps, VotingStrategyType } from '../../../types'; +import { GasslessVotingToggleCard } from '../../ui/cards/GasslessVotingToggleCard'; import { BigIntInput } from '../../ui/forms/BigIntInput'; import { CustomNonceInput } from '../../ui/forms/CustomNonceInput'; import { LabelComponent } from '../../ui/forms/InputComponent'; @@ -252,6 +253,12 @@ export function AzoriusGovernance(props: ICreationStepProps) { /> )} + + setFieldValue('essentials.gasslessVoting', !values.essentials.gasslessVoting) + } + /> void; +} + +export function GasslessVotingToggleCard({ + address = '0x01168475F8B9e46F710Ff3654cbD9405e8ADb421', + balance = '0 ETH', + isEnabled, + onToggle, +}: GasslessVotingToggleCardProps) { + const { t } = useTranslation('daoCreate'); + + return ( + + + + {t('gasslessVotingLabel')} + + {t('gasslessVotingDescription')} + + + onToggle()} + variant="secondary" + /> + + + {address && ( + + + {address} + + + )} + + + {t('titleBalance', { ns: 'modals' })}:{' '} + + {balance} + + + + + + + + {t('gasslessVotingGettingStarted')} + + + + + ); +} diff --git a/src/i18n/locales/en/daoCreate.json b/src/i18n/locales/en/daoCreate.json index 491a8553c0..fae78f9240 100644 --- a/src/i18n/locales/en/daoCreate.json +++ b/src/i18n/locales/en/daoCreate.json @@ -104,5 +104,8 @@ "networks": "Networks", "networkDescription": "What network would you like to deploy this DAO on?", "attachFractalModuleDescription": "This setting controls whether Parent DAO will be able to execute arbitrary transactions on Child DAO bypassing voting process on Child DAO.", - "fractalModuleAttachedDescription": "This setting can not be modified as Fractal Module already attached to the DAO." + "fractalModuleAttachedDescription": "This setting can not be modified as Fractal Module already attached to the DAO.", + "gasslessVotingLabel": "Gasless Voting", + "gasslessVotingDescription": "Sponsor gas for votes and proposals.", + "gasslessVotingGettingStarted": "To get you started, we're covering your first 0.1 ETH of gas fees. You can top up your balance in your DAO settings, or by sending ETH to this address directly in your wallet." } diff --git a/src/types/createDAO.ts b/src/types/createDAO.ts index 546f54d8c3..f59f488f93 100644 --- a/src/types/createDAO.ts +++ b/src/types/createDAO.ts @@ -68,6 +68,7 @@ export type DAOEssentials = { daoName: string; governance: GovernanceType; snapshotENS: string; + gasslessVoting: boolean; }; export type DAOGovernorERC20Token = { From 61e24f1b25498975b7efbe21efd26a82aef2d526 Mon Sep 17 00:00:00 2001 From: Kellar Date: Mon, 27 Jan 2025 14:37:04 +0000 Subject: [PATCH 02/25] Add GasslessVotingToggleDAOSettings --- .../formComponents/AzoriusGovernance.tsx | 4 +- .../ui/cards/GasslessVotingToggleCard.tsx | 58 ++++++++++++++----- src/i18n/locales/en/daoEdit.json | 4 +- .../general/SafeGeneralSettingsPage.tsx | 15 +++++ 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index 9aa65ae30c..d16224e2ba 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next'; import { isFeatureEnabled } from '../../../helpers/featureFlags'; import { useDaoInfoStore } from '../../../store/daoInfo/useDaoInfoStore'; import { FractalModuleType, ICreationStepProps, VotingStrategyType } from '../../../types'; -import { GasslessVotingToggleCard } from '../../ui/cards/GasslessVotingToggleCard'; +import { GasslessVotingToggleDAOCreate } from '../../ui/cards/GasslessVotingToggleCard'; import { BigIntInput } from '../../ui/forms/BigIntInput'; import { CustomNonceInput } from '../../ui/forms/CustomNonceInput'; import { LabelComponent } from '../../ui/forms/InputComponent'; @@ -253,7 +253,7 @@ export function AzoriusGovernance(props: ICreationStepProps) { /> )} - setFieldValue('essentials.gasslessVoting', !values.essentials.gasslessVoting) diff --git a/src/components/ui/cards/GasslessVotingToggleCard.tsx b/src/components/ui/cards/GasslessVotingToggleCard.tsx index 45a4131a62..56f0f09de6 100644 --- a/src/components/ui/cards/GasslessVotingToggleCard.tsx +++ b/src/components/ui/cards/GasslessVotingToggleCard.tsx @@ -4,46 +4,51 @@ import { useTranslation } from 'react-i18next'; import { DETAILS_BOX_SHADOW } from '../../../constants/common'; import EtherscanLink from '../links/EtherscanLink'; -interface GasslessVotingToggleCardProps { +interface GasslessVotingToggleProps { address?: string; balance?: string; isEnabled: boolean; onToggle: () => void; } -export function GasslessVotingToggleCard({ - address = '0x01168475F8B9e46F710Ff3654cbD9405e8ADb421', - balance = '0 ETH', +function GasslessVotingToggleContent({ isEnabled, onToggle, -}: GasslessVotingToggleCardProps) { + address, + balance = '0 ETH', + isSettings, +}: GasslessVotingToggleProps & { isSettings?: boolean }) { const { t } = useTranslation('daoCreate'); return ( - {t('gasslessVotingLabel')} + + {isSettings + ? t('gasslessVotingLabelSettings', { ns: 'daoEdit' }) + : t('gasslessVotingLabel')} + - {t('gasslessVotingDescription')} + {isSettings + ? t('gasslessVotingDescriptionSettings', { ns: 'daoEdit' }) + : t('gasslessVotingDescription')} {balance} + + ); +} +export function GasslessVotingToggleDAOCreate(props: GasslessVotingToggleProps) { + const { t } = useTranslation('daoCreate'); + + return ( + + ); } + +export function GasslessVotingToggleDAOSettings(props: GasslessVotingToggleProps) { + return ( + + ); +} diff --git a/src/i18n/locales/en/daoEdit.json b/src/i18n/locales/en/daoEdit.json index cc2b8e1092..06d40ccc5d 100644 --- a/src/i18n/locales/en/daoEdit.json +++ b/src/i18n/locales/en/daoEdit.json @@ -1,3 +1,5 @@ { - "cannotModifyGovernance": "You do not have permissions to modify this Safe's governance." + "cannotModifyGovernance": "You do not have permissions to modify this Safe's governance.", + "gasslessVotingLabelSettings": "Sponsor Gas", + "gasslessVotingDescriptionSettings": "Fund transaction fees for DAO voters from a shared DAO gas tank." } diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index 43938c0fe2..aacd6a13f8 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { encodeFunctionData, zeroAddress } from 'viem'; import { SettingsContentBox } from '../../../../components/SafeSettings/SettingsContentBox'; +import { GasslessVotingToggleDAOSettings } from '../../../../components/ui/cards/GasslessVotingToggleCard'; import { InputComponent } from '../../../../components/ui/forms/InputComponent'; import { BarLoader } from '../../../../components/ui/loaders/BarLoader'; import NestedPageHeader from '../../../../components/ui/page/Header/NestedPageHeader'; @@ -205,6 +206,20 @@ export function SafeGeneralSettingsPage() { )} + + + + ) : ( Date: Mon, 27 Jan 2025 14:39:57 +0000 Subject: [PATCH 03/25] Move GasslessVotingToggle --- .../DaoCreator/formComponents/AzoriusGovernance.tsx | 2 +- .../GasslessVotingToggleCard.tsx => GasslessVotingToggle.tsx} | 4 ++-- src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/components/ui/{cards/GasslessVotingToggleCard.tsx => GasslessVotingToggle.tsx} (96%) diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index d16224e2ba..3d556f418c 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next'; import { isFeatureEnabled } from '../../../helpers/featureFlags'; import { useDaoInfoStore } from '../../../store/daoInfo/useDaoInfoStore'; import { FractalModuleType, ICreationStepProps, VotingStrategyType } from '../../../types'; -import { GasslessVotingToggleDAOCreate } from '../../ui/cards/GasslessVotingToggleCard'; +import { GasslessVotingToggleDAOCreate } from '../../ui/GasslessVotingToggle'; import { BigIntInput } from '../../ui/forms/BigIntInput'; import { CustomNonceInput } from '../../ui/forms/CustomNonceInput'; import { LabelComponent } from '../../ui/forms/InputComponent'; diff --git a/src/components/ui/cards/GasslessVotingToggleCard.tsx b/src/components/ui/GasslessVotingToggle.tsx similarity index 96% rename from src/components/ui/cards/GasslessVotingToggleCard.tsx rename to src/components/ui/GasslessVotingToggle.tsx index 56f0f09de6..ba87bac044 100644 --- a/src/components/ui/cards/GasslessVotingToggleCard.tsx +++ b/src/components/ui/GasslessVotingToggle.tsx @@ -1,8 +1,8 @@ import { Box, Text, HStack, Switch, Flex, Icon } from '@chakra-ui/react'; import { WarningCircle } from '@phosphor-icons/react'; import { useTranslation } from 'react-i18next'; -import { DETAILS_BOX_SHADOW } from '../../../constants/common'; -import EtherscanLink from '../links/EtherscanLink'; +import { DETAILS_BOX_SHADOW } from '../../constants/common'; +import EtherscanLink from './links/EtherscanLink'; interface GasslessVotingToggleProps { address?: string; diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index aacd6a13f8..e96d06a673 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { encodeFunctionData, zeroAddress } from 'viem'; import { SettingsContentBox } from '../../../../components/SafeSettings/SettingsContentBox'; -import { GasslessVotingToggleDAOSettings } from '../../../../components/ui/cards/GasslessVotingToggleCard'; +import { GasslessVotingToggleDAOSettings } from '../../../../components/ui/GasslessVotingToggle'; import { InputComponent } from '../../../../components/ui/forms/InputComponent'; import { BarLoader } from '../../../../components/ui/loaders/BarLoader'; import NestedPageHeader from '../../../../components/ui/page/Header/NestedPageHeader'; From 2db640a09614dc7be804b0241f376dd41e056437 Mon Sep 17 00:00:00 2001 From: Kellar Date: Mon, 27 Jan 2025 14:58:13 +0000 Subject: [PATCH 04/25] Add "add gas" button --- .../formComponents/AzoriusGovernance.tsx | 1 + src/components/ui/GasslessVotingToggle.tsx | 70 +++++++++++++------ src/i18n/locales/en/daoEdit.json | 3 +- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index 3d556f418c..f35b7b9ccb 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -258,6 +258,7 @@ export function AzoriusGovernance(props: ICreationStepProps) { onToggle={() => setFieldValue('essentials.gasslessVoting', !values.essentials.gasslessVoting) } + address="0x01168475f8b9e46f710ff3654cbd9405e8adb421" /> void; @@ -15,7 +16,6 @@ function GasslessVotingToggleContent({ isEnabled, onToggle, address, - balance = '0 ETH', isSettings, }: GasslessVotingToggleProps & { isSettings?: boolean }) { const { t } = useTranslation('daoCreate'); @@ -36,13 +36,13 @@ function GasslessVotingToggleContent({ flexDirection="column" gap="0.25rem" > - + {isSettings ? t('gasslessVotingLabelSettings', { ns: 'daoEdit' }) : t('gasslessVotingLabel')} @@ -76,16 +76,6 @@ function GasslessVotingToggleContent({ )} - - - {t('titleBalance', { ns: 'modals' })}:{' '} - - {balance} - - ); } @@ -105,6 +95,16 @@ export function GasslessVotingToggleDAOCreate(props: GasslessVotingToggleProps) boxShadow={DETAILS_BOX_SHADOW} > + + + {t('titleBalance', { ns: 'modals' })}:{' '} + + {props.balance || '0 ETH'} + + + + + + + + {t('titleBalance', { ns: 'modals' })}:{' '} + + {props.balance || '0 ETH'} + + + + + ); } diff --git a/src/i18n/locales/en/daoEdit.json b/src/i18n/locales/en/daoEdit.json index 06d40ccc5d..5eadb3fc20 100644 --- a/src/i18n/locales/en/daoEdit.json +++ b/src/i18n/locales/en/daoEdit.json @@ -1,5 +1,6 @@ { "cannotModifyGovernance": "You do not have permissions to modify this Safe's governance.", "gasslessVotingLabelSettings": "Sponsor Gas", - "gasslessVotingDescriptionSettings": "Fund transaction fees for DAO voters from a shared DAO gas tank." + "gasslessVotingDescriptionSettings": "Fund transaction fees for DAO voters from a shared DAO gas tank.", + "addGas": "Add Gas" } From 6c86f3e834d3929ac5c0ea24f2879b4767780a66 Mon Sep 17 00:00:00 2001 From: Kellar Date: Mon, 27 Jan 2025 15:28:14 +0000 Subject: [PATCH 05/25] Move feature behing flag --- src/components/ui/GasslessVotingToggle.tsx | 15 +++++++++++++-- src/helpers/featureFlags.ts | 2 +- .../settings/general/SafeGeneralSettingsPage.tsx | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/components/ui/GasslessVotingToggle.tsx b/src/components/ui/GasslessVotingToggle.tsx index 51f91e5e10..a186df8700 100644 --- a/src/components/ui/GasslessVotingToggle.tsx +++ b/src/components/ui/GasslessVotingToggle.tsx @@ -3,7 +3,9 @@ import { GasPump, WarningCircle } from '@phosphor-icons/react'; import { useTranslation } from 'react-i18next'; import { Address } from 'viem'; import { DETAILS_BOX_SHADOW } from '../../constants/common'; +import { isFeatureEnabled } from '../../helpers/featureFlags'; import EtherscanLink from './links/EtherscanLink'; +import Divider from './utils/Divider'; interface GasslessVotingToggleProps { address?: Address; @@ -83,6 +85,8 @@ function GasslessVotingToggleContent({ export function GasslessVotingToggleDAOCreate(props: GasslessVotingToggleProps) { const { t } = useTranslation('daoCreate'); + if (!isFeatureEnabled('flag_gassless_voting')) return null; + return ( + + diff --git a/src/helpers/featureFlags.ts b/src/helpers/featureFlags.ts index d5764e1143..d06db77bb8 100644 --- a/src/helpers/featureFlags.ts +++ b/src/helpers/featureFlags.ts @@ -1,4 +1,4 @@ -export const FEATURE_FLAGS = ['flag_dev', 'flag_yelling'] as const; +export const FEATURE_FLAGS = ['flag_dev', 'flag_gassless_voting', 'flag_yelling'] as const; export type FeatureFlagKeys = typeof FEATURE_FLAGS; export type FeatureFlagKey = (typeof FEATURE_FLAGS)[number]; diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index e96d06a673..aaa702c651 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -207,11 +207,11 @@ export function SafeGeneralSettingsPage() { )} - + /> */} Date: Mon, 27 Jan 2025 15:38:57 +0000 Subject: [PATCH 06/25] Include feature for multisig create --- src/components/DaoCreator/formComponents/Multisig.tsx | 9 +++++++++ src/components/ui/GasslessVotingToggle.tsx | 1 + 2 files changed, 10 insertions(+) diff --git a/src/components/DaoCreator/formComponents/Multisig.tsx b/src/components/DaoCreator/formComponents/Multisig.tsx index 668cf19e47..4607a56ce2 100644 --- a/src/components/DaoCreator/formComponents/Multisig.tsx +++ b/src/components/DaoCreator/formComponents/Multisig.tsx @@ -3,6 +3,7 @@ import { MinusCircle, Plus } from '@phosphor-icons/react'; import { Field, FieldAttributes } from 'formik'; import { useTranslation } from 'react-i18next'; import { ICreationStepProps } from '../../../types'; +import { GasslessVotingToggleDAOCreate } from '../../ui/GasslessVotingToggle'; import { AddressInput } from '../../ui/forms/EthAddressInput'; import { LabelComponent } from '../../ui/forms/InputComponent'; import LabelWrapper from '../../ui/forms/LabelWrapper'; @@ -151,6 +152,14 @@ export function Multisig(props: ICreationStepProps) { + + + setFieldValue('essentials.gasslessVoting', !values.essentials.gasslessVoting) + } + address="0x01168475f8b9e46f710ff3654cbd9405e8adb421" + /> From 259aa584ae293c832716c17d3a2800742a6842d5 Mon Sep 17 00:00:00 2001 From: Kellar Date: Tue, 28 Jan 2025 15:26:23 +0000 Subject: [PATCH 07/25] =?UTF-8?q?`gassless`=20->=20`gasless`=20?= =?UTF-8?q?=F0=9F=A4=A6=F0=9F=8F=BE=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DaoCreator/constants.ts | 2 +- .../formComponents/AzoriusGovernance.tsx | 10 +++---- .../DaoCreator/formComponents/Multisig.tsx | 11 +++----- ...tingToggle.tsx => GaslessVotingToggle.tsx} | 28 +++++++++---------- src/helpers/featureFlags.ts | 2 +- src/i18n/locales/en/daoCreate.json | 6 ++-- src/i18n/locales/en/daoEdit.json | 4 +-- .../general/SafeGeneralSettingsPage.tsx | 4 +-- src/types/createDAO.ts | 2 +- 9 files changed, 32 insertions(+), 37 deletions(-) rename src/components/ui/{GasslessVotingToggle.tsx => GaslessVotingToggle.tsx} (82%) diff --git a/src/components/DaoCreator/constants.ts b/src/components/DaoCreator/constants.ts index 6ead0041a1..3a791053f5 100644 --- a/src/components/DaoCreator/constants.ts +++ b/src/components/DaoCreator/constants.ts @@ -14,7 +14,7 @@ export const initialState: CreatorFormState = { daoName: '', governance: GovernanceType.AZORIUS_ERC20, snapshotENS: '', - gasslessVoting: false, + gaslessVoting: false, }, erc20Token: { tokenCreationType: TokenCreationType.IMPORTED, diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index f35b7b9ccb..bae55ce6c8 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next'; import { isFeatureEnabled } from '../../../helpers/featureFlags'; import { useDaoInfoStore } from '../../../store/daoInfo/useDaoInfoStore'; import { FractalModuleType, ICreationStepProps, VotingStrategyType } from '../../../types'; -import { GasslessVotingToggleDAOCreate } from '../../ui/GasslessVotingToggle'; +import { GaslessVotingToggleDAOCreate } from '../../ui/GaslessVotingToggle'; import { BigIntInput } from '../../ui/forms/BigIntInput'; import { CustomNonceInput } from '../../ui/forms/CustomNonceInput'; import { LabelComponent } from '../../ui/forms/InputComponent'; @@ -253,11 +253,9 @@ export function AzoriusGovernance(props: ICreationStepProps) { /> )} - - setFieldValue('essentials.gasslessVoting', !values.essentials.gasslessVoting) - } + setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)} address="0x01168475f8b9e46f710ff3654cbd9405e8adb421" /> - - setFieldValue('essentials.gasslessVoting', !values.essentials.gasslessVoting) - } + setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)} address="0x01168475f8b9e46f710ff3654cbd9405e8adb421" /> void; } -function GasslessVotingToggleContent({ +function GaslessVotingToggleContent({ isEnabled, onToggle, address, isSettings, -}: GasslessVotingToggleProps & { isSettings?: boolean }) { +}: GaslessVotingToggleProps & { isSettings?: boolean }) { const { t } = useTranslation('daoCreate'); return ( @@ -40,8 +40,8 @@ function GasslessVotingToggleContent({ > {isSettings - ? t('gasslessVotingLabelSettings', { ns: 'daoEdit' }) - : t('gasslessVotingLabel')} + ? t('gaslessVotingLabelSettings', { ns: 'daoEdit' }) + : t('gaslessVotingLabel')} {isSettings - ? t('gasslessVotingDescriptionSettings', { ns: 'daoEdit' }) - : t('gasslessVotingDescription')} + ? t('gaslessVotingDescriptionSettings', { ns: 'daoEdit' }) + : t('gaslessVotingDescription')} - + {t('titleBalance', { ns: 'modals' })}:{' '} @@ -126,7 +126,7 @@ export function GasslessVotingToggleDAOCreate(props: GasslessVotingToggleProps) color="lilac-0" marginLeft="1rem" > - {t('gasslessVotingGettingStarted')} + {t('gaslessVotingGettingStarted')} @@ -134,10 +134,10 @@ export function GasslessVotingToggleDAOCreate(props: GasslessVotingToggleProps) ); } -export function GasslessVotingToggleDAOSettings(props: GasslessVotingToggleProps) { +export function GaslessVotingToggleDAOSettings(props: GaslessVotingToggleProps) { const { t } = useTranslation('daoEdit'); - if (!isFeatureEnabled('flag_gassless_voting')) return null; + if (!isFeatureEnabled('flag_gasless_voting')) return null; return ( - diff --git a/src/helpers/featureFlags.ts b/src/helpers/featureFlags.ts index d06db77bb8..9b75bc5ac5 100644 --- a/src/helpers/featureFlags.ts +++ b/src/helpers/featureFlags.ts @@ -1,4 +1,4 @@ -export const FEATURE_FLAGS = ['flag_dev', 'flag_gassless_voting', 'flag_yelling'] as const; +export const FEATURE_FLAGS = ['flag_dev', 'flag_gasless_voting', 'flag_yelling'] as const; export type FeatureFlagKeys = typeof FEATURE_FLAGS; export type FeatureFlagKey = (typeof FEATURE_FLAGS)[number]; diff --git a/src/i18n/locales/en/daoCreate.json b/src/i18n/locales/en/daoCreate.json index fae78f9240..23f5897b2f 100644 --- a/src/i18n/locales/en/daoCreate.json +++ b/src/i18n/locales/en/daoCreate.json @@ -105,7 +105,7 @@ "networkDescription": "What network would you like to deploy this DAO on?", "attachFractalModuleDescription": "This setting controls whether Parent DAO will be able to execute arbitrary transactions on Child DAO bypassing voting process on Child DAO.", "fractalModuleAttachedDescription": "This setting can not be modified as Fractal Module already attached to the DAO.", - "gasslessVotingLabel": "Gasless Voting", - "gasslessVotingDescription": "Sponsor gas for votes and proposals.", - "gasslessVotingGettingStarted": "To get you started, we're covering your first 0.1 ETH of gas fees. You can top up your balance in your DAO settings, or by sending ETH to this address directly in your wallet." + "gaslessVotingLabel": "Gasless Voting", + "gaslessVotingDescription": "Sponsor gas for votes and proposals.", + "gaslessVotingGettingStarted": "To get you started, we're covering your first 0.1 ETH of gas fees. You can top up your balance in your DAO settings, or by sending ETH to this address directly in your wallet." } diff --git a/src/i18n/locales/en/daoEdit.json b/src/i18n/locales/en/daoEdit.json index 5eadb3fc20..c776a7bd06 100644 --- a/src/i18n/locales/en/daoEdit.json +++ b/src/i18n/locales/en/daoEdit.json @@ -1,6 +1,6 @@ { "cannotModifyGovernance": "You do not have permissions to modify this Safe's governance.", - "gasslessVotingLabelSettings": "Sponsor Gas", - "gasslessVotingDescriptionSettings": "Fund transaction fees for DAO voters from a shared DAO gas tank.", + "gaslessVotingLabelSettings": "Sponsor Gas", + "gaslessVotingDescriptionSettings": "Fund transaction fees for DAO voters from a shared DAO gas tank.", "addGas": "Add Gas" } diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index aaa702c651..26557111a5 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { encodeFunctionData, zeroAddress } from 'viem'; import { SettingsContentBox } from '../../../../components/SafeSettings/SettingsContentBox'; -import { GasslessVotingToggleDAOSettings } from '../../../../components/ui/GasslessVotingToggle'; +import { GaslessVotingToggleDAOSettings } from '../../../../components/ui/GaslessVotingToggle'; import { InputComponent } from '../../../../components/ui/forms/InputComponent'; import { BarLoader } from '../../../../components/ui/loaders/BarLoader'; import NestedPageHeader from '../../../../components/ui/page/Header/NestedPageHeader'; @@ -213,7 +213,7 @@ export function SafeGeneralSettingsPage() { mx={{ base: '-0.75rem', md: '-1.5rem' }} /> */} - = { From d168e338b13aec77dcefde5afd78aaddbee5015e Mon Sep 17 00:00:00 2001 From: Kellar Date: Tue, 28 Jan 2025 15:26:38 +0000 Subject: [PATCH 08/25] cleanup --- src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index 26557111a5..868cace62a 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -207,12 +207,6 @@ export function SafeGeneralSettingsPage() { )} - {/* */} - Date: Wed, 29 Jan 2025 11:35:13 +0000 Subject: [PATCH 09/25] Reduce instances of hardcoded demo address to 1 --- src/components/DaoCreator/formComponents/AzoriusGovernance.tsx | 1 - src/components/DaoCreator/formComponents/Multisig.tsx | 1 - src/components/ui/GaslessVotingToggle.tsx | 3 +++ src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx | 1 - 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index bae55ce6c8..5c6a7c7cc6 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -256,7 +256,6 @@ export function AzoriusGovernance(props: ICreationStepProps) { setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)} - address="0x01168475f8b9e46f710ff3654cbd9405e8adb421" /> setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)} - address="0x01168475f8b9e46f710ff3654cbd9405e8adb421" /> ) : ( From f8afb0d2e7ac2d97381ba25c6bc310b6528d3c13 Mon Sep 17 00:00:00 2001 From: Kellar Date: Wed, 29 Jan 2025 12:07:12 +0000 Subject: [PATCH 10/25] Remove balance prop. Read data from native token --- src/components/ui/GaslessVotingToggle.tsx | 8 +++++--- src/hooks/useNativeToken.ts | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/hooks/useNativeToken.ts diff --git a/src/components/ui/GaslessVotingToggle.tsx b/src/components/ui/GaslessVotingToggle.tsx index 1709739cb6..181d4820fa 100644 --- a/src/components/ui/GaslessVotingToggle.tsx +++ b/src/components/ui/GaslessVotingToggle.tsx @@ -4,12 +4,12 @@ import { useTranslation } from 'react-i18next'; import { Address } from 'viem'; import { DETAILS_BOX_SHADOW } from '../../constants/common'; import { isFeatureEnabled } from '../../helpers/featureFlags'; +import { useNativeToken } from '../../hooks/useNativeToken'; import EtherscanLink from './links/EtherscanLink'; import Divider from './utils/Divider'; interface GaslessVotingToggleProps { address?: Address; - balance?: string; isEnabled: boolean; onToggle: () => void; } @@ -87,6 +87,7 @@ function GaslessVotingToggleContent({ export function GaslessVotingToggleDAOCreate(props: GaslessVotingToggleProps) { const { t } = useTranslation('daoCreate'); + const { formattedNativeTokenBalance } = useNativeToken(); if (!isFeatureEnabled('flag_gasless_voting')) return null; @@ -110,7 +111,7 @@ export function GaslessVotingToggleDAOCreate(props: GaslessVotingToggleProps) { as="span" color="neutral-7" > - {props.balance || '0 ETH'} + {formattedNativeTokenBalance ?? '0'} - {props.balance || '0 ETH'} + {formattedNativeTokenBalance ?? '0'} diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index b0bc4a813c..98d321a337 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -188,6 +188,15 @@ export function SafeGeneralSettingsPage() { }} /> + + { + console.log( + 'onToggle. Add this action to the proposal, to be submitted via propose changes button.', + ); + }} + /> {canUserCreateProposal && ( <> )} - - ) : ( Date: Tue, 4 Feb 2025 18:31:40 +0000 Subject: [PATCH 16/25] Add `updateDAOInfo` to useDaoInfoStore, for setting gasless voting flag and gas tank address from external source of truth --- src/store/daoInfo/useDaoInfoStore.ts | 37 ++++++++++++++++++++++------ src/types/fractal.ts | 5 ++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/store/daoInfo/useDaoInfoStore.ts b/src/store/daoInfo/useDaoInfoStore.ts index 8ed99fdd50..23da0e6105 100644 --- a/src/store/daoInfo/useDaoInfoStore.ts +++ b/src/store/daoInfo/useDaoInfoStore.ts @@ -1,4 +1,4 @@ -import { getAddress } from 'viem'; +import { Address, getAddress } from 'viem'; import { create } from 'zustand'; import { DAOSubgraph, DecentModule, IDAO, SafeWithNextNonce } from '../../types'; @@ -6,12 +6,21 @@ export const initialDaoInfoStore: IDAO = { safe: null, subgraphInfo: null, modules: null, + gaslessVotingEnabled: false, + gasTankAddress: null, }; + +interface UpdateDAOInfoParams { + daoName?: string; + gaslessVotingEnabled?: boolean; + gasTankAddress?: Address; +} + export interface DaoInfoStore extends IDAO { setSafeInfo: (safe: SafeWithNextNonce) => void; setDaoInfo: (daoInfo: DAOSubgraph) => void; setDecentModules: (modules: DecentModule[]) => void; - updateDaoName: (newDaoName: string) => void; + updateDAOInfo: (params: UpdateDAOInfoParams) => void; resetDaoInfoStore: () => void; } @@ -40,14 +49,26 @@ export const useDaoInfoStore = create()(set => ({ setDecentModules: (modules: DecentModule[]) => { set({ modules }); }, - updateDaoName: (newDaoName: string) => { + updateDAOInfo: ({ daoName, gaslessVotingEnabled, gasTankAddress }: UpdateDAOInfoParams) => { set(state => { - if (!state.subgraphInfo) { - throw new Error('Subgraph info is not set'); + const updates: Partial = {}; + + if (daoName !== undefined) { + if (!state.subgraphInfo) { + throw new Error('Subgraph info is not set'); + } + updates.subgraphInfo = { ...state.subgraphInfo, daoName }; } - return { - subgraphInfo: { ...state.subgraphInfo, daoName: newDaoName }, - }; + + if (gaslessVotingEnabled !== undefined) { + updates.gaslessVotingEnabled = gaslessVotingEnabled; + } + + if (gasTankAddress !== undefined) { + updates.gasTankAddress = gasTankAddress; + } + + return updates; }); }, resetDaoInfoStore: () => set(initialDaoInfoStore), diff --git a/src/types/fractal.ts b/src/types/fractal.ts index 7013ab696d..1bfa1ea31f 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -156,6 +156,11 @@ export enum DecentModuleType { export interface IDAO { // replaces DaoInfo safe: GnosisSafe | null; + + // @todo: where's the best place for these 2 props to exist? + gaslessVotingEnabled: boolean; + gasTankAddress: Address | null; + subgraphInfo: DAOSubgraph | null; modules: DecentModule[] | null; } From a206d507b4e08991df833af5fec29f94490f9c02 Mon Sep 17 00:00:00 2001 From: Kellar Date: Tue, 4 Feb 2025 18:32:25 +0000 Subject: [PATCH 17/25] Remove unused types --- src/types/fractal.ts | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/types/fractal.ts b/src/types/fractal.ts index 1bfa1ea31f..2fa25c0d25 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -226,21 +226,6 @@ export interface FractalGovernanceContracts { export type SafeWithNextNonce = SafeInfoResponseWithGuard & { nextNonce: number }; -// @dev Information retreived from subgraph -interface SubgraphDAOInfo { - daoName: string | null; - nodeHierarchy: NodeHierarchy; - isHierarchyLoaded?: boolean; - daoSnapshotENS?: string; - proposalTemplatesHash?: string; -} - -// @dev Information retreived from Safe -export interface DaoInfo extends SubgraphDAOInfo { - safe: SafeWithNextNonce | null; - fractalModules: DecentModule[]; - isModulesLoaded?: boolean; -} export type DaoHierarchyStrategyType = 'ERC-20' | 'ERC-721' | 'MULTISIG'; export interface DaoHierarchyInfo { safeAddress: Address; @@ -341,11 +326,6 @@ export enum VotingStrategyType { LINEAR_ERC721_HATS_WHITELISTING = 'labelLinearErc721WithWhitelisting', } -export interface NodeHierarchy { - parentAddress: Address | null; - childNodes: Omit[]; -} - export type FractalProposal = AzoriusProposal | MultisigProposal | SnapshotProposal; export interface TransferDisplayData { From 5db5d827d7428371e4dc424ec149f69106b1369a Mon Sep 17 00:00:00 2001 From: Kellar Date: Tue, 4 Feb 2025 18:39:42 +0000 Subject: [PATCH 18/25] Add some more placeholder logic to onToggle and add gas button click --- src/components/ui/GaslessVotingToggle.tsx | 13 +++++++- src/i18n/locales/en/proposalMetadata.json | 2 ++ .../general/SafeGeneralSettingsPage.tsx | 33 +++++++++++++++++-- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/components/ui/GaslessVotingToggle.tsx b/src/components/ui/GaslessVotingToggle.tsx index 1aa3ff7349..c53a9f0b2c 100644 --- a/src/components/ui/GaslessVotingToggle.tsx +++ b/src/components/ui/GaslessVotingToggle.tsx @@ -6,6 +6,7 @@ import { DETAILS_BOX_SHADOW } from '../../constants/common'; import { isFeatureEnabled } from '../../helpers/featureFlags'; import { useNetworkConfigStore } from '../../providers/NetworkConfig/useNetworkConfigStore'; import { useDaoInfoStore } from '../../store/daoInfo/useDaoInfoStore'; +import { BigIntValuePair } from '../../types'; import { formatCoin } from '../../utils'; import EtherscanLink from './links/EtherscanLink'; import Divider from './utils/Divider'; @@ -107,7 +108,11 @@ export function GaslessVotingToggleDAOCreate(props: GaslessVotingToggleProps) { ); } -export function GaslessVotingToggleDAOSettings(props: GaslessVotingToggleProps) { +export function GaslessVotingToggleDAOSettings( + props: GaslessVotingToggleProps & { + onGasTankTopupAmountChange: (amount: BigIntValuePair) => void; + }, +) { const { t } = useTranslation('daoEdit'); const { safe } = useDaoInfoStore(); const { chain } = useNetworkConfigStore(); @@ -179,6 +184,12 @@ export function GaslessVotingToggleDAOSettings(props: GaslessVotingToggleProps) console.log( 'addGas. Add this action to the proposal, to be submitted via propose changes button.', ); + + // @todo: Add UI to set the amount, then call onGasTankTopupAmountChange. + props.onGasTankTopupAmountChange({ + value: '1', + bigintValue: 1n, + }); }} > {t('addGas')} diff --git a/src/i18n/locales/en/proposalMetadata.json b/src/i18n/locales/en/proposalMetadata.json index 87f8b5e280..3ec518b778 100644 --- a/src/i18n/locales/en/proposalMetadata.json +++ b/src/i18n/locales/en/proposalMetadata.json @@ -7,6 +7,8 @@ "removeProposalTemplateTitle": "Remove Proposal Template", "removeProposalTemplateDescription": "Execution of this proposal will remove the proposal template attached to this Safe.", "updatesSafeName": "Update Safe Name", + "enableGaslessVoting": "Enable Gasless Voting", + "topupGasTank": "Topup Gas Tank", "updateSnapshotSpace": "Update Snapshot Space", "lidoWithdrawalTitle": "Lido Withdrawal", "lidoWithdrawalDescription": "This proposal will burn your Lido Withdrawal NFT and return the ETH to your Safe.", diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index 98d321a337..a963094202 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -16,7 +16,7 @@ import { useCanUserCreateProposal } from '../../../../hooks/utils/useCanUserSubm import { createAccountSubstring } from '../../../../hooks/utils/useGetAccountName'; import { useNetworkConfigStore } from '../../../../providers/NetworkConfig/useNetworkConfigStore'; import { useDaoInfoStore } from '../../../../store/daoInfo/useDaoInfoStore'; -import { ProposalExecuteData } from '../../../../types'; +import { BigIntValuePair, ProposalExecuteData } from '../../../../types'; import { validateENSName } from '../../../../utils/url'; export function SafeGeneralSettingsPage() { @@ -24,11 +24,19 @@ export function SafeGeneralSettingsPage() { const [name, setName] = useState(''); const [snapshotENS, setSnapshotENS] = useState(''); const [snapshotENSValid, setSnapshotENSValid] = useState(); + + const [isGaslessVotingEnabled, setIsGaslessVotingEnabled] = useState(false); + const [gasTankTopupAmount, setGasTankTopupAmount] = useState(); + const navigate = useNavigate(); const { submitProposal } = useSubmitProposal(); const { canUserCreateProposal } = useCanUserCreateProposal(); - const { subgraphInfo, safe } = useDaoInfoStore(); + const { + subgraphInfo, + safe, + gaslessVotingEnabled: currentIsGaslessVotingEnabled, + } = useDaoInfoStore(); const { addressPrefix, contracts: { keyValuePairs }, @@ -71,6 +79,9 @@ export function SafeGeneralSettingsPage() { const nameChanged = name !== subgraphInfo?.daoName; const snapshotChanged = snapshotENSValid && snapshotENS !== subgraphInfo?.daoSnapshotENS; + const gaslessVotingChanged = isGaslessVotingEnabled !== currentIsGaslessVotingEnabled; + const gasTankTopupAmountSet = + gasTankTopupAmount?.bigintValue !== undefined && gasTankTopupAmount.bigintValue > 0n; const handleEditGeneralGovernance = () => { const changeTitles = []; @@ -93,6 +104,20 @@ export function SafeGeneralSettingsPage() { valueArgs.push(snapshotENS); } + if (gaslessVotingChanged) { + changeTitles.push(t('enableGaslessVoting', { ns: 'proposalMetadata' })); + + // @todo Is KV pairs the place we're storing this flag? + keyArgs.push('gaslessVotingEnabled'); + valueArgs.push(`${isGaslessVotingEnabled}`); + } + + if (gasTankTopupAmountSet) { + changeTitles.push(t('topupGasTank', { ns: 'proposalMetadata' })); + + // @todo add tx to send `gasTankTopupAmount` to gas tank address + } + const proposalData: ProposalExecuteData = { metaData: { title, @@ -190,12 +215,14 @@ export function SafeGeneralSettingsPage() { { console.log( 'onToggle. Add this action to the proposal, to be submitted via propose changes button.', ); + setIsGaslessVotingEnabled(!isGaslessVotingEnabled); }} + onGasTankTopupAmountChange={setGasTankTopupAmount} /> {canUserCreateProposal && ( <> From 1d54f0bb0bb6985ef4442f6e3f759dd3958f33b7 Mon Sep 17 00:00:00 2001 From: Kellar Date: Tue, 4 Feb 2025 18:43:17 +0000 Subject: [PATCH 19/25] DRY --- src/i18n/locales/en/proposalMetadata.json | 2 +- .../settings/general/SafeGeneralSettingsPage.tsx | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/i18n/locales/en/proposalMetadata.json b/src/i18n/locales/en/proposalMetadata.json index 3ec518b778..d9755dac70 100644 --- a/src/i18n/locales/en/proposalMetadata.json +++ b/src/i18n/locales/en/proposalMetadata.json @@ -8,7 +8,7 @@ "removeProposalTemplateDescription": "Execution of this proposal will remove the proposal template attached to this Safe.", "updatesSafeName": "Update Safe Name", "enableGaslessVoting": "Enable Gasless Voting", - "topupGasTank": "Topup Gas Tank", + "topupGasTank": "Top up Gas Tank", "updateSnapshotSpace": "Update Snapshot Space", "lidoWithdrawalTitle": "Lido Withdrawal", "lidoWithdrawalDescription": "This proposal will burn your Lido Withdrawal NFT and return the ETH to your Safe.", diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index a963094202..fbe2f4c756 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -85,21 +85,17 @@ export function SafeGeneralSettingsPage() { const handleEditGeneralGovernance = () => { const changeTitles = []; - if (nameChanged) { - changeTitles.push(t('updatesSafeName', { ns: 'proposalMetadata' })); - } - if (snapshotChanged) { - changeTitles.push(t('updateSnapshotSpace', { ns: 'proposalMetadata' })); - } - const title = changeTitles.join(` ${t('and', { ns: 'common' })} `); - const keyArgs = []; const valueArgs = []; + if (nameChanged) { + changeTitles.push(t('updatesSafeName', { ns: 'proposalMetadata' })); keyArgs.push('daoName'); valueArgs.push(name); } + if (snapshotChanged) { + changeTitles.push(t('updateSnapshotSpace', { ns: 'proposalMetadata' })); keyArgs.push('snapshotENS'); valueArgs.push(snapshotENS); } @@ -118,6 +114,8 @@ export function SafeGeneralSettingsPage() { // @todo add tx to send `gasTankTopupAmount` to gas tank address } + const title = changeTitles.join(`; `); + const proposalData: ProposalExecuteData = { metaData: { title, From bbbe6fe9b1e679bb2afc8d58eda1645602c20144 Mon Sep 17 00:00:00 2001 From: Kellar Date: Tue, 4 Feb 2025 18:53:14 +0000 Subject: [PATCH 20/25] dont hardcode ETH --- src/components/ui/GaslessVotingToggle.tsx | 5 ++++- src/i18n/locales/en/daoCreate.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/ui/GaslessVotingToggle.tsx b/src/components/ui/GaslessVotingToggle.tsx index c53a9f0b2c..6ecc991cf5 100644 --- a/src/components/ui/GaslessVotingToggle.tsx +++ b/src/components/ui/GaslessVotingToggle.tsx @@ -67,6 +67,7 @@ function GaslessVotingToggleContent({ export function GaslessVotingToggleDAOCreate(props: GaslessVotingToggleProps) { const { t } = useTranslation('daoCreate'); + const { chain } = useNetworkConfigStore(); if (!isFeatureEnabled('flag_gasless_voting')) return null; @@ -100,7 +101,9 @@ export function GaslessVotingToggleDAOCreate(props: GaslessVotingToggleProps) { color="lilac-0" marginLeft="1rem" > - {t('gaslessVotingGettingStarted')} + {t('gaslessVotingGettingStarted', { + symbol: chain.nativeCurrency.symbol, + })} diff --git a/src/i18n/locales/en/daoCreate.json b/src/i18n/locales/en/daoCreate.json index 23f5897b2f..9a0675a31a 100644 --- a/src/i18n/locales/en/daoCreate.json +++ b/src/i18n/locales/en/daoCreate.json @@ -107,5 +107,5 @@ "fractalModuleAttachedDescription": "This setting can not be modified as Fractal Module already attached to the DAO.", "gaslessVotingLabel": "Gasless Voting", "gaslessVotingDescription": "Sponsor gas for votes and proposals.", - "gaslessVotingGettingStarted": "To get you started, we're covering your first 0.1 ETH of gas fees. You can top up your balance in your DAO settings, or by sending ETH to this address directly in your wallet." + "gaslessVotingGettingStarted": "To get you started, we're covering your first 0.1 {{symbol}} of gas fees. You can top up your balance in your DAO settings, or by sending {{symbol}} to this address directly in your wallet." } From d94b010f3dac7fb3d834653d823cf14f5540c526 Mon Sep 17 00:00:00 2001 From: Kellar Date: Mon, 10 Feb 2025 15:16:50 +0000 Subject: [PATCH 21/25] Move gaslessVotingSupported conditional rendering into `GaslessVotingToggleDAOCreate` and `GaslessVotingToggleDAOSettings` --- .../formComponents/AzoriusGovernance.tsx | 15 ++++----------- .../DaoCreator/formComponents/Multisig.tsx | 15 ++++----------- src/components/ui/GaslessVotingToggle.tsx | 6 ++++-- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx index 99ba134164..5c6a7c7cc6 100644 --- a/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx +++ b/src/components/DaoCreator/formComponents/AzoriusGovernance.tsx @@ -12,7 +12,6 @@ import { WarningCircle } from '@phosphor-icons/react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { isFeatureEnabled } from '../../../helpers/featureFlags'; -import { useNetworkConfigStore } from '../../../providers/NetworkConfig/useNetworkConfigStore'; import { useDaoInfoStore } from '../../../store/daoInfo/useDaoInfoStore'; import { FractalModuleType, ICreationStepProps, VotingStrategyType } from '../../../types'; import { GaslessVotingToggleDAOCreate } from '../../ui/GaslessVotingToggle'; @@ -102,8 +101,6 @@ export function AzoriusGovernance(props: ICreationStepProps) { setFieldValue('azorius.executionPeriod', { bigintValue: minutes, value: minutes.toString() }); }, [setFieldValue, executionPeriodDays]); - const { gaslessVotingSupported } = useNetworkConfigStore(); - return ( <> )} - {gaslessVotingSupported && ( - - setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting) - } - /> - )} + setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)} + /> - {gaslessVotingSupported && ( - - setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting) - } - /> - )} + setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)} + /> Date: Mon, 10 Feb 2025 15:17:04 +0000 Subject: [PATCH 22/25] re-arrange some stuff --- src/components/ui/GaslessVotingToggle.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/ui/GaslessVotingToggle.tsx b/src/components/ui/GaslessVotingToggle.tsx index 03bd46f50e..79c89a634f 100644 --- a/src/components/ui/GaslessVotingToggle.tsx +++ b/src/components/ui/GaslessVotingToggle.tsx @@ -119,11 +119,12 @@ export function GaslessVotingToggleDAOSettings( ) { const { t } = useTranslation('daoEdit'); const { chain, gaslessVotingSupported } = useNetworkConfigStore(); + + // @todo: Retrieve and use the paymaster address here for `gasTankAddress`. Replace safe.address with the paymaster address. Remove use of `useDaoInfoStore`. const { safe } = useDaoInfoStore(); - const { chain } = useNetworkConfigStore(); + const gasTankAddress = safe?.address; - // @todo: Use the paymaster address here. - const { data: balance } = useBalance({ address: safe?.address, chainId: chain.id }); + const { data: balance } = useBalance({ address: gasTankAddress, chainId: chain.id }); if (!isFeatureEnabled('flag_gasless_voting')) return null; if (!gaslessVotingSupported) return null; @@ -131,9 +132,6 @@ export function GaslessVotingToggleDAOSettings( const formattedNativeTokenBalance = balance && formatCoin(balance.value, true, balance.decimals, balance.symbol); - // @todo: Retrieve the paymaster address here. Replace safe.address with the paymaster address. - const gasTankAddress = safe.address; - return ( Date: Mon, 10 Feb 2025 15:26:46 +0000 Subject: [PATCH 23/25] Move dao gasless state props to subgraphInfo --- .../dao/settings/general/SafeGeneralSettingsPage.tsx | 8 +++----- src/store/daoInfo/useDaoInfoStore.ts | 12 ++++++++---- src/types/fractal.ts | 7 ++----- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx index fbe2f4c756..55bf26516f 100644 --- a/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx +++ b/src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx @@ -32,11 +32,7 @@ export function SafeGeneralSettingsPage() { const { submitProposal } = useSubmitProposal(); const { canUserCreateProposal } = useCanUserCreateProposal(); - const { - subgraphInfo, - safe, - gaslessVotingEnabled: currentIsGaslessVotingEnabled, - } = useDaoInfoStore(); + const { subgraphInfo, safe } = useDaoInfoStore(); const { addressPrefix, contracts: { keyValuePairs }, @@ -44,6 +40,8 @@ export function SafeGeneralSettingsPage() { const safeAddress = safe?.address; + const currentIsGaslessVotingEnabled = subgraphInfo?.gaslessVotingEnabled ?? false; + useEffect(() => { if ( subgraphInfo?.daoName && diff --git a/src/store/daoInfo/useDaoInfoStore.ts b/src/store/daoInfo/useDaoInfoStore.ts index 23da0e6105..23f87235c1 100644 --- a/src/store/daoInfo/useDaoInfoStore.ts +++ b/src/store/daoInfo/useDaoInfoStore.ts @@ -6,8 +6,6 @@ export const initialDaoInfoStore: IDAO = { safe: null, subgraphInfo: null, modules: null, - gaslessVotingEnabled: false, - gasTankAddress: null, }; interface UpdateDAOInfoParams { @@ -61,11 +59,17 @@ export const useDaoInfoStore = create()(set => ({ } if (gaslessVotingEnabled !== undefined) { - updates.gaslessVotingEnabled = gaslessVotingEnabled; + if (!state.subgraphInfo) { + throw new Error('Subgraph info is not set'); + } + updates.subgraphInfo = { ...state.subgraphInfo, gaslessVotingEnabled }; } if (gasTankAddress !== undefined) { - updates.gasTankAddress = gasTankAddress; + if (!state.subgraphInfo) { + throw new Error('Subgraph info is not set'); + } + updates.subgraphInfo = { ...state.subgraphInfo, gasTankAddress }; } return updates; diff --git a/src/types/fractal.ts b/src/types/fractal.ts index 2fa25c0d25..ebcd861d52 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -142,6 +142,8 @@ export interface DAOSubgraph { childAddresses: Address[]; daoSnapshotENS: string | null; proposalTemplatesHash: string | null; + gaslessVotingEnabled: boolean; + gasTankAddress: Address | null; } // @todo should we add other Decent Module types here? @@ -156,11 +158,6 @@ export enum DecentModuleType { export interface IDAO { // replaces DaoInfo safe: GnosisSafe | null; - - // @todo: where's the best place for these 2 props to exist? - gaslessVotingEnabled: boolean; - gasTankAddress: Address | null; - subgraphInfo: DAOSubgraph | null; modules: DecentModule[] | null; } From 714237abd2e6925ed4da617276b62a6df5a7b504 Mon Sep 17 00:00:00 2001 From: Kellar Date: Mon, 10 Feb 2025 15:28:07 +0000 Subject: [PATCH 24/25] Asked AI to simplify. Boom. Nifty lil thing. --- src/store/daoInfo/useDaoInfoStore.ts | 30 ++++++++++------------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/store/daoInfo/useDaoInfoStore.ts b/src/store/daoInfo/useDaoInfoStore.ts index 23f87235c1..a60b738fc5 100644 --- a/src/store/daoInfo/useDaoInfoStore.ts +++ b/src/store/daoInfo/useDaoInfoStore.ts @@ -49,28 +49,18 @@ export const useDaoInfoStore = create()(set => ({ }, updateDAOInfo: ({ daoName, gaslessVotingEnabled, gasTankAddress }: UpdateDAOInfoParams) => { set(state => { - const updates: Partial = {}; - - if (daoName !== undefined) { - if (!state.subgraphInfo) { - throw new Error('Subgraph info is not set'); - } - updates.subgraphInfo = { ...state.subgraphInfo, daoName }; - } - - if (gaslessVotingEnabled !== undefined) { - if (!state.subgraphInfo) { - throw new Error('Subgraph info is not set'); - } - updates.subgraphInfo = { ...state.subgraphInfo, gaslessVotingEnabled }; + if (!state.subgraphInfo) { + throw new Error('Subgraph info is not set'); } - if (gasTankAddress !== undefined) { - if (!state.subgraphInfo) { - throw new Error('Subgraph info is not set'); - } - updates.subgraphInfo = { ...state.subgraphInfo, gasTankAddress }; - } + const updates: Partial = { + subgraphInfo: { + ...state.subgraphInfo, + ...(daoName !== undefined && { daoName }), + ...(gaslessVotingEnabled !== undefined && { gaslessVotingEnabled }), + ...(gasTankAddress !== undefined && { gasTankAddress }), + }, + }; return updates; }); From efd973f6a0e1a1318cb6f17f2ae0536dde6d063f Mon Sep 17 00:00:00 2001 From: Kellar Date: Mon, 10 Feb 2025 15:32:20 +0000 Subject: [PATCH 25/25] fix types --- src/types/fractal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/fractal.ts b/src/types/fractal.ts index ebcd861d52..5ccc4c441a 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -142,8 +142,8 @@ export interface DAOSubgraph { childAddresses: Address[]; daoSnapshotENS: string | null; proposalTemplatesHash: string | null; - gaslessVotingEnabled: boolean; - gasTankAddress: Address | null; + gaslessVotingEnabled?: boolean; + gasTankAddress?: Address; } // @todo should we add other Decent Module types here?