/
GenericScheme.sol
151 lines (134 loc) · 5.08 KB
/
GenericScheme.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
pragma solidity 0.5.17;
import "@daostack/infra/contracts/votingMachines/IntVoteInterface.sol";
import "@daostack/infra/contracts/votingMachines/VotingMachineCallbacksInterface.sol";
import "../votingMachines/VotingMachineCallbacks.sol";
/**
* @title GenericScheme.
* @dev A scheme for proposing and executing calls to an arbitrary function
* on a specific contract on behalf of the organization avatar.
*/
contract GenericScheme is VotingMachineCallbacks, ProposalExecuteInterface {
event NewCallProposal(
address indexed _avatar,
bytes32 indexed _proposalId,
bytes _callData,
uint256 _value,
string _descriptionHash
);
event ProposalExecuted(
address indexed _avatar,
bytes32 indexed _proposalId,
bytes _genericCallReturnValue
);
event ProposalExecutedByVotingMachine(
address indexed _avatar,
bytes32 indexed _proposalId,
int256 _param
);
event ProposalDeleted(address indexed _avatar, bytes32 indexed _proposalId);
// Details of a voting proposal:
struct CallProposal {
bytes callData;
uint256 value;
bool exist;
bool passed;
}
mapping(bytes32=>CallProposal) public organizationProposals;
IntVoteInterface public votingMachine;
bytes32 public voteParams;
address public contractToCall;
Avatar public avatar;
/**
* @dev initialize
* @param _avatar the avatar to mint reputation from
* @param _votingMachine the voting machines address to
* @param _voteParams voting machine parameters.
* @param _contractToCall the target contract this scheme will call to
*/
function initialize(
Avatar _avatar,
IntVoteInterface _votingMachine,
bytes32 _voteParams,
address _contractToCall
)
external
{
require(avatar == Avatar(0), "can be called only one time");
require(_avatar != Avatar(0), "avatar cannot be zero");
avatar = _avatar;
votingMachine = _votingMachine;
voteParams = _voteParams;
contractToCall = _contractToCall;
}
/**
* @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 _decision a parameter of the voting result, 1 yes and 2 is no.
* @return bool success
*/
function executeProposal(bytes32 _proposalId, int256 _decision)
external
onlyVotingMachine(_proposalId)
returns(bool) {
CallProposal storage proposal = organizationProposals[_proposalId];
require(proposal.exist, "must be a live proposal");
require(proposal.passed == false, "cannot execute twice");
if (_decision == 1) {
proposal.passed = true;
execute(_proposalId);
} else {
delete organizationProposals[_proposalId];
emit ProposalDeleted(address(avatar), _proposalId);
}
emit ProposalExecutedByVotingMachine(address(avatar), _proposalId, _decision);
return true;
}
/**
* @dev execution of proposals after it has been decided by the voting machine
* @param _proposalId the ID of the voting in the voting machine
*/
function execute(bytes32 _proposalId) public {
CallProposal storage proposal = organizationProposals[_proposalId];
require(proposal.exist, "must be a live proposal");
require(proposal.passed, "proposal must passed by voting machine");
proposal.exist = false;
bytes memory genericCallReturnValue;
bool success;
Controller controller = Controller(avatar.owner());
(success, genericCallReturnValue) =
controller.genericCall(contractToCall, proposal.callData, avatar, proposal.value);
if (success) {
delete organizationProposals[_proposalId];
emit ProposalDeleted(address(avatar), _proposalId);
emit ProposalExecuted(address(avatar), _proposalId, genericCallReturnValue);
} else {
proposal.exist = true;
}
}
/**
* @dev propose to call on behalf of the _avatar
* The function trigger NewCallProposal event
* @param _callData - The abi encode data for the call
* @param _value value(ETH) to transfer with the call
* @param _descriptionHash proposal description hash
* @return an id which represents the proposal
*/
function proposeCall(bytes memory _callData, uint256 _value, string memory _descriptionHash)
public
returns(bytes32)
{
bytes32 proposalId = votingMachine.propose(2, voteParams, msg.sender, address(avatar));
organizationProposals[proposalId] = CallProposal({
callData: _callData,
value: _value,
exist: true,
passed: false
});
proposalsInfo[address(votingMachine)][proposalId] = ProposalInfo({
blockNumber:block.number,
avatar:avatar
});
emit NewCallProposal(address(avatar), proposalId, _callData, _value, _descriptionHash);
return proposalId;
}
}