Skip to content

genericschemeMultipleCalls - fix warnings #787

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

Merged
merged 2 commits into from
Sep 10, 2020
Merged
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
79 changes: 79 additions & 0 deletions contracts/libs/BytesLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* @title Solidity Bytes Arrays Utils
* @author Gonçalo Sá <[email protected]>
*
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
*/

pragma solidity 0.5.17;


library BytesLib {

function slice(
bytes memory _bytes,
uint _start,
uint _length
)
internal
pure
returns (bytes memory)
// solhint-disable-next-line function-max-lines
{
require(_bytes.length >= (_start + _length));

bytes memory tempBytes;
// solhint-disable-next-line no-inline-assembly
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)

// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)

// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)

for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}

mstore(tempBytes, _length)

//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)

mstore(0x40, add(tempBytes, 0x20))
}
}

return tempBytes;
}
}
48 changes: 30 additions & 18 deletions contracts/schemes/GenericSchemeMultiCall.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
pragma solidity 0.5.17;
pragma experimental ABIEncoderV2;

import "@daostack/infra/contracts/votingMachines/IntVoteInterface.sol";
import "@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol";
import "../votingMachines/VotingMachineCallbacks.sol";
import "../libs/BytesLib.sol";


/**
* @title GenericSchemeMultiCall.
* @dev A scheme for proposing and executing calls to multiple arbitrary function
* on one or multiple contracts on behalf of the organization avatar.
*/
contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterface {
using BytesLib for bytes;
using SafeMath for uint256;

// Details of a voting proposal:
struct MultiCallProposal {
address[] contractsToCall;
bytes[] callsData;
bytes callsData;
uint256[] callsDataLens;
uint256[] values;
bool exist;
bool passed;
Expand All @@ -32,7 +36,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
event NewMultiCallProposal(
address indexed _avatar,
bytes32 indexed _proposalId,
bytes[] _callsData,
bytes _callsData,
uint256[] _values,
string _descriptionHash,
address[] _contractsToCall
Expand All @@ -47,6 +51,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
address indexed _avatar,
bytes32 indexed _proposalId,
address _contractToCall,
bytes _callsData,
bool _success,
bytes _callDataReturnValue
);
Expand All @@ -65,7 +70,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
* @param _votingMachine the voting machines address to
* @param _voteParams voting machine parameters.
* @param _contractWhitelist the contracts the scheme is allowed to interact with
*
*
*/
function initialize(
Avatar _avatar,
Expand All @@ -85,7 +90,7 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
Controller controller = Controller(_avatar.owner());
whitelistedContracts.push(address(controller));
contractWhitelist[address(controller)] = true;

for (uint i = 0; i < _contractWhitelist.length; i++) {
contractWhitelist[_contractWhitelist[i]] = true;
whitelistedContracts.push(_contractWhitelist[i]);
Expand Down Expand Up @@ -130,27 +135,30 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
bytes memory genericCallReturnValue;
bool success;
Controller controller = Controller(whitelistedContracts[0]);
uint256 startIndex = 0;

for (uint i = 0; i < proposal.contractsToCall.length; i++) {
bytes memory callData = proposal.callsData.slice(startIndex, proposal.callsDataLens[i]);
if (proposal.contractsToCall[i] == address(controller)) {
(IERC20 extToken,
address spender,
uint256 valueToSpend
) =
abi.decode(
proposal.callsData[i],
callData,
(IERC20, address, uint256)
);
(success) = controller.externalTokenApproval(extToken, spender, valueToSpend, avatar);
} else {
(success, genericCallReturnValue) =
controller.genericCall(proposal.contractsToCall[i], proposal.callsData[i], avatar, proposal.values[i]);
controller.genericCall(proposal.contractsToCall[i], callData, avatar, proposal.values[i]);
}

startIndex = startIndex.add(proposal.callsDataLens[i]);
emit ProposalCallExecuted(
address(avatar),
_proposalId,
proposal.contractsToCall[i],
callData,
success,
genericCallReturnValue
);
Expand All @@ -164,47 +172,51 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
/**
* @dev propose to call one or multiple contracts on behalf of the _avatar
* The function trigger NewMultiCallProposal event
* @param _contractsToCall the contracts to be called
* @param _contractsToCall the contracts to be called
* @param _callsData - The abi encode data for the calls
* @param _callsDataLens the length of each callData
* @param _values value(ETH) to transfer with the calls
* @param _descriptionHash proposal description hash
* @return an id which represents the proposal
*/
function proposeCalls(
address[] memory _contractsToCall,
bytes[] memory _callsData,
bytes memory _callsData,
uint256[] memory _callsDataLens,
uint256[] memory _values,
string memory _descriptionHash
)
public
returns(bytes32 proposalId)
{
require(
(_contractsToCall.length == _callsData.length) && (_contractsToCall.length == _values.length),
"Wrong length of _contractsToCall, _callsData or _values arrays"
(_contractsToCall.length == _callsDataLens.length) && (_contractsToCall.length == _values.length),
"Wrong length of _contractsToCall, _callsDataLens or _values arrays"
);
Controller controller = Controller(whitelistedContracts[0]);
uint256 startIndex = 0;
for (uint i = 0; i < _contractsToCall.length; i++) {
require(
contractWhitelist[_contractsToCall[i]], "contractToCall is not whitelisted"
);
if (_contractsToCall[i] == address(controller)) {
(IERC20 extToken,
address spender,
uint256 valueToSpend
) =

bytes memory callData = _callsData.slice(startIndex, _callsDataLens[i]);
(, address spender,) =
abi.decode(
_callsData[i],
callData,
(IERC20, address, uint256)
);
require(contractWhitelist[spender], "spender contract not whitelisted");
}
startIndex = startIndex.add(_callsDataLens[i]);
}
proposalId = votingMachine.propose(2, voteParams, msg.sender, address(avatar));

proposals[proposalId] = MultiCallProposal({
contractsToCall: _contractsToCall,
callsData: _callsData,
callsDataLens: _callsDataLens,
values: _values,
exist: true,
passed: false
Expand All @@ -217,4 +229,4 @@ contract GenericSchemeMultiCall is VotingMachineCallbacks, ProposalExecuteInterf
emit NewMultiCallProposal(address(avatar), proposalId, _callsData, _values, _descriptionHash, _contractsToCall);

}
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading