diff --git a/contracts/democracy/Democracy.sol b/contracts/democracy/Democracy.sol new file mode 100644 index 0000000..ebf9f42 --- /dev/null +++ b/contracts/democracy/Democracy.sol @@ -0,0 +1,82 @@ +pragma solidity ^0.4.21; +import "./DemocracyInterface.sol"; +import "./ProposalManager.sol"; + +contract Democracy is DemocracyInterface { + + mapping (bytes32 => Allowance) topicAllowance; + + struct Allowance { + mapping(address => bool) anyCall; + mapping(bytes32 => bool) calls; + } + + function Democracy(address _baseToken, address _trustNetwork) public { + token = MiniMeTokenInterface(_baseToken); + trustNet = TrustNetworkInterface(_trustNetwork); + proposalManager = new ProposalManager(token, trustNet); + } + + function allowTopicSpecific(bytes32 _topic, address _destination, bytes4 _allowedCall, bool allowance) + external + { + require(msg.sender == address(this)); + topicAllowance[_topic].calls[keccak256(_destination, _allowedCall)] = allowance; + } + + function allowTopicAnyCall(bytes32 _topic, address _destination, bool allowance) + external + { + require(msg.sender == address(this)); + topicAllowance[_topic].anyCall[_destination] = allowance; + } + + function executeProposal( + uint256 _proposalId, + address _destination, + uint _value, + bytes _data + ) + external + returns (bool success) + { + bytes32 topic; + bytes32 txHash; + bool approved; + bool executed; + (topic, txHash, approved, executed) = proposalManager.getProposal(_proposalId); + require(approved); + require(!executed); + require( + txHash == keccak256( + _destination, + _value, + _data + ) + ); + if(topic != 0x0) { //if not root topic + Allowance storage allowed = topicAllowance[topic]; + if(!allowed.anyCall[_destination]){ //if topic not allowed any call to destination + bytes memory data = _data; + bytes4 calling; + assembly { + calling := mload(add(data, 4)) + } + delete data; + require(allowed.calls[keccak256(_destination, calling)]); //require call allowance + } + } + + // save that this was executed + require( + proposalManager.setExecuted( + _proposalId, + txHash + ) + ); + + //execute the call + return _destination.call.value(_value)(_data); + } + +} \ No newline at end of file diff --git a/contracts/democracy/DemocracyInterface.sol b/contracts/democracy/DemocracyInterface.sol new file mode 100644 index 0000000..070f3d6 --- /dev/null +++ b/contracts/democracy/DemocracyInterface.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.4.17; + +import "./DemocracyStorage.sol"; + +/** + * @title DemocracyInterface + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + */ +contract DemocracyInterface is DemocracyStorage { + + function executeProposal( + uint256 _proposalId, + address _destination, + uint _value, + bytes _data + ) + external + returns(bool success); + + +} \ No newline at end of file diff --git a/contracts/democracy/DemocracyStorage.sol b/contracts/democracy/DemocracyStorage.sol new file mode 100644 index 0000000..1d10f80 --- /dev/null +++ b/contracts/democracy/DemocracyStorage.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.4.17; + +import "../deploy/InstanceStorage.sol"; +import "../token/MiniMeTokenInterface.sol"; +import "./TrustNetworkInterface.sol"; +import "./ProposalManagerInterface.sol"; + +/** + * @title DemocracyStorage + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev Defines kernel vars that Kernel contract share with Instance. + * Important to avoid overwriting wrong storage pointers is that + * InstanceStorage should be always the first contract at heritance. + */ +contract DemocracyStorage is InstanceStorage { + // protected zone start (InstanceStorage vars) + MiniMeTokenInterface public token; + TrustNetworkInterface public trustNet; + ProposalManagerInterface public proposalManager; + // protected zone end +} \ No newline at end of file diff --git a/contracts/democracy/ProposalManager.sol b/contracts/democracy/ProposalManager.sol index f692a09..5d64584 100644 --- a/contracts/democracy/ProposalManager.sol +++ b/contracts/democracy/ProposalManager.sol @@ -36,9 +36,9 @@ contract ProposalManager is ProposalManagerInterface, Controlled { return pos; } - function getProposal(uint id) public constant returns (bytes32 topic, bytes32 txHash, uint stake, address staker, bool approved, bool executed) { + function getProposal(uint id) public constant returns (bytes32 topic, bytes32 txHash, bool approved, bool executed) { Proposal memory p = proposals[id]; - return (p.topic, p.txHash, p.stake, p.staker, p.approved, p.executed); + return (p.topic, p.txHash, p.approved, p.executed); } function getProposalTxHash(uint id) public constant returns(bytes32) { @@ -106,10 +106,11 @@ contract ProposalManager is ProposalManagerInterface, Controlled { require(token.transferFrom(address(this), proposal.staker, proposal.stake)); } - function setExecuted(uint id) public onlyController { - Proposal memory p = proposals[id]; + function setExecuted(uint _id, bytes32 _txHash) public onlyController returns(bool){ + Proposal memory p = proposals[_id]; + require(p.txHash == _txHash); require(p.approved); require(!p.executed); - proposals[id].executed = true; + proposals[_id].executed = true; } } \ No newline at end of file diff --git a/contracts/democracy/ProposalManagerInterface.sol b/contracts/democracy/ProposalManagerInterface.sol index 7e849f5..f328ace 100644 --- a/contracts/democracy/ProposalManagerInterface.sol +++ b/contracts/democracy/ProposalManagerInterface.sol @@ -49,11 +49,11 @@ contract ProposalManagerInterface { } function addProposal(bytes32 _topic, bytes32 _txHash, uint _stake) public returns (uint); - function getProposal(uint id) public constant returns (bytes32 topic, bytes32 txHash, uint stake, address staker, bool approved, bool executed); - function getProposalTxHash(uint id) public constant returns(bytes32); + function getProposal(uint _id) public constant returns (bytes32 topic, bytes32 txHash, bool approved, bool executed); + function getProposalTxHash(uint _id) public constant returns(bytes32); function vote(uint _proposal, Vote _vote) public; function tabulateVote(uint _proposal, address _delegator) public; function tabulateVeto(uint _proposal, address _delegator) public; function approve(uint _proposal) public; - function setExecuted(uint id) public; + function setExecuted(uint _id, bytes32 _txHash) public returns(bool); } \ No newline at end of file