Skip to content

Commit

Permalink
hassucceeded
Browse files Browse the repository at this point in the history
  • Loading branch information
novaknole committed Nov 4, 2024
1 parent 427a7f5 commit e906746
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 10 deletions.
34 changes: 24 additions & 10 deletions packages/contracts/src/MajorityVotingBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,15 @@ abstract contract MajorityVotingBase is
/// @inheritdoc IMajorityVoting
function canExecute(
uint256 _proposalId
) public view virtual override(IMajorityVoting, IProposal) returns (bool) {
) public view virtual override(IMajorityVoting) returns (bool) {
return _canExecute(_proposalId);
}

/// @inheritdoc IProposal
function hasSucceeded(uint256 _proposalId) public view virtual returns (bool) {
return _hasSucceeded(_proposalId);
}

/// @inheritdoc IMajorityVoting
function isSupportThresholdReached(uint256 _proposalId) public view virtual returns (bool) {
Proposal storage proposal_ = proposals[_proposalId];
Expand Down Expand Up @@ -596,18 +601,12 @@ abstract contract MajorityVotingBase is
VoteOption _voteOption
) internal view virtual returns (bool);

/// @notice Internal function to check if a proposal can be executed. It assumes the queried proposal exists.
/// @notice An internal function that checks if the proposal succeeded or not.
/// @param _proposalId The ID of the proposal.
/// @return True if the proposal can be executed, false otherwise.
/// @dev Threshold and minimal values are compared with `>` and `>=` comparators, respectively.
function _canExecute(uint256 _proposalId) internal view virtual returns (bool) {
/// @return Returns `true` if the proposal succeeded depending on the thresholds and voting modes.
function _hasSucceeded(uint256 _proposalId) internal view virtual returns (bool) {
Proposal storage proposal_ = proposals[_proposalId];

// Verify that the vote has not been executed already.
if (proposal_.executed) {
return false;
}

if (_isProposalOpen(proposal_)) {
// Early execution
if (proposal_.parameters.votingMode != VotingMode.EarlyExecution) {
Expand All @@ -632,6 +631,21 @@ abstract contract MajorityVotingBase is
return true;
}

/// @notice Internal function to check if a proposal can be executed. It assumes the queried proposal exists.
/// @param _proposalId The ID of the proposal.
/// @return True if the proposal can be executed, false otherwise.
/// @dev Threshold and minimal values are compared with `>` and `>=` comparators, respectively.
function _canExecute(uint256 _proposalId) internal view virtual returns (bool) {
Proposal storage proposal_ = proposals[_proposalId];

// Verify that the vote has not been executed already.
if (proposal_.executed) {
return false;
}

return _hasSucceeded(_proposalId);
}

/// @notice Internal function to check if a proposal vote is still open.
/// @param proposal_ The proposal struct.
/// @return True if the proposal vote is open, false otherwise.
Expand Down
17 changes: 17 additions & 0 deletions packages/contracts/test/10_unit-testing/11_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,8 @@ describe('TokenVoting', function () {
expect(await plugin.isSupportThresholdReachedEarly(id)).to.be.true;
expect(await plugin.isMinParticipationReached(id)).to.be.true;
expect(await plugin.canExecute(id)).to.equal(false);
// Still return false as voting mode is Standard and proposal is still open.
expect(await plugin.hasSucceeded(id)).to.be.false;
});

it('can execute normally if participation and support are met', async () => {
Expand Down Expand Up @@ -2062,6 +2064,8 @@ describe('TokenVoting', function () {
expect(await plugin.isSupportThresholdReached(id)).to.be.true;
expect(await plugin.isMinParticipationReached(id)).to.be.true;
expect(await plugin.canExecute(id)).to.equal(true);

expect(await plugin.hasSucceeded(id)).to.be.true;
});

it('does not execute early when voting with the `tryEarlyExecution` option', async () => {
Expand Down Expand Up @@ -2413,6 +2417,7 @@ describe('TokenVoting', function () {
expect(await plugin.isMinParticipationReached(id)).to.be.true;
expect(await plugin.isSupportThresholdReachedEarly(id)).to.be.true;
expect(await plugin.canExecute(id)).to.equal(true);
expect(await plugin.hasSucceeded(id)).to.be.true;

// Advance time after the end date.
await time.increaseTo(endDate);
Expand All @@ -2421,6 +2426,7 @@ describe('TokenVoting', function () {
expect(await plugin.isMinParticipationReached(id)).to.be.true;
expect(await plugin.isSupportThresholdReached(id)).to.be.true;
expect(await plugin.canExecute(id)).to.equal(true);
expect(await plugin.hasSucceeded(id)).to.be.true;
});

it('can execute normally if participation is large enough', async () => {
Expand Down Expand Up @@ -2464,11 +2470,15 @@ describe('TokenVoting', function () {
abstain: [ivan], // 10 votes
});

expect(await plugin.hasSucceeded(id)).to.be.true;

// Advance after the end date.
await time.increaseTo(endDate);

// Check that the vote is executable because support > 50%, participation > 20%, and the voting period is over.
expect(await plugin.canExecute(id)).to.equal(true);

expect(await plugin.hasSucceeded(id)).to.be.true;
});

it('cannot execute normally if participation is too low', async () => {
Expand Down Expand Up @@ -2517,6 +2527,7 @@ describe('TokenVoting', function () {

// Check that the vote is not executable because the participation with 19% is still too low, despite a support of 67% and the voting period being over.
expect(await plugin.canExecute(id)).to.equal(false);
expect(await plugin.hasSucceeded(id)).to.be.false;
});

it('executes target with delegate call', async () => {
Expand Down Expand Up @@ -2596,6 +2607,9 @@ describe('TokenVoting', function () {
await expect(plugin.execute(id))
.to.emit(pluginMerged, 'ExecutedCustom')
.to.emit(pluginMerged, 'ProposalExecuted');

// It still should return `true` even if proposal has executed.
expect(await plugin.hasSucceeded(id)).to.be.true;
});

it('executes the vote immediately when the vote is decided early and the tryEarlyExecution options is selected', async () => {
Expand Down Expand Up @@ -2974,6 +2988,7 @@ describe('TokenVoting', function () {
expect(await plugin.isSupportThresholdReachedEarly(id)).to.be.true;
expect(await plugin.isMinParticipationReached(id)).to.be.true;
expect(await plugin.canExecute(id)).to.equal(false);
expect(await plugin.hasSucceeded(id)).to.be.false;
});

it('can execute normally if participation and support are met', async () => {
Expand Down Expand Up @@ -3019,6 +3034,7 @@ describe('TokenVoting', function () {
expect(await plugin.isSupportThresholdReached(id)).to.be.true;
expect(await plugin.isMinParticipationReached(id)).to.be.true;
expect(await plugin.canExecute(id)).to.equal(false);
expect(await plugin.hasSucceeded(id)).to.be.false;

// Advance time to the end date.
await time.increaseTo(endDate);
Expand All @@ -3027,6 +3043,7 @@ describe('TokenVoting', function () {
expect(await plugin.isSupportThresholdReached(id)).to.be.true;
expect(await plugin.isMinParticipationReached(id)).to.be.true;
expect(await plugin.canExecute(id)).to.equal(true);
expect(await plugin.hasSucceeded(id)).to.be.true;
});

it('does not execute early when voting with the `tryEarlyExecution` option', async () => {
Expand Down

0 comments on commit e906746

Please sign in to comment.