The logic inside state() needs to be:
This is because users are allowed to vote at block.timestamp = proposal.endTime
as can be seen inside castVote():
The following scenario can happen:
At timestamp = proposal.endTime - 1
proposal has 100 YES votes more than NO votes and quorum has been reached.
At timestamp = proposal.endTime
two actions are performed:
First, Alice votes NO with her 500 votes
Second, Bob calls execute()
Due to tx ordering/higher gas-fee paid Bob's tx precedes Alice's tx in the mempool
state()
returns this proposal as ProposalState.Succeeded
and hence _queueProposal()
is called successfully inside execute()
Alice's votes now get added to proposalVote.againstVotes
Now after the queueing period ends, a call needs to be made to execute()
again. This time when state()
is internally called by execute()
, Alice's votes play a part and this check fails resulting in the proposal being DEFEATED:
So execute()
reverts with error InvalidProposalState()
All users expected the proposal to go through since it was already queued, but it fails now.
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.