@@ -3,6 +3,7 @@ import { Trans } from '@lingui/macro';
33import { useQueryClient } from '@tanstack/react-query' ;
44import { AbiCoder , keccak256 , RLP } from 'ethers/lib/utils' ;
55import { useGovernanceTokensAndPowers } from 'src/hooks/governance/useGovernanceTokensAndPowers' ;
6+ import { useIsContractAddress } from 'src/hooks/useIsContractAddress' ;
67import { useModalContext } from 'src/hooks/useModal' ;
78import { useWeb3Context } from 'src/libs/hooks/useWeb3Context' ;
89import { VoteProposalData } from 'src/modules/governance/types' ;
@@ -201,7 +202,15 @@ export const GovVoteActions = ({
201202 const votingMachineAddress =
202203 governanceV3Config . votingChainConfig [ votingChainId ] . votingMachineAddress ;
203204
204- const withGaslessVoting = process . env . NEXT_PUBLIC_ENABLE_GASLESS_VOTING === 'true' ;
205+ // Smart contract wallets (e.g. Safe) can't use the sponsored path: the relay calls
206+ // `submitVoteBySignature`, which verifies the vote with `ecrecover`, so the signer must
207+ // be an EOA. The wallet has to be on the voting chain to sign (wallets reject typed data
208+ // for another chainId), so that's where a contract wallet will have code. Stay self-paid
209+ // until the lookup resolves.
210+ const { data : isContractWallet } = useIsContractAddress ( user , votingChainId ) ;
211+
212+ const withGaslessVoting =
213+ process . env . NEXT_PUBLIC_ENABLE_GASLESS_VOTING === 'true' && isContractWallet === false ;
205214
206215 const assets : Array < { underlyingAsset : string ; isWithDelegatedPower : boolean } > = [ ] ;
207216
0 commit comments