When the function castVoteWithReasonAndParams
is used to split votes, the event VoteCastWithParams
with the support
argument is emitted, although this is ignored in this case.
GovernorCountingFractional
supports splitting votes between Against/For/Abstain. To do so, _countVote
checks if voteData
is non-zero. If so, the split is parsed based on this data and the argument support
is completely ignored. The function _castVote
(within Governor
: https://github.com/Cyfrin/2024-10-zksync/blob/cfc1251de29379a9548eeff1eea3c78267288356/zk-governance/l2-contracts/lib/openzeppelin-contracts/contracts/governance/Governor.sol#L581) calls _countVote
and afterwards emits an event. If params
has length zero, VoteCast
is emitted with the support
and weight
parameters, which is correct when using GovernorCountingFractional
(as it also allocates the whole weight to the chosen support value in this case).
However, when the params are non-zero, the event VoteCastWithParams
is emitted with the same weight
and support
parameters. But these parameters are not directly related to the vote in this case. The weight
is just the total weight (that can be arbitrarily split, even with multiple calls) and support
is completely ignored. Note that the support
value could even have invalid values in these events, as it is not verified in _countVoteFractional
.
If an off-chain system (that tracks the voting progress or even makes decision automatically based on it, for instance with a Subgraph) just parses support
and weight
, it will lead to completely wrong result and would be easily gameable. For instance, someone with weight 10 could vote to times with vote 1 for "against", but always set the support parameter to "for". The off-chain system would then think that this were 100 votes "for", which is wrong. Setting invalid support parameters could also lead to crashes / errors in off-chain systems, as they might only expect the three possible enum values.
Even if an off-chain system is aware of these intricate details, actually parsing the vote result based on the events is hard: You need to decode the params
byte array for every VoteCastWithParams
event to get the correct votes.
It is recommended to introduce custom events within GovernorCountingFractional
that emit the actual voting result directly. This will avoid errors in off-chain systems. The _castVote
function could also be overwritten to prevent that these confusing events are emitted.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.