feat: minimum participation rules (#9)

This commit is contained in:
RichΛrd 2020-03-30 11:49:51 -04:00 committed by GitHub
parent 5ec6c5e671
commit 66989c76f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 5 deletions

View File

@ -30,28 +30,34 @@ contract StakingPoolDAO is StakingPool, GSNRecipient, ERC20Snapshot, Controlled
uint public proposalVoteLength; // Voting available during this period
uint public proposalExpirationLength; // Proposals should be executed up to 1 day after they have ended
uint public minimumParticipation; // Minimum participation percentage with 2 decimals 10000 == 100.00
event NewProposal(uint indexed proposalId);
event Vote(uint indexed proposalId, address indexed voter, VoteStatus indexed choice);
event Execution(uint indexed proposalId);
event ExecutionFailure(uint indexed proposalId);
constructor (address _tokenAddress, uint _stakingPeriodLen, uint _proposalVoteLength, uint _proposalExpirationLength) public
constructor (address _tokenAddress, uint _stakingPeriodLen, uint _proposalVoteLength, uint _proposalExpirationLength, uint _minimumParticipation) public
StakingPool(_tokenAddress, _stakingPeriodLen) {
changeController(address(uint160(address(this))));
proposalVoteLength = _proposalVoteLength;
proposalExpirationLength = _proposalExpirationLength;
minimumParticipation = _minimumParticipation;
}
function setProposalVoteLength(uint _newProposalVoteLength) public onlyController {
proposalVoteLength = _newProposalVoteLength;
}
function setproposalExpirationLength(uint _newProposalExpirationLength) public onlyController {
function setProposalExpirationLength(uint _newProposalExpirationLength) public onlyController {
proposalExpirationLength = _newProposalExpirationLength;
}
function setMinimumParticipation(uint _newMinimumParticipation) public onlyController {
minimumParticipation = _newMinimumParticipation;
}
/// @dev Adds a new proposal
/// @param destination Transaction target address.
/// @param value Transaction ether value.
@ -141,6 +147,10 @@ contract StakingPoolDAO is StakingPool, GSNRecipient, ERC20Snapshot, Controlled
require(block.number <= proposal.voteEndingBlock + proposalExpirationLength, "Proposal is already expired");
require(proposal.votes[true] > proposal.votes[false], "Proposal wasn't approved");
uint totalParticipation = ((proposal.votes[true] + proposal.votes[false]) * 100) / totalSupply();
require(totalParticipation >= minimumParticipation, "Did not meet the minimum required participation");
proposal.executed = true;
bool result = external_call(proposal.destination, proposal.value, proposal.data.length, proposal.data);

View File

@ -62,7 +62,7 @@ contract("StakingPoolDAO", function () {
// Deploy Staking Pool
StakingPool = await StakingPoolDAO.deploy({ arguments: [SNT.options.address, 100, 20, 10] }).send();
StakingPool = await StakingPoolDAO.deploy({ arguments: [SNT.options.address, 100, 20, 10, 0] }).send();
const encodedCall = StakingPool.methods.stake("10000000000").encodeABI();
await web3.eth.sendTransaction({from: iuri, to: StakingPool.options.address, value: "100000000000000000"});
@ -267,6 +267,56 @@ contract("StakingPoolDAO", function () {
const finalBalance = await SNT.methods.balanceOf("0xAA000000000000000000000000000000000000AA").call();
assert.strictEqual(finalBalance, "12345");
});
})
it("set minimum participation", async () => {
// Change minimum participation
const encodedCall = StakingPool.methods.setMinimumParticipation("5000").encodeABI();
const receipt = await StakingPool.methods.addProposal(StakingPool.options.address, 0, encodedCall, "0x").send({from: richard});
proposalId = receipt.events.NewProposal.returnValues.proposalId;
await StakingPool.methods.vote(proposalId, true).send({from: richard});
// Mine 20 blocks
for(let i = 0; i < 20; i++){
await mineAtTimestamp(12345678);
}
await StakingPool.methods.executeTransaction(proposalId).send({from: iuri});
const minimumParticipation = await StakingPool.methods.minimumParticipation().call();
assert.strictEqual(minimumParticipation, "5000");
});
it("requires a minimum participation to execute a proposal", async () => {
const encodedCall = SNT.methods.transfer("0xAA000000000000000000000000000000000000BB", "12345").encodeABI();
const receipt = await StakingPool.methods.addProposal(SNT.options.address, 0, encodedCall, "0x").send({from: richard});
proposalId = receipt.events.NewProposal.returnValues.proposalId;
await StakingPool.methods.vote(proposalId, true).send({from: richard});
// Mine 20 blocks
for(let i = 0; i < 20; i++){
await mineAtTimestamp(12345678);
}
await assert.reverts(StakingPool.methods.executeTransaction(proposalId), {from: iuri}, "Returned error: VM Exception while processing transaction: revert Did not meet the minimum required participation");
});
it("proposal can be executed if it meets the minimum participation", async () => {
const encodedCall = SNT.methods.transfer("0xAA000000000000000000000000000000000000BB", "12345").encodeABI();
const receipt = await StakingPool.methods.addProposal(SNT.options.address, 0, encodedCall, "0x").send({from: richard});
proposalId = receipt.events.NewProposal.returnValues.proposalId;
await StakingPool.methods.vote(proposalId, true).send({from: iuri});
await StakingPool.methods.vote(proposalId, true).send({from: richard});
await StakingPool.methods.vote(proposalId, true).send({from: pascal});
// Mine 20 blocks
for(let i = 0; i < 20; i++){
await mineAtTimestamp(12345678);
}
await StakingPool.methods.executeTransaction(proposalId).send({from: iuri});
});
});
});