2018-03-27 23:16:51 -03:00
|
|
|
pragma solidity ^0.4.21;
|
2017-11-28 01:33:25 -02:00
|
|
|
|
2018-03-27 23:16:51 -03:00
|
|
|
import "./ProposalManagerInterface.sol";
|
2018-03-17 13:50:33 -03:00
|
|
|
import "./TrustNetworkInterface.sol";
|
|
|
|
import "./DelegationProxyInterface.sol";
|
|
|
|
import "../token/MiniMeTokenInterface.sol";
|
2017-11-28 01:33:25 -02:00
|
|
|
import "../common/Controlled.sol";
|
2017-12-19 23:06:19 -02:00
|
|
|
|
2017-11-28 01:33:25 -02:00
|
|
|
/**
|
|
|
|
* @title ProposalManager
|
|
|
|
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
|
|
|
* Store the proposals, votes and results for other smartcontracts
|
|
|
|
*/
|
2018-03-27 23:16:51 -03:00
|
|
|
contract ProposalManager is ProposalManagerInterface, Controlled {
|
|
|
|
|
2018-03-17 13:50:33 -03:00
|
|
|
function ProposalManager(MiniMeTokenInterface _SNT, TrustNetworkInterface _trustNet) public {
|
2017-11-28 01:33:25 -02:00
|
|
|
trustNet = _trustNet;
|
2018-03-17 13:50:33 -03:00
|
|
|
token = _SNT;
|
2017-11-28 01:33:25 -02:00
|
|
|
}
|
|
|
|
|
2018-03-16 22:55:57 -03:00
|
|
|
function addProposal(bytes32 _topic, bytes32 _txHash, uint _stake) public returns (uint) {
|
|
|
|
require(_stake > 1000);
|
2018-03-17 13:50:33 -03:00
|
|
|
require(token.transferFrom(msg.sender, address(this), _stake));
|
2017-11-28 01:33:25 -02:00
|
|
|
uint pos = proposals.length++;
|
|
|
|
Proposal storage p = proposals[pos];
|
|
|
|
|
2018-03-16 22:55:57 -03:00
|
|
|
p.topic = _topic;
|
|
|
|
p.txHash = _txHash;
|
|
|
|
p.stake = _stake;
|
|
|
|
p.staker = msg.sender;
|
2017-11-28 01:33:25 -02:00
|
|
|
|
|
|
|
p.blockStart = block.number + 1000; //will be replaced by configurations
|
|
|
|
p.voteBlockEnd = p.blockStart + 10000; //dummy value
|
|
|
|
p.vetoBlockEnd = p.voteBlockEnd + 5000; //dummy value
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
2018-03-16 22:55:57 -03:00
|
|
|
function getProposal(uint id) public constant returns (bytes32 topic, bytes32 txHash, uint stake, address staker, bool approved, bool executed) {
|
2017-11-28 01:33:25 -02:00
|
|
|
Proposal memory p = proposals[id];
|
2018-03-16 22:55:57 -03:00
|
|
|
return (p.topic, p.txHash, p.stake, p.staker, p.approved, p.executed);
|
2017-11-28 01:33:25 -02:00
|
|
|
}
|
|
|
|
|
2018-03-16 22:55:57 -03:00
|
|
|
function getProposalTxHash(uint id) public constant returns(bytes32) {
|
|
|
|
return proposals[id].txHash;
|
2017-11-28 01:33:25 -02:00
|
|
|
}
|
|
|
|
|
2017-12-19 23:06:19 -02:00
|
|
|
function vote(uint _proposal, Vote _vote) public {
|
2017-11-28 01:33:25 -02:00
|
|
|
Proposal storage proposal = proposals[_proposal];
|
|
|
|
require(block.number >= proposal.blockStart);
|
|
|
|
if (_vote == Vote.Veto) {
|
|
|
|
require(block.number <= proposal.vetoBlockEnd);
|
|
|
|
} else {
|
|
|
|
require(block.number <= proposal.voteBlockEnd);
|
|
|
|
}
|
2018-03-11 17:11:46 +07:00
|
|
|
|
|
|
|
proposal.voteMap[msg.sender] = _vote;
|
|
|
|
|
2017-11-28 01:33:25 -02:00
|
|
|
}
|
|
|
|
|
2018-03-27 23:16:51 -03:00
|
|
|
function tabulateVote(uint _proposal, address _delegator) public {
|
2017-11-28 01:33:25 -02:00
|
|
|
Proposal storage proposal = proposals[_proposal];
|
2018-03-16 22:55:57 -03:00
|
|
|
require(block.number > proposal.voteBlockEnd);
|
|
|
|
require(!proposal.tabulated[_delegator].vote);
|
|
|
|
proposal.tabulated[_delegator].vote = true;
|
|
|
|
Vote _vote = proposal.voteMap[_delegator];
|
|
|
|
if(_vote == Vote.Null) {
|
2018-03-27 23:16:51 -03:00
|
|
|
address delegate = trustNet.getVoteDelegation(proposal.topic).delegationOfAt(_delegator, proposal.vetoBlockEnd);
|
2018-03-16 22:55:57 -03:00
|
|
|
_vote = proposal.voteMap[delegate];
|
2017-11-28 01:33:25 -02:00
|
|
|
}
|
2018-03-11 17:11:46 +07:00
|
|
|
|
|
|
|
if (_vote == Vote.Reject || _vote == Vote.Approve) {
|
2018-03-17 13:50:33 -03:00
|
|
|
proposal.results[uint8(_vote)] += token.balanceOfAt(_delegator, proposal.voteBlockEnd);
|
2017-11-28 01:33:25 -02:00
|
|
|
}
|
2018-03-16 22:55:57 -03:00
|
|
|
}
|
2017-11-28 01:33:25 -02:00
|
|
|
|
2018-03-16 22:55:57 -03:00
|
|
|
function tabulateVeto(uint _proposal, address _delegator) public {
|
|
|
|
Proposal storage proposal = proposals[_proposal];
|
|
|
|
require(block.number > proposal.vetoBlockEnd);
|
|
|
|
require(!proposal.tabulated[_delegator].veto);
|
|
|
|
proposal.tabulated[_delegator].veto = true;
|
|
|
|
Vote _vote = proposal.voteMap[_delegator];
|
|
|
|
if (_vote == Vote.Null) {
|
2018-03-27 23:16:51 -03:00
|
|
|
address delegate = trustNet.getVetoDelegation(proposal.topic).delegationOfAt(_delegator, proposal.vetoBlockEnd);
|
2018-03-16 22:55:57 -03:00
|
|
|
_vote = proposal.voteMap[delegate];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_vote == Vote.Veto) {
|
2018-03-17 13:50:33 -03:00
|
|
|
proposal.results[uint8(Vote.Veto)] += token.balanceOfAt(_delegator, proposal.vetoBlockEnd);
|
2018-03-16 22:55:57 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function approve(uint _proposal) public {
|
|
|
|
Proposal storage proposal = proposals[_proposal];
|
|
|
|
require(proposal.vetoBlockEnd + tabulationBlockDelay > block.number);
|
|
|
|
require(!proposal.approved);
|
2018-03-17 13:50:33 -03:00
|
|
|
uint256 totalTokens = token.totalSupplyAt(proposal.vetoBlockEnd);
|
2018-03-16 22:55:57 -03:00
|
|
|
uint256 approvals = proposal.results[uint8(Vote.Approve)];
|
|
|
|
uint256 veto = proposal.results[uint8(Vote.Veto)];
|
|
|
|
uint256 approvalQuorum = (totalTokens / 2);
|
|
|
|
uint256 vetoQuorum = (totalTokens / 3);
|
|
|
|
require(veto < vetoQuorum);
|
|
|
|
require(approvals >= approvalQuorum);
|
|
|
|
proposal.approved = true;
|
2018-03-17 13:50:33 -03:00
|
|
|
require(token.transferFrom(address(this), proposal.staker, proposal.stake));
|
2018-03-16 22:55:57 -03:00
|
|
|
}
|
2018-03-27 23:16:51 -03:00
|
|
|
|
|
|
|
function setExecuted(uint id) public onlyController {
|
|
|
|
Proposal memory p = proposals[id];
|
|
|
|
require(p.approved);
|
|
|
|
require(!p.executed);
|
|
|
|
proposals[id].executed = true;
|
|
|
|
}
|
2017-11-28 01:33:25 -02:00
|
|
|
}
|