feat: minimum participation rules (#9)
This commit is contained in:
parent
5ec6c5e671
commit
66989c76f3
|
@ -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);
|
||||
|
|
|
@ -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});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue