27 KiB
PRD: Gasless (Sponsored) Voting Feature
1. Overview
This document describes the requirements and user experience workflow for the Gasless (Sponsored) Voting feature. This feature allows DAOs to sponsor the network transaction fees for their members when voting on proposals, utilizing a Paymaster contract via ERC-4337 Account Abstraction.
Note: This PRD describes both the current implementation and desired improvements. Sections marked **Current Behavior:** describe how the feature works today. Sections marked **Desired Behavior / Issue:** describe proposed changes or identified problems.
2. Goals
- Improve voter participation by removing the friction of gas fees.
- Provide DAOs with a mechanism to subsidize voting costs for their members.
- Offer a seamless UX for voters when their transaction is sponsored.
- Clearly identify areas for UX improvement in the current implementation.
3. User Workflows
Architectural Note on Desired State (KV Flag Removal): The Current Behavior described below relies on a gaslessVotingEnabled flag stored in the DAO's KeyValuePairs contract to represent the DAO's intent to sponsor votes. However, analysis revealed this flag is misleading and insufficient:
- It only affects the frontend's determination of sponsorship eligibility (
canVoteForFree). - It does not prevent users from manually constructing and submitting UserOperations to a bundler if the Paymaster contract is otherwise funded and active on-chain, as the Paymaster's
validatePaymasterUserOpfunction does not check this external flag. This creates race conditions, particularly when attempting to withdraw the full deposit balance. - It creates ambiguity between the DAO's intent and the Paymaster's actual readiness (deployment, funding, stake status, validator configuration).
Therefore, the Desired Behavior / Issue sections outlined below describe a revised model where the KeyValuePairs flag is removed. In this desired state, the UI state, available actions, and sponsorship eligibility are determined solely by the Paymaster contract's verifiable on-chain status:
- Deployment status (
paymasterAddress !== null). - Deposit balance (
depositInfo.balance). - Stake lock status (
depositInfo.stake,depositInfo.withdrawTime), particularly ifstakingRequired. - Function Validator Registration: Crucially, whether a valid (non-zero) validator address is registered on the Paymaster for the specific voting strategy's
votefunction selector (paymaster.validators(strategyAddress, voteSelector) !== address(0)). Disabling sponsorship is achieved by callingremoveFunctionValidator, and enabling/re-enabling requiressetFunctionValidator. If funds are staked,unlockStakeis also needed to begin the withdrawal cooldown for those funds.
This approach provides a more accurate, secure (on-chain enforcement), and less confusing representation of the system's capabilities.
3.1. DAO Creator: Initial DAO Setup
This section describes the process during the initial creation of a new DAO.
**Current Behavior:**During the DAO creation flow, there is no option to enable the Gasless (Sponsored) Voting feature. The Paymaster contract cannot be deployed and activated as part of the DAO creation transaction.- Reasoning:
- Most networks require a minimum stake to be deposited for the Paymaster on the
EntryPointcontract (bundlerMinimumStake). - The
EntryPoint.addStakefunction requires the deposit to come from the Paymaster contract itself (msg.sendermust be the Paymaster). - Our
DAOPaymasterV1.addStakefunction facilitates this by forwardingmsg.valueto theEntryPoint, but this function is restricted byonlyOwner. - The designated owner of the Paymaster is the DAO Safe contract.
- During the creation transaction, the DAO Safe does not yet exist and, more importantly, possesses no funds to forward as
msg.valueto thePaymaster.addStakefunction.
- Most networks require a minimum stake to be deposited for the Paymaster on the
- Result: DAO users must enable sponsored voting after the DAO is created and funded, using the DAO Settings page (described in Section 3.2).
- Reasoning:
**Desired Behavior / Issue:**Allow the DAO creator to optionally enable Gasless Voting during the initial DAO setup transaction, provided the network requires staking (stakingRequired).- Workflow:
- The DAO creation UI presents an option like "Enable Sponsored Voting".
- If selected and
stakingRequiredis true:- The UI calculates the
bundlerMinimumStakerequired. - The UI informs the creator that enabling this feature requires them to send at least the
bundlerMinimumStakeamount asmsg.valuewith the DAO creation transaction. - The UI explains that this value will be forwarded to the newly created DAO Safe to cover the initial Paymaster stake.
- The UI calculates the
- The backend transaction builder (
DaoTxBuilderor similar) needs modification:- It must predict the addresses of the DAO Safe and the Paymaster contract using
CREATE2. - The main multi-send transaction must be structured to ensure the
msg.valuesent by the creator is correctly received by the predicted DAO Safe address upon its creation. - Include instructions within the multi-send to deploy the Paymaster contract.
- Include an internal transaction executed by the predicted DAO Safe address that calls the
addStake(bundlerMinimumStake)function on the predicted Paymaster address, forwarding the required funds received from the creator'smsg.value. - Include instructions to whitelist the DAO's voting strategies on the Paymaster.
- It must predict the addresses of the DAO Safe and the Paymaster contract using
- Complexity Note: This significantly increases the complexity and gas cost of the initial DAO creation transaction, involving address prediction, value forwarding, and chained internal calls within a single multi-send.
- Workflow:
3.2. DAO User: Managing Sponsored Voting Paymaster
Managing Settings (Post-DAO Creation - General Settings):
- Navigation:
**Current Behavior:**User navigates to DAO Settings -> General (SafeGeneralSettingsPage).
- Section Visibility:
**Current Behavior:**A "Sponsored Votes" section (GaslessVotingToggleDAOSettings) is visible if the feature flagflag_gasless_votingis active globally, AND Gasless voting is supported for the current configuration (gaslessVotingSupportedis true - requires AA support on network and non-Multisig governance).
- Scenario A: Paymaster Not Deployed (
paymasterAddress === null)- UI State:
**Current Behavior:**Displays a toggle reflecting the (now irrelevant) KV state. Does not clearly state Paymaster is missing.**Desired Behavior / Issue:**Display clear status: "Sponsorship Status: Inactive (Paymaster not deployed)." No toggle shown. Show "Deploy Paymaster" button only if user has proposal rights.
- Available Actions (Proposal):
**Current Behavior:**Clicking toggle ON proposes bundled deployment/KV/stake/whitelist.**Desired Behavior / Issue:**Clicking "Deploy Paymaster" button -> Propose: [- Deploy Paymaster (
deployModule). - (If
stakingRequired) Lock Required Funds viaaddStake(86400)withmsg.value=bundlerMinimumStake. - Whitelist Strategies via
setFunctionValidator(strategy, selector, validator). - Fund Initial Gas Tank via
depositTo(predictedPaymasterAddress, initialDepositAmount)(requires user input forinitialDepositAmount >= 0). ].
- Add UI confirmation explaining a Paymaster deployment is being proposed, potentially including the initial fund lock if required.
- Perform Treasury funding check before proposal creation if locking funds (
addStake) is included.
- Deploy Paymaster (
- UI State:
- Scenario B: Paymaster Deployed (
paymasterAddress !== null)- Common Information Display:
**Current Behavior:**Only displays Balance/Stake when toggle is ON. Address not shown. Stake status unclear. Validator status not shown.**Desired Behavior / Issue:**Always display the following:- Paymaster Address (
paymasterAddress), linked to block explorer. - Current Paymaster Deposit Balance (
depositInfo.balance) (aka "Gas Tank"). - Funds Locked for Sponsorship (
depositInfo.stake). - Sponsorship Status: Clearly display one of:
- "Active"
- Conditions:
paymaster.validators(...) != address(0)AND (stakingRequired == falseOR (stakingRequired == trueANDinfo.staked == trueANDinfo.stake >= bundlerMinimumStake)) - Meaning: Ready for sponsorship. On-chain validation passes and bundler requirements met.
- Conditions:
- "Active (Stake Issue)"
- Conditions:
paymaster.validators(...) != address(0)ANDstakingRequired == trueAND (info.staked == falseORinfo.stake < bundlerMinimumStake) - Meaning: Sponsorship passes on-chain (validator set), but bundlers will likely reject due to insufficient/unlocked stake. Needs stake configuration (
addStake/re-locking). Direct UserOp submission might still work.
- Conditions:
- "Deactivating (Cooldown Active)"
- Conditions:
paymaster.validators(...) == address(0)ANDinfo.withdrawTime > block.timestamp - Meaning: Sponsorship fails on-chain (validator not set). Stake unlock initiated, cooldown active.
- Conditions:
- "Deactivated (Ready to Withdraw Stake)"
- Conditions:
paymaster.validators(...) == address(0)ANDinfo.withdrawTime > 0ANDinfo.withdrawTime <= block.timestamp - Meaning: Sponsorship fails on-chain (validator not set). Stake withdrawal ready.
- Conditions:
- "Inactive (Validator Not Set)"
- Conditions:
paymaster.validators(...) == address(0)ANDinfo.staked == false - Meaning: Sponsorship fails on-chain (validator not set). Stake not in withdrawal cycle. Needs
setFunctionValidator.
- Conditions:
- Note: Status prioritizes on-chain possibility (Validator Set). Stake issues are secondary but critical for bundler compatibility. UI should clearly distinguish these. Flowchart Representation:
graph TD A[Start: Check Paymaster Status] --> D{Validator Set?}; D -- No --> B{withdrawTime > 0?}; D -- Yes --> E{Staking Required?}; B -- Yes --> C{withdrawTime <= <br/>block.timestamp?}; B -- No --> S3[Status: Inactive: <br/>Validator Not Set]; C -- Yes --> S5[Status: Deactivated: <br/>Ready to Withdraw Stake]; C -- No --> S4[Status: Deactivating: <br/>Cooldown Active]; E -- No --> S1[Status: Active]; E -- Yes --> F{staked == true AND <br/>stake >= minStake?}; F -- Yes --> S1; F -- No --> S2[Status: Active: <br/>Stake Issue]; - "Active"
- Sponsoring Functional Status: Display "Inactive" only if Sponsorship Status is
Inactive (Validator Not Set),Deactivating, orDeactivated. Display "Needs Attention" or similar ifActive (Stake Issue). Otherwise, determined by technical readiness (sufficient deposit balance in gas tank).
- Paymaster Address (
- Sub-Scenario 4.1: Sponsorship Active (
paymaster.validators(...) != address(0)AND (stakingRequired == falseOR (stakingRequired == trueANDinfo.staked == trueANDinfo.stake >= bundlerMinimumStake)))- UI State:
**Current Behavior:**Toggle reflects KV state. Status/sufficiency unclear unless KVtrue.**Desired Behavior / Issue:**Display Sponsorship Status: "Active". If activation requires locked funds (stakingRequired), show sufficiency ("X Funds Locked / Y Required"). Buttons disabled if user lacks proposal rights.
- Available Actions (Proposal):
**Current Behavior:**Toggle ON proposes KV set + stake top-up + whitelist. Toggle OFF proposes KV set tofalse. Separate Refill/Withdraw Deposit.**Desired Behavior / Issue:**Provide explicit action buttons:- "Deactivate Sponsorship" -> Propose: [Call
removeFunctionValidator(...)for all voting strategies. Ifinfo.stake > 0, also callunlockStake()]. Add UI Warning: "Turns off sponsoring immediately by removing strategy validation. If funds are staked, also starts the [~1-day] cooldown before locked funds can be withdrawn." (This replaces KV disabling). - Pre-check: Only available if
depositInfo.balance > 0. - Offer "Withdraw Gas Tank" -> Propose: [Call
withdrawTo(recipient, amount)]. - Note: It should be possible to bundle the "Withdraw Gas Tank" action (
withdrawTo) with either "Deactivate Sponsorship" (removeFunctionValidator/unlockStake) or "Increase Locked Funds" (addStake) in a single proposal.
- "Deactivate Sponsorship" -> Propose: [Call
- UI State:
- Sub-Scenario 4.2: Sponsorship Active (Stake Issue) (
paymaster.validators(...) != address(0)ANDstakingRequired == trueAND (info.staked == falseORinfo.stake < bundlerMinimumStake))- UI State:
**Desired Behavior / Issue:**Display Sponsorship Status: "Active (Stake Issue)". Display Prominent Warning: "Sponsorship should pass on-chain, but bundlers will likely reject UserOps due to insufficient or unlocked stake. Configuration needed." Buttons disabled if user lacks proposal rights.
- Available Actions (Proposal):
**Desired Behavior / Issue:**- (If
info.staked == false)- Pre-check: Verify DAO Treasury balance >=
max(0, bundlerMinimumStake - info.stake). - "Re-lock Stake" -> Propose: [
addStake(currentUnstakeDelay)withmsg.value = max(0, bundlerMinimumStake - info.stake)]. Explain: "Re-locks existing stake and tops up to minimum if needed. Uses the previously set unstake delay." (Requires fetchingunstakeDelaySec).
- Pre-check: Verify DAO Treasury balance >=
- (If
info.staked == trueANDinfo.stake < bundlerMinimumStake)- Pre-check: Verify DAO Treasury balance >=
bundlerMinimumStake - info.stake. - "Increase Locked Funds" -> Propose: [
addStake(currentUnstakeDelay)withmsg.value = bundlerMinimumStake - info.stake]. Explain: "Tops up locked funds to meet the minimum requirement."
- Pre-check: Verify DAO Treasury balance >=
- Pre-check: Only available if
depositInfo.balance > 0. - Offer "Withdraw Gas Tank" -> Propose: [Call
withdrawTo(recipient, amount)]. - "Deactivate Sponsorship" -> Propose: [
removeFunctionValidator(...)for all strategies. Ifinfo.stake > 0ANDinfo.staked == true, also callunlockStake()]. UI Warning as before. - Note: Bundling "Deactivate Sponsorship" (
removeFunctionValidator/unlockStake) with "Withdraw Gas Tank" (withdrawTo) should be possible.
- (If
- UI State:
- Sub-Scenario 4.3: Sponsorship Deactivating (Cooldown Active) (
paymaster.validators(...) == address(0),info.withdrawTime > block.timestamp)- UI State:
**Current Behavior:**Unclear UI representation.**Desired Behavior / Issue:**Display Sponsorship Status: "Deactivating (Validator Removed / Cooldown Period: ~X days remaining)". Display Prominent Warning: "Sponsored voting is inactive." Buttons disabled if user lacks proposal rights.
- Available Actions (Proposal):
**Current Behavior:**Unclear available actions.**Desired Behavior / Issue:**- Offer "Propose Locked Funds Withdrawal" -> Propose: [Call
withdrawStake(recipient)]. Add UI Explanation: "Proposal execution only possible after cooldown ends (~X days remaining)." - Pre-check: Only available if
depositInfo.balance > 0. - Offer "Withdraw Gas Tank" -> Propose: [Call
withdrawTo(recipient, amount)]. - Offer "Reactivate Sponsorship" -> Propose: [
- Call
setFunctionValidator(...). - If
stakingRequired:- Pre-check: Verify DAO Treasury balance >=
max(0, bundlerMinimumStake - info.stake). - Call
addStake(86400)withmsg.value = max(0, bundlerMinimumStake - info.stake)]. Explain: "Re-whitelists strategy validation, cancels the pending stake withdrawal, re-locks funds (potentially topping up), turning sponsorship back on."
- Pre-check: Verify DAO Treasury balance >=
- Call
- Note: It should be possible to bundle "Propose Locked Funds Withdrawal" and "Withdraw Gas Tank" into a single proposal.
- Offer "Propose Locked Funds Withdrawal" -> Propose: [Call
- UI State:
- Sub-Scenario 4.4: Sponsorship Deactivated (Ready to Withdraw Stake) (
paymaster.validators(...) == address(0),info.withdrawTime > 0,info.withdrawTime <= block.timestamp)- UI State:
**Current Behavior:**Unclear UI representation.**Desired Behavior / Issue:**Display Sponsorship Status: "Deactivated (Ready to Withdraw Stake)". Display Prominent Warning: "Sponsored voting is inactive (Validator Removed)." Buttons disabled if user lacks proposal rights.
- Available Actions (Proposal):
**Current Behavior:**Unclear available actions.**Desired Behavior / Issue:**- Offer "Withdraw Locked Funds" -> Propose: [Call
withdrawStake(recipient)]. - Offer "Reactivate Sponsorship" -> Propose: [
- Call
setFunctionValidator(...). - If
stakingRequired:- Pre-check: Verify DAO Treasury balance >=
max(0, bundlerMinimumStake - info.stake). - Calculate
stakeDelta = max(0, bundlerMinimumStake - info.stake). - Call
addStake(86400)withmsg.value = stakeDelta]. Explain: "Re-whitelists strategy validation, tops up stake to meet minimum (if required), cancels pending withdrawal, and re-locks funds using a 1-day delay, turning vote sponsoring back on."
- Pre-check: Verify DAO Treasury balance >=
- Call
- Pre-check: Only available if
depositInfo.balance > 0. - Offer "Withdraw Gas Tank" -> Propose: [Call
withdrawTo(recipient, amount)]. - Note: It should be possible to bundle "Withdraw Locked Funds" and "Withdraw Gas Tank" into a single proposal.
- Offer "Withdraw Locked Funds" -> Propose: [Call
- UI State:
- Sub-Scenario 4.5: Sponsorship Inactive (Validator Not Set) (
paymaster.validators(...) == address(0)ANDinfo.staked == false)- UI State:
**Current Behavior:**Toggle reflects KV state. Stake status implied 0. Validator status ignored.**Desired Behavior / Issue:**Display Sponsorship Status: "Inactive (Validator Not Set)". Show warning label ("Activation Required: Set validator" or "Set validator & Lock Funds"). Buttons disabled if user lacks proposal rights.
- Available Actions (Proposal):
**Current Behavior:**Toggle ON proposes KV set + Add Stake + Whitelist.**Desired Behavior / Issue:**- Offer "Activate Sponsorship" -> Propose: [
- Call
setFunctionValidator(...). - If
stakingRequired: - Pre-check: Verify DAO Treasury balance >=bundlerMinimumStake. - CalladdStake(bundlerMinimumStake)with appropriate delay (e.g., 86400). ].
- Call
- Pre-check: Only available if
depositInfo.balance > 0. - Offer "Withdraw Gas Tank" -> Propose: [Call
withdrawTo(recipient, amount)].
- Offer "Activate Sponsorship" -> Propose: [
- UI State:
- Common Information Display:
- Refill:
**Current Behavior:**An "Refill" button (addGas) allows a user (with proposal rights for proposal method, or any user for direct deposit) to add funds to the paymaster deposit (gas tank). This button is likely only visible if the Paymaster is deployed.- Clicking opens a modal (
ModalType.REFILL_GAS). - User enters the amount to add.
- User chooses the method:
- Via Proposal: Creates a new DAO proposal (
prepareRefillPaymasterAction) to transfer funds from the DAO treasury to the paymaster's deposit on the EntryPoint contract. The user is navigated to the proposal creation page to submit it. - Direct Deposit: User sends funds directly from their connected wallet to the paymaster's deposit on the EntryPoint contract (
EntryPoint07Abi.depositTo).
- Via Proposal: Creates a new DAO proposal (
- Clicking opens a modal (
**Desired Behavior / Issue:**Ensure the "Refill" button is only available when the Paymaster is deployed (paymasterAddress !== null).
3.3. DAO Member: Voting on a Proposal
- Navigate to Proposal:
**Current Behavior:**User views an active proposal (FractalProposalState.ACTIVE).
- Voting Interface (
CastVote):**Current Behavior:**User interacts with the voting options (e.g., For, Against, Abstain).
- System Check (Behind the Scenes):
**Current Behavior:**The system determines if the vote can be sponsored by evaluatingcanVoteForFreeinCastVote.tsx. This involves several checks:- Global Feature Flag: Checks if
flag_gasless_votingis enabled globally (useFeatureFlag). - DAO KV Setting: Checks if the DAO has
gaslessVotingEnabledset totrue(on-chain state fromKeyValuePairsviauseDaoInfoStore). - Paymaster Readiness (via
useCastVote->canCastGaslessVotestate):- A
paymasterAddressmust exist for the DAO. - The
estimateGaslessVoteGasfunction withinuseCastVoteis called. - This function attempts to estimate the UserOperation gas cost by calling
bundlerClient.estimateUserOperationGas. - Implicit Bundler Check: This estimation call must succeed without throwing an error. The system currently relies on the bundler potentially rejecting this estimation (throwing an error) if the Paymaster would fail validation later (e.g., due to insufficient stake, incorrect configuration, etc.). If an error occurs during estimation,
canCastGaslessVoteis set tofalse. - Explicit Balance Check: If estimation succeeds, the function fetches the Paymaster's deposit balance (
paymasterBalance) from the EntryPoint contract. - It compares the fetched
paymasterBalanceto the estimatedgasCostreturned by the bundler. - The
canCastGaslessVotestate variable is set totrueonly if the estimation succeeded andpaymasterBalance >= gasCost.
- A
- Final Determination:
canVoteForFreeis ultimatelytrueif and only ifgaslessFeatureEnabled && gaslessVotingEnabled && canCastGaslessVoteevaluates totrue.
- Global Feature Flag: Checks if
**Desired Behavior / Issue:**The determination of voting eligibility should be made proactively and explicitly within the frontend based on the Paymaster's actual state and balance.- Check Global Feature Flag: Verify
flag_gasless_votingis enabled. If not, sponsorship is unavailable. - Check Paymaster Deployment: Verify a
paymasterAddressexists for the DAO. If not, sponsorship is unavailable. - Determine Paymaster Sponsorship Status: Use the logic defined in Section 3.2.4 (based on validator status,
DepositInfo,stakingRequired, etc.) to determine the current status (e.g., "Active", "Active (Stake Issue)", "Inactive (Validator Not Set)", "Deactivating", "Deactivated"). - Eligibility Check:
- If Sponsorship Status is exactly
"Active":- Attempt to estimate the gas cost (
estimatedGasCost) for the specific vote UserOperation. - Fetch the current Paymaster deposit balance (
depositInfo.balance). - Compare balance to cost (
depositInfo.balance >= estimatedGasCost).
- Attempt to estimate the gas cost (
- If Sponsorship Status is not
"Active": Sponsorship is considered unavailable for this vote.
- If Sponsorship Status is exactly
- Check Global Feature Flag: Verify
- Determine Voting Experience:
**Current Behavior:**- Sponsored Path (
canVoteForFreeis true):- User selects their vote choice.
- User clicks the "Vote" button.
- The
castGaslessVotefunction is called. - The user is prompted to sign a UserOperation via their wallet.
- The signed UserOperation is sent to the bundler (
bundlerClient.sendUserOperation). - The bundler includes the transaction on-chain, with the Paymaster covering the gas fees.
- On successful inclusion, a confirmation modal is shown (
ModalType.GASLESS_VOTE_SUCCESS) indicating the vote was sponsored ("Your vote is sponsored."). - If the user rejects the signature request (
UserRejectedRequestError), an error message is shown via toast. - Fallback on Error: If another error occurs during the gasless submission process (e.g., bundler error, paymaster validation fails), an error toast appears (
castVoteError), and the system automatically attempts to fall back to the standard voting path after a 5-second delay (setTimeout(() => { castVote(...) }, 5000)).
- Standard Path (
canVoteForFreeis false):- User selects their vote choice.
- The button simply says "Vote" (without the "for free" indication).
- User clicks the "Vote" button.
- The standard
castVotefunction is called. - The user is prompted to sign and send a standard blockchain transaction via their wallet, paying the associated gas fee themselves.
- The UI does not proactively explain why sponsoring is unavailable; the user only sees the standard voting option.
- Sponsored Path (
**Desired Behavior / Issue:**Based on the checks above, the UI presents the appropriate voting option and handles the submission:- Scenario A: Sponsorship Status == "Active"
- Sub-Scenario A.1: Sufficient Balance (
depositInfo.balance >= estimatedGasCost)- UI: Show "Vote for Free" button.
- Action: User clicks -> Proceed with
castGaslessVoteflow:- User signs UserOperation.
- Submit UserOp to bundler.
- Show pending modal.
- On confirmation, show success modal.
- Error Handling: If
castGaslessVotefails post-submission (bundler/paymaster error), display error modal with option to retry via standard tx.
- Sub-Scenario A.2: Insufficient Balance (
depositInfo.balance < estimatedGasCost)- UI: Show standard "Vote" button. Display message: "Sponsorship is active, but the gas tank is too low for this vote. Refill via Direct Deposit possible."
- Action: User clicks -> Proceed with standard
castVoteflow (User pays gas).
- Sub-Scenario A.1: Sufficient Balance (
- Scenario B: Sponsorship Status != "Active" (i.e., "Active (Stake Issue)", "Inactive (Validator Not Set)", "Deactivating", "Deactivated")
- UI: Show standard "Vote" button.
- Action: User clicks -> Proceed with standard
castVoteflow (User pays gas). - Note: No extra explanation is given to the user about why sponsorship is unavailable in these cases.
- Scenario A: Sponsorship Status == "Active"
4. Technical Details (High-Level)
- Feature Flag:
flag_gasless_voting - Core Components:
GaslessVotingToggleDAOSettings(needs redesign -> becomes PaymasterStatus component),CastVotecomponent,useCastVotehook,RefillGasTankModal. - Key Hooks:
useDepositInfo,(KV logic removed),useKeyValuePairsuseSubmitProposal. - Contracts: Paymaster (
DAOPaymasterV1mastercopy deployed viaZodiacModuleProxyFactory),EntryPoint07,(KV logic removed), Voting Strategy Validators (KeyValuePairsLinearERC20VotingV1ValidatorV1,LinearERC721VotingV1ValidatorV1). - State Management:
useDaoInfoStore(removegaslessVotingEnabledstate, keeppaymasterAddress). - Utils:
gaslessVoting.ts(e.g.,getPaymasterAddress),prepareRefillPaymasterActionData.ts. - Backend/Infrastructure: Relies on an ERC-4337 Bundler service (RPC endpoint configured via
rpcEndpoint).