Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gasless voting UI #2692

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
83fa276
Add GasslessVotingToggleCard
DarksightKellar Jan 27, 2025
61e24f1
Add GasslessVotingToggleDAOSettings
DarksightKellar Jan 27, 2025
af5ada3
Move GasslessVotingToggle
DarksightKellar Jan 27, 2025
2db640a
Add "add gas" button
DarksightKellar Jan 27, 2025
6c86f3e
Move feature behing flag
DarksightKellar Jan 27, 2025
f540143
Include feature for multisig create
DarksightKellar Jan 27, 2025
259aa58
`gassless` -> `gasless` 🤦🏾‍♂️
DarksightKellar Jan 28, 2025
d168e33
cleanup
DarksightKellar Jan 28, 2025
1e623e0
Reduce instances of hardcoded demo address to 1
DarksightKellar Jan 29, 2025
f8afb0d
Remove balance prop. Read data from native token
DarksightKellar Jan 29, 2025
e113bbc
Balance and address don't make sense for create DAO as there's no suc…
DarksightKellar Jan 29, 2025
cfb7a1a
Don't show balance if not loaded
DarksightKellar Jan 29, 2025
305ebf1
Some cleanup
DarksightKellar Jan 31, 2025
3094fdf
Add gasless supported flag to network config
DarksightKellar Jan 31, 2025
21e4423
Merge branch 'develop' into eng-25-gassless-voting-ui
DarksightKellar Jan 31, 2025
e8e024f
Move propose changes button to bottom of page. bugfix
DarksightKellar Feb 4, 2025
748f9ce
Add `updateDAOInfo` to useDaoInfoStore, for setting gasless voting fl…
DarksightKellar Feb 4, 2025
a206d50
Remove unused types
DarksightKellar Feb 4, 2025
5db5d82
Add some more placeholder logic to onToggle and add gas button click
DarksightKellar Feb 4, 2025
1d54f0b
DRY
DarksightKellar Feb 4, 2025
bbbe6fe
dont hardcode ETH
DarksightKellar Feb 4, 2025
0a254bb
Merge branch 'develop' into eng-25-gassless-voting-ui
DarksightKellar Feb 4, 2025
d94b010
Move gaslessVotingSupported conditional rendering into `GaslessVoting…
DarksightKellar Feb 10, 2025
c044f3b
re-arrange some stuff
DarksightKellar Feb 10, 2025
4f91044
Move dao gasless state props to subgraphInfo
DarksightKellar Feb 10, 2025
714237a
Asked AI to simplify. Boom. Nifty lil thing.
DarksightKellar Feb 10, 2025
efd973f
fix types
DarksightKellar Feb 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/DaoCreator/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const initialState: CreatorFormState = {
daoName: '',
governance: GovernanceType.AZORIUS_ERC20,
snapshotENS: '',
gaslessVoting: false,
DarksightKellar marked this conversation as resolved.
Show resolved Hide resolved
},
erc20Token: {
tokenCreationType: TokenCreationType.IMPORTED,
Expand Down
12 changes: 12 additions & 0 deletions src/components/DaoCreator/formComponents/AzoriusGovernance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ 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';
import { BigIntInput } from '../../ui/forms/BigIntInput';
import { CustomNonceInput } from '../../ui/forms/CustomNonceInput';
import { LabelComponent } from '../../ui/forms/InputComponent';
Expand Down Expand Up @@ -100,6 +102,8 @@ export function AzoriusGovernance(props: ICreationStepProps) {
setFieldValue('azorius.executionPeriod', { bigintValue: minutes, value: minutes.toString() });
}, [setFieldValue, executionPeriodDays]);

const { gaslessVotingSupported } = useNetworkConfigStore();

return (
<>
<StepWrapper
Expand Down Expand Up @@ -252,6 +256,14 @@ export function AzoriusGovernance(props: ICreationStepProps) {
/>
</Box>
)}
{gaslessVotingSupported && (
<GaslessVotingToggleDAOCreate
isEnabled={values.essentials.gaslessVoting}
onToggle={() =>
setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)
}
/>
)}
DarksightKellar marked this conversation as resolved.
Show resolved Hide resolved
<StepButtons
{...props}
isEdit={mode === DAOCreateMode.EDIT}
Expand Down
13 changes: 13 additions & 0 deletions src/components/DaoCreator/formComponents/Multisig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ 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';
import { useNetworkConfigStore } from '../../../providers/NetworkConfig/useNetworkConfigStore';
import { ICreationStepProps } from '../../../types';
import { GaslessVotingToggleDAOCreate } from '../../ui/GaslessVotingToggle';
import { AddressInput } from '../../ui/forms/EthAddressInput';
import { LabelComponent } from '../../ui/forms/InputComponent';
import LabelWrapper from '../../ui/forms/LabelWrapper';
Expand Down Expand Up @@ -31,6 +33,8 @@ export function Multisig(props: ICreationStepProps) {
return updatedNum !== num;
};

const { gaslessVotingSupported } = useNetworkConfigStore();

return (
<>
<StepWrapper
Expand Down Expand Up @@ -151,6 +155,15 @@ export function Multisig(props: ICreationStepProps) {
</LabelComponent>
</Flex>
</StepWrapper>

{gaslessVotingSupported && (
<GaslessVotingToggleDAOCreate
isEnabled={values.essentials.gaslessVoting}
onToggle={() =>
setFieldValue('essentials.gaslessVoting', !values.essentials.gaslessVoting)
}
/>
)}
DarksightKellar marked this conversation as resolved.
Show resolved Hide resolved
<StepButtons
{...props}
isEdit={mode === DAOCreateMode.EDIT}
Expand Down
182 changes: 182 additions & 0 deletions src/components/ui/GaslessVotingToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { Box, Text, HStack, Switch, Flex, Icon, Button } from '@chakra-ui/react';
import { GasPump, WarningCircle } from '@phosphor-icons/react';
import { useTranslation } from 'react-i18next';
import { useBalance } from 'wagmi';
import { DETAILS_BOX_SHADOW } from '../../constants/common';
import { isFeatureEnabled } from '../../helpers/featureFlags';
import { useDaoInfoStore } from '../../store/daoInfo/useDaoInfoStore';
import { formatCoin } from '../../utils';
import EtherscanLink from './links/EtherscanLink';
import Divider from './utils/Divider';

interface GaslessVotingToggleProps {
isEnabled: boolean;
onToggle: () => void;
}

function GaslessVotingToggleContent({
isEnabled,
onToggle,
isSettings,
}: GaslessVotingToggleProps & { isSettings?: boolean }) {
const { t } = useTranslation('daoCreate');

return (
<Box
display="flex"
flexDirection="column"
gap="1.5rem"
w="100%"
>
<HStack
justify="space-between"
width="100%"
alignItems="flex-start"
>
<Flex
flexDirection="column"
gap="0.25rem"
>
<Text textStyle={isSettings ? 'heading-small' : 'helper-text'}>
{isSettings
? t('gaslessVotingLabelSettings', { ns: 'daoEdit' })
: t('gaslessVotingLabel')}
</Text>
<Text
textStyle={isSettings ? 'label-large' : 'helper-text'}
color="neutral-7"
w="17.25rem"
>
{isSettings
? t('gaslessVotingDescriptionSettings', { ns: 'daoEdit' })
: t('gaslessVotingDescription')}
</Text>
</Flex>
<Switch
size="md"
isChecked={isEnabled}
onChange={() => onToggle()}
variant="secondary"
/>
</HStack>
</Box>
);
}

export function GaslessVotingToggleDAOCreate(props: GaslessVotingToggleProps) {
const { t } = useTranslation('daoCreate');

if (!isFeatureEnabled('flag_gasless_voting')) return null;

return (
<Box
borderRadius="0.75rem"
bg="neutral-2"
p="1.5rem"
display="flex"
flexDirection="column"
alignItems="flex-start"
gap="1.5rem"
boxShadow={DETAILS_BOX_SHADOW}
mt={2}
>
<GaslessVotingToggleContent {...props} />

<Box
p="1rem"
bg="neutral-3"
borderRadius="0.75rem"
>
<Flex alignItems="center">
<Icon
as={WarningCircle}
color="lilac-0"
width="1.5rem"
height="1.5rem"
/>
<Text
color="lilac-0"
marginLeft="1rem"
>
{t('gaslessVotingGettingStarted')}
</Text>
</Flex>
</Box>
</Box>
);
}

export function GaslessVotingToggleDAOSettings(props: GaslessVotingToggleProps) {
const { t } = useTranslation('daoEdit');
const { safe } = useDaoInfoStore();

// @todo: Use the paymaster address here.
const { data: balance } = useBalance({ address: safe?.address });

if (!isFeatureEnabled('flag_gasless_voting')) return null;
if (!safe) return null;

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;
DarksightKellar marked this conversation as resolved.
Show resolved Hide resolved

return (
<Box
gap="1.5rem"
display="flex"
flexDirection="column"
>
<Divider
my="1rem"
w={{ base: 'calc(100% + 1.5rem)', md: 'calc(100% + 3rem)' }}
mx={{ base: '-0.75rem', md: '-1.5rem' }}
/>

<GaslessVotingToggleContent
{...props}
isSettings
/>

{gasTankAddress && (
<Box
borderRadius="0.75rem"
border="1px solid"
borderColor="neutral-3"
p="1rem 0.5rem"
w="100%"
>
<EtherscanLink
type="address"
value={gasTankAddress}
isTextLink
>
<Text as="span">{gasTankAddress}</Text>
</EtherscanLink>
</Box>
)}

<Flex
mt="-0.55rem"
justifyContent="space-between"
>
<Text textStyle="body-small">
{t('titleBalance', { ns: 'modals' })}:{' '}
<Text
as="span"
color="neutral-7"
>
{formattedNativeTokenBalance}
</Text>
</Text>
<Button
variant="secondary"
leftIcon={<Icon as={GasPump} />}
>
{t('addGas')}
</Button>
</Flex>
</Box>
);
}
2 changes: 1 addition & 1 deletion src/helpers/featureFlags.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const FEATURE_FLAGS = ['flag_dev', '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];
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/locales/en/daoCreate.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
"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."
}
5 changes: 4 additions & 1 deletion src/i18n/locales/en/daoEdit.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"cannotModifyGovernance": "You do not have permissions to modify this Safe's governance."
"cannotModifyGovernance": "You do not have permissions to modify this Safe's governance.",
"gaslessVotingLabelSettings": "Sponsor Gas",
"gaslessVotingDescriptionSettings": "Fund transaction fees for DAO voters from a shared DAO gas tank.",
"addGas": "Add Gas"
}
8 changes: 8 additions & 0 deletions src/pages/dao/settings/general/SafeGeneralSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 { 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';
Expand Down Expand Up @@ -205,6 +206,13 @@ export function SafeGeneralSettingsPage() {
</Button>
</>
)}

<GaslessVotingToggleDAOSettings
isEnabled={false}
onToggle={function (): void {
throw new Error('Function not implemented.');
}}
/>
</SettingsContentBox>
) : (
<Flex
Expand Down
1 change: 1 addition & 0 deletions src/providers/NetworkConfig/networks/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const baseConfig: NetworkConfig = {
GovernanceType.AZORIUS_ERC20,
GovernanceType.AZORIUS_ERC721,
],
gaslessVotingSupported: false,
};

export default baseConfig;
1 change: 1 addition & 0 deletions src/providers/NetworkConfig/networks/mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export const mainnetConfig: NetworkConfig = {
GovernanceType.AZORIUS_ERC20,
GovernanceType.AZORIUS_ERC721,
],
gaslessVotingSupported: true,
};

export default mainnetConfig;
1 change: 1 addition & 0 deletions src/providers/NetworkConfig/networks/optimism.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const optimismConfig: NetworkConfig = {
GovernanceType.AZORIUS_ERC20,
GovernanceType.AZORIUS_ERC721,
],
gaslessVotingSupported: false,
};

export default optimismConfig;
1 change: 1 addition & 0 deletions src/providers/NetworkConfig/networks/polygon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const polygonConfig: NetworkConfig = {
GovernanceType.AZORIUS_ERC20,
GovernanceType.AZORIUS_ERC721,
],
gaslessVotingSupported: false,
};

export default polygonConfig;
1 change: 1 addition & 0 deletions src/providers/NetworkConfig/networks/sepolia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export const sepoliaConfig: NetworkConfig = {
GovernanceType.AZORIUS_ERC20,
GovernanceType.AZORIUS_ERC721,
],
gaslessVotingSupported: true,
};

export default sepoliaConfig;
1 change: 1 addition & 0 deletions src/types/createDAO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export type DAOEssentials = {
daoName: string;
governance: GovernanceType;
snapshotENS: string;
gaslessVoting: boolean;
};

export type DAOGovernorERC20Token<T = bigint> = {
Expand Down
1 change: 1 addition & 0 deletions src/types/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,5 @@ export type NetworkConfig = {
};
};
createOptions: GovernanceType[];
gaslessVotingSupported: boolean;
};