snt-voting/contracts/democracy/ProposalManager.sol

163 lines
5.4 KiB
Solidity
Raw Normal View History

pragma solidity ^0.4.17;
2017-11-28 01:33:25 -02:00
import "./TrustNetwork.sol";
import "./DelegationProxy.sol";
import "./ProposalExecutor.sol";
2017-11-28 01:33:25 -02:00
import "../token/MiniMeToken.sol";
import "../common/Controlled.sol";
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
*/
contract ProposalManager is Controlled {
TrustNetwork public trustNet;
MiniMeToken public SNT;
2018-03-16 22:55:57 -03:00
uint256 public tabulationBlockDelay = 10000;
2017-11-28 01:33:25 -02:00
Proposal[] proposals;
2017-11-28 01:33:25 -02:00
struct Proposal {
2018-03-16 22:55:57 -03:00
bytes32 topic;
bytes32 txHash;
2017-11-28 01:33:25 -02:00
uint stake;
2018-03-16 22:55:57 -03:00
address staker;
2017-11-28 01:33:25 -02:00
uint blockStart;
uint voteBlockEnd;
uint vetoBlockEnd;
mapping(address => Vote) voteMap;
2017-11-28 01:33:25 -02:00
2018-03-16 22:55:57 -03:00
mapping(address => Tabulations) tabulated;
mapping(uint8 => uint256) results;
2017-11-28 01:33:25 -02:00
bool approved;
bool executed;
}
2018-03-16 22:55:57 -03:00
struct Tabulations {
bool vote;
bool veto;
}
2017-11-28 01:33:25 -02:00
enum Vote {
Null,
2017-11-28 01:33:25 -02:00
Reject,
Approve,
Veto
}
2018-03-16 22:57:30 -03:00
function ProposalManager(MiniMeToken _SNT, TrustNetwork _trustNet) public {
2017-11-28 01:33:25 -02:00
trustNet = _trustNet;
SNT = _SNT;
}
2018-03-16 22:55:57 -03:00
function addProposal(bytes32 _topic, bytes32 _txHash, uint _stake) public returns (uint) {
require(_stake > 1000);
require(SNT.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
}
2018-03-16 22:55:57 -03:00
function execute(uint id, address dest, uint value, bytes data) public {
Proposal memory p = proposals[id];
2018-03-11 18:17:50 +07:00
require(p.approved == true);
2018-03-16 22:55:57 -03:00
require(keccak256(dest, value, data) == p.txHash);
2017-11-28 01:33:25 -02:00
proposals[id].executed = true;
2018-03-16 22:55:57 -03:00
ProposalExecutor(controller).executeProposal(dest, value, data);
2017-11-28 01:33:25 -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);
}
proposal.voteMap[msg.sender] = _vote;
2017-11-28 01:33:25 -02:00
}
2018-03-16 22:55:57 -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) {
DelegationProxy voteDelegation;
DelegationProxy vetoDelegation;
(voteDelegation, vetoDelegation) = trustNet.getTopic(proposal.topic);
address delegate = voteDelegation.delegationOfAt(_delegator, proposal.vetoBlockEnd);
_vote = proposal.voteMap[delegate];
2017-11-28 01:33:25 -02:00
}
if (_vote == Vote.Reject || _vote == Vote.Approve) {
proposal.results[uint8(_vote)] += MiniMeToken(SNT).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) {
DelegationProxy voteDelegation;
DelegationProxy vetoDelegation;
(voteDelegation, vetoDelegation) = trustNet.getTopic(proposal.topic);
address delegate = vetoDelegation.delegationOfAt(_delegator, proposal.vetoBlockEnd);
_vote = proposal.voteMap[delegate];
}
if (_vote == Vote.Veto) {
proposal.results[uint8(Vote.Veto)] += MiniMeToken(SNT).balanceOfAt(_delegator, proposal.vetoBlockEnd);
}
}
function approve(uint _proposal) public {
Proposal storage proposal = proposals[_proposal];
require(proposal.vetoBlockEnd + tabulationBlockDelay > block.number);
require(!proposal.approved);
uint256 totalTokens = MiniMeToken(SNT).totalSupplyAt(proposal.vetoBlockEnd);
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;
require(SNT.transferFrom(address(this), proposal.staker, proposal.stake));
}
2017-11-28 01:33:25 -02:00
}