11pragma solidity 0.5.17 ;
2- pragma experimental ABIEncoderV2;
32
43import "@daostack/infra/contracts/votingMachines/IntVoteInterface.sol " ;
54import "@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol " ;
65import "../votingMachines/VotingMachineCallbacks.sol " ;
6+ import "../libs/BytesLib.sol " ;
7+
78
89/**
910 * @title GenericSchemeMultiCall.
1011 * @dev A scheme for proposing and executing calls to multiple arbitrary function
1112 * on one or multiple contracts on behalf of the organization avatar.
1213 */
1314contract GenericSchemeMultiCall is VotingMachineCallbacks , ProposalExecuteInterface {
15+ using BytesLib for bytes ;
16+ using SafeMath for uint256 ;
1417
1518 // Details of a voting proposal:
1619 struct MultiCallProposal {
1720 address [] contractsToCall;
18- bytes [] callsData;
21+ bytes callsData;
22+ uint256 [] callsDataLens;
1923 uint256 [] values;
2024 bool exist;
2125 bool passed;
@@ -32,7 +36,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
3236 event NewMultiCallProposal (
3337 address indexed _avatar ,
3438 bytes32 indexed _proposalId ,
35- bytes [] _callsData ,
39+ bytes _callsData ,
3640 uint256 [] _values ,
3741 string _descriptionHash ,
3842 address [] _contractsToCall
@@ -47,6 +51,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
4751 address indexed _avatar ,
4852 bytes32 indexed _proposalId ,
4953 address _contractToCall ,
54+ bytes _callsData ,
5055 bool _success ,
5156 bytes _callDataReturnValue
5257 );
@@ -65,7 +70,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
6570 * @param _votingMachine the voting machines address to
6671 * @param _voteParams voting machine parameters.
6772 * @param _contractWhitelist the contracts the scheme is allowed to interact with
68- *
73+ *
6974 */
7075 function initialize (
7176 Avatar _avatar ,
@@ -85,7 +90,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
8590 Controller controller = Controller (_avatar.owner ());
8691 whitelistedContracts.push (address (controller));
8792 contractWhitelist[address (controller)] = true ;
88-
93+
8994 for (uint i = 0 ; i < _contractWhitelist.length ; i++ ) {
9095 contractWhitelist[_contractWhitelist[i]] = true ;
9196 whitelistedContracts.push (_contractWhitelist[i]);
@@ -130,27 +135,30 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
130135 bytes memory genericCallReturnValue;
131136 bool success;
132137 Controller controller = Controller (whitelistedContracts[0 ]);
138+ uint256 startIndex = 0 ;
133139
134140 for (uint i = 0 ; i < proposal.contractsToCall.length ; i++ ) {
141+ bytes memory callData = proposal.callsData.slice (startIndex, proposal.callsDataLens[i]);
135142 if (proposal.contractsToCall[i] == address (controller)) {
136143 (IERC20 extToken ,
137144 address spender ,
138145 uint256 valueToSpend
139146 ) =
140147 abi.decode (
141- proposal.callsData[i] ,
148+ callData ,
142149 (IERC20 , address , uint256 )
143150 );
144151 (success) = controller.externalTokenApproval (extToken, spender, valueToSpend, avatar);
145152 } else {
146153 (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]);
148155 }
149-
156+ startIndex = startIndex. add (proposal.callsDataLens[i]);
150157 emit ProposalCallExecuted (
151158 address (avatar),
152159 _proposalId,
153160 proposal.contractsToCall[i],
161+ callData,
154162 success,
155163 genericCallReturnValue
156164 );
@@ -164,47 +172,51 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
164172 /**
165173 * @dev propose to call one or multiple contracts on behalf of the _avatar
166174 * The function trigger NewMultiCallProposal event
167- * @param _contractsToCall the contracts to be called
175+ * @param _contractsToCall the contracts to be called
168176 * @param _callsData - The abi encode data for the calls
177+ * @param _callsDataLens the length of each callData
169178 * @param _values value(ETH) to transfer with the calls
170179 * @param _descriptionHash proposal description hash
171180 * @return an id which represents the proposal
172181 */
173182 function proposeCalls (
174183 address [] memory _contractsToCall ,
175- bytes [] memory _callsData ,
184+ bytes memory _callsData ,
185+ uint256 [] memory _callsDataLens ,
176186 uint256 [] memory _values ,
177187 string memory _descriptionHash
178188 )
179189 public
180190 returns (bytes32 proposalId )
181191 {
182192 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 "
185195 );
186196 Controller controller = Controller (whitelistedContracts[0 ]);
197+ uint256 startIndex = 0 ;
187198 for (uint i = 0 ; i < _contractsToCall.length ; i++ ) {
188199 require (
189200 contractWhitelist[_contractsToCall[i]], "contractToCall is not whitelisted "
190201 );
191202 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 ,) =
196206 abi.decode (
197- _callsData[i] ,
207+ callData ,
198208 (IERC20 , address , uint256 )
199209 );
200210 require (contractWhitelist[spender], "spender contract not whitelisted " );
201211 }
212+ startIndex = startIndex.add (_callsDataLens[i]);
202213 }
203214 proposalId = votingMachine.propose (2 , voteParams, msg .sender , address (avatar));
204215
205216 proposals[proposalId] = MultiCallProposal ({
206217 contractsToCall: _contractsToCall,
207218 callsData: _callsData,
219+ callsDataLens: _callsDataLens,
208220 values: _values,
209221 exist: true ,
210222 passed: false
@@ -217,4 +229,4 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
217229 emit NewMultiCallProposal (address (avatar), proposalId, _callsData, _values, _descriptionHash, _contractsToCall);
218230
219231 }
220- }
232+ }
0 commit comments