Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make GenericScheme more generic and flexible #623

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 13 additions & 22 deletions contracts/universalSchemes/GenericScheme.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu

// Details of a voting proposal:
struct CallProposal {
address contractToCall;
bytes callData;
uint256 value;
bool exist;
Expand All @@ -48,7 +49,6 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
struct Parameters {
IntVoteInterface intVote;
bytes32 voteParams;
address contractToCall;
}

// A mapping from hashes to parameters (use to store a particular configuration on the controller)
Expand Down Expand Up @@ -86,7 +86,6 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
* @param _proposalId the ID of the voting in the voting machine
*/
function execute(Avatar _avatar, bytes32 _proposalId) public {
Parameters memory params = parameters[getParametersFromController(_avatar)];
CallProposal storage proposal = organizationsProposals[address(_avatar)][_proposalId];
require(proposal.exist, "must be a live proposal");
require(proposal.passed, "proposal must passed by voting machine");
Expand All @@ -95,7 +94,7 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
bool success;
ControllerInterface controller = ControllerInterface(_avatar.owner());
(success, genericCallReturnValue) =
controller.genericCall(params.contractToCall, proposal.callData, _avatar, proposal.value);
controller.genericCall(proposal.contractToCall, proposal.callData, _avatar, proposal.value);
if (success) {
delete organizationsProposals[address(_avatar)][_proposalId];
emit ProposalDeleted(address(_avatar), _proposalId);
Expand All @@ -113,14 +112,12 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
*/
function setParameters(
bytes32 _voteParams,
IntVoteInterface _intVote,
address _contractToCall
IntVoteInterface _intVote
) public returns(bytes32)
{
bytes32 paramsHash = getParametersHash(_voteParams, _intVote, _contractToCall);
bytes32 paramsHash = getParametersHash(_voteParams, _intVote);
parameters[paramsHash].voteParams = _voteParams;
parameters[paramsHash].intVote = _intVote;
parameters[paramsHash].contractToCall = _contractToCall;
return paramsHash;
}

Expand All @@ -132,11 +129,10 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
*/
function getParametersHash(
bytes32 _voteParams,
IntVoteInterface _intVote,
address _contractToCall
IntVoteInterface _intVote
) public pure returns(bytes32)
{
return keccak256(abi.encodePacked(_voteParams, _intVote, _contractToCall));
return keccak256(abi.encodePacked(_voteParams, _intVote));
}

/**
Expand All @@ -148,7 +144,12 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
* @param _descriptionHash proposal description hash
* @return an id which represents the proposal
*/
function proposeCall(Avatar _avatar, bytes memory _callData, uint256 _value, string memory _descriptionHash)
function proposeCall(
Avatar _avatar,
address _contractToCall,
bytes memory _callData,
uint256 _value,
string memory _descriptionHash)
public
returns(bytes32)
{
Expand All @@ -158,6 +159,7 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
bytes32 proposalId = intVote.propose(2, params.voteParams, msg.sender, address(_avatar));

organizationsProposals[address(_avatar)][proposalId] = CallProposal({
contractToCall: _contractToCall,
callData: _callData,
value: _value,
exist: true,
Expand All @@ -170,15 +172,4 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
emit NewCallProposal(address(_avatar), proposalId, _callData, _value, _descriptionHash);
return proposalId;
}

/**
* @dev getContractToCall return the contract this scheme is calling
* @param _avatar address of the organization's avatar
* @return address the address of the contract this scheme is calling to
* on behalf of the avatar
*/
function getContractToCall(Avatar _avatar) public view returns(address) {
return parameters[getParametersFromController(_avatar)].contractToCall;
}

}
179 changes: 179 additions & 0 deletions contracts/universalSchemes/GenericSchemeTemplates.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
pragma solidity ^0.5.4;

import "@daostack/infra/contracts/votingMachines/IntVoteInterface.sol";
import "@daostack/infra/contracts/votingMachines/VotingMachineCallbacksInterface.sol";
import "./UniversalScheme.sol";
import "../votingMachines/VotingMachineCallbacks.sol";
import "./GenericScheme.sol";

/**
* @title A scheme for registering GenericScheme proposal templates
*/
contract GenericSchemeTemplates is UniversalScheme, VotingMachineCallbacks, ProposalExecuteInterface {

event ProposalExecuted(address indexed _avatar, bytes32 indexed _proposalId, int256 _param);

// solhint-disable-next-line max-line-length
event NewTemplateProposal(bytes32 indexed proposalId, address indexed _avatar, address indexed _genericScheme, string _name, address _contract, string _abi);

// A mapping from hashes to parameters (use to store a particular configuration on the controller)
struct Parameters {
bytes32 voteApproveParams;
IntVoteInterface intVote;
}

// A mapping from hashes to parameters (use to store a particular configuration on the controller)
mapping(bytes32=>Parameters) public parameters;

struct Proposal {
Avatar avatar;
GenericScheme genericScheme;
string name;
address theContract;
string abi;
uint256 executionTime;
}

/**
* @dev execution of proposals, can only be called by the voting machine in which the vote is held.
* @param _proposalId the ID of the voting in the voting machine
* @param _param a parameter of the voting result, 1 yes and 2 is no.
*/
function executeProposal(bytes32 _proposalId, int256 _param) external onlyVotingMachine(_proposalId) returns(bool) {
ProposalInfo memory proposalInfo = proposalsInfo[msg.sender][_proposalId];
Proposal memory proposal = organizationsProposals[address(proposalInfo.avatar)][_proposalId];
require(proposalInfo.avatar == proposal.avatar);
require(proposal.executionTime == 0);
require(bytes(proposal.name).length != 0);
require(proposal.theContract != address(0));
require(proposal.avatar != Avatar(0));
require(proposal.genericScheme != GenericScheme(0));
require(bytes(proposal.abi).length != 0);
// Check if vote was successful:
if (_param == 1) {
// solhint-disable-next-line not-rely-on-time
organizationsProposals[address(proposal.avatar)][_proposalId].executionTime = now;
}
emit ProposalExecuted(address(proposal.avatar), _proposalId, _param);
return true;
}

/**
* @dev hash the parameters, save them if necessary, and return the hash value
*/
function setParameters(
bytes32 _voteApproveParams,
IntVoteInterface _intVote
) public returns(bytes32)
{
bytes32 paramsHash = getParametersHash(
_voteApproveParams,
_intVote
);
parameters[paramsHash].voteApproveParams = _voteApproveParams;
parameters[paramsHash].intVote = _intVote;
return paramsHash;
}

/**
* @dev return a hash of the given parameters
* @param _voteApproveParams parameters for the voting machine used to approve a contribution
* @param _intVote the voting machine used to approve a contribution
* @return a hash of the parameters
*/
function getParametersHash(
bytes32 _voteApproveParams,
IntVoteInterface _intVote
) public pure returns(bytes32)
{
return (keccak256(abi.encodePacked(_voteApproveParams, _intVote)));
}

// A mapping from the organization (Avatar) address to the saved data of the organization:
mapping(address=>mapping(bytes32=>Proposal)) public organizationsProposals;

/**
* @dev Submit a proposal
*/
function propose(
/**
* the avatar to which the GenericScheme is registered
*/
Avatar _avatar,
/**
* the registered GenericScheme
*/
GenericScheme _genericScheme,
/**
* The abi describing a function that GenericScheme would invoke when executed.
* The _abi may be missing values for one or more function parameters, and dApps may
* prompt users to supply the missing values before
* submitting proposals to GenesisScheme to invoke the function.
*/
string memory _abi,
/**
* A name that may be used, for example, to identify a GUI form by which an
* incomplete _abi may be filled-in by the user prior to submitting a proposal
* to invoke the function described by _abi.
*/
string memory _name,
/**
* address of the contract that implements the function described by _abi.
*/
address _contract
)
public
returns(bytes32)
{
validateProposalParams(_avatar, _genericScheme, _abi, _name, _contract);

Parameters memory controllerParams = parameters[getParametersFromController(_avatar)];

bytes32 proposalId = controllerParams.intVote.propose(
2,
controllerParams.voteApproveParams,
msg.sender,
address(_avatar)
);

Proposal memory proposal = Proposal({
avatar: _avatar,
genericScheme: _genericScheme,
name: _name,
theContract: _contract,
abi: _abi,
executionTime: 0
});

organizationsProposals[address(_avatar)][proposalId] = proposal;

emit NewTemplateProposal(
proposalId,
address(_avatar),
address(_genericScheme),
_name,
_contract,
_abi
);

proposalsInfo[address(controllerParams.intVote)][proposalId] = ProposalInfo({
blockNumber:block.number,
avatar:_avatar
});
return proposalId;
}

function validateProposalParams(
Avatar _avatar,
GenericScheme _genericScheme,
string memory _abi,
string memory _name,
address _contract
) private pure {
require(_avatar != Avatar(0), "_avatar is not set");
require(_genericScheme != GenericScheme(0), "_genericScheme is not set");
require(_contract != address(0), "_contract is not set");
require(bytes(_name).length != 0, "_name is not set");
require(bytes(_abi).length != 0, "_abi is not set");
}
}