1
1
pragma solidity 0.5.17 ;
2
- pragma experimental ABIEncoderV2;
3
2
4
3
import "@daostack/infra/contracts/votingMachines/IntVoteInterface.sol " ;
5
4
import "@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol " ;
6
5
import "../votingMachines/VotingMachineCallbacks.sol " ;
6
+ import "../libs/BytesLib.sol " ;
7
+
7
8
8
9
/**
9
10
* @title GenericSchemeMultiCall.
10
11
* @dev A scheme for proposing and executing calls to multiple arbitrary function
11
12
* on one or multiple contracts on behalf of the organization avatar.
12
13
*/
13
14
contract GenericSchemeMultiCall is VotingMachineCallbacks , ProposalExecuteInterface {
15
+ using BytesLib for bytes ;
16
+ using SafeMath for uint256 ;
14
17
15
18
// Details of a voting proposal:
16
19
struct MultiCallProposal {
17
20
address [] contractsToCall;
18
- bytes [] callsData;
21
+ bytes callsData;
22
+ uint256 [] callsDataLens;
19
23
uint256 [] values;
20
24
bool exist;
21
25
bool passed;
@@ -32,7 +36,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
32
36
event NewMultiCallProposal (
33
37
address indexed _avatar ,
34
38
bytes32 indexed _proposalId ,
35
- bytes [] _callsData ,
39
+ bytes _callsData ,
36
40
uint256 [] _values ,
37
41
string _descriptionHash ,
38
42
address [] _contractsToCall
@@ -47,6 +51,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
47
51
address indexed _avatar ,
48
52
bytes32 indexed _proposalId ,
49
53
address _contractToCall ,
54
+ bytes _callsData ,
50
55
bool _success ,
51
56
bytes _callDataReturnValue
52
57
);
@@ -65,7 +70,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
65
70
* @param _votingMachine the voting machines address to
66
71
* @param _voteParams voting machine parameters.
67
72
* @param _contractWhitelist the contracts the scheme is allowed to interact with
68
- *
73
+ *
69
74
*/
70
75
function initialize (
71
76
Avatar _avatar ,
@@ -85,7 +90,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
85
90
Controller controller = Controller (_avatar.owner ());
86
91
whitelistedContracts.push (address (controller));
87
92
contractWhitelist[address (controller)] = true ;
88
-
93
+
89
94
for (uint i = 0 ; i < _contractWhitelist.length ; i++ ) {
90
95
contractWhitelist[_contractWhitelist[i]] = true ;
91
96
whitelistedContracts.push (_contractWhitelist[i]);
@@ -130,27 +135,30 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
130
135
bytes memory genericCallReturnValue;
131
136
bool success;
132
137
Controller controller = Controller (whitelistedContracts[0 ]);
138
+ uint256 startIndex = 0 ;
133
139
134
140
for (uint i = 0 ; i < proposal.contractsToCall.length ; i++ ) {
141
+ bytes memory callData = proposal.callsData.slice (startIndex, proposal.callsDataLens[i]);
135
142
if (proposal.contractsToCall[i] == address (controller)) {
136
143
(IERC20 extToken ,
137
144
address spender ,
138
145
uint256 valueToSpend
139
146
) =
140
147
abi.decode (
141
- proposal.callsData[i] ,
148
+ callData ,
142
149
(IERC20 , address , uint256 )
143
150
);
144
151
(success) = controller.externalTokenApproval (extToken, spender, valueToSpend, avatar);
145
152
} else {
146
153
(success, genericCallReturnValue) =
147
- controller.genericCall (proposal.contractsToCall[i], proposal.callsData[i] , avatar, proposal.values[i]);
154
+ controller.genericCall (proposal.contractsToCall[i], callData , avatar, proposal.values[i]);
148
155
}
149
-
156
+ startIndex = startIndex. add (proposal.callsDataLens[i]);
150
157
emit ProposalCallExecuted (
151
158
address (avatar),
152
159
_proposalId,
153
160
proposal.contractsToCall[i],
161
+ callData,
154
162
success,
155
163
genericCallReturnValue
156
164
);
@@ -164,47 +172,51 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
164
172
/**
165
173
* @dev propose to call one or multiple contracts on behalf of the _avatar
166
174
* The function trigger NewMultiCallProposal event
167
- * @param _contractsToCall the contracts to be called
175
+ * @param _contractsToCall the contracts to be called
168
176
* @param _callsData - The abi encode data for the calls
177
+ * @param _callsDataLens the length of each callData
169
178
* @param _values value(ETH) to transfer with the calls
170
179
* @param _descriptionHash proposal description hash
171
180
* @return an id which represents the proposal
172
181
*/
173
182
function proposeCalls (
174
183
address [] memory _contractsToCall ,
175
- bytes [] memory _callsData ,
184
+ bytes memory _callsData ,
185
+ uint256 [] memory _callsDataLens ,
176
186
uint256 [] memory _values ,
177
187
string memory _descriptionHash
178
188
)
179
189
public
180
190
returns (bytes32 proposalId )
181
191
{
182
192
require (
183
- (_contractsToCall.length == _callsData .length ) && (_contractsToCall.length == _values.length ),
184
- "Wrong length of _contractsToCall, _callsData or _values arrays "
193
+ (_contractsToCall.length == _callsDataLens .length ) && (_contractsToCall.length == _values.length ),
194
+ "Wrong length of _contractsToCall, _callsDataLens or _values arrays "
185
195
);
186
196
Controller controller = Controller (whitelistedContracts[0 ]);
197
+ uint256 startIndex = 0 ;
187
198
for (uint i = 0 ; i < _contractsToCall.length ; i++ ) {
188
199
require (
189
200
contractWhitelist[_contractsToCall[i]], "contractToCall is not whitelisted "
190
201
);
191
202
if (_contractsToCall[i] == address (controller)) {
192
- (IERC20 extToken ,
193
- address spender ,
194
- uint256 valueToSpend
195
- ) =
203
+
204
+ bytes memory callData = _callsData.slice (startIndex, _callsDataLens[i]);
205
+ (, address spender ,) =
196
206
abi.decode (
197
- _callsData[i] ,
207
+ callData ,
198
208
(IERC20 , address , uint256 )
199
209
);
200
210
require (contractWhitelist[spender], "spender contract not whitelisted " );
201
211
}
212
+ startIndex = startIndex.add (_callsDataLens[i]);
202
213
}
203
214
proposalId = votingMachine.propose (2 , voteParams, msg .sender , address (avatar));
204
215
205
216
proposals[proposalId] = MultiCallProposal ({
206
217
contractsToCall: _contractsToCall,
207
218
callsData: _callsData,
219
+ callsDataLens: _callsDataLens,
208
220
values: _values,
209
221
exist: true ,
210
222
passed: false
@@ -217,4 +229,4 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
217
229
emit NewMultiCallProposal (address (avatar), proposalId, _callsData, _values, _descriptionHash, _contractsToCall);
218
230
219
231
}
220
- }
232
+ }
0 commit comments