-
Notifications
You must be signed in to change notification settings - Fork 969
/
Copy pathMultiSend.sol
59 lines (53 loc) · 2.94 KB
/
MultiSend.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
pragma solidity >=0.5.0 <0.7.0;
/// @title Multi Send - Allows to batch multiple transactions into one.
/// @author Nick Dodson - <[email protected]>
/// @author Gonçalo Sá - <[email protected]>
/// @author Stefan George - <[email protected]>
/// @author Richard Meissner - <[email protected]>
contract MultiSend {
bytes32 constant private GUARD_VALUE = keccak256("multisend.guard.bytes32");
bytes32 guard;
constructor() public {
guard = GUARD_VALUE;
}
/// @dev Sends multiple transactions and reverts all if one fails.
/// @param transactions Encoded transactions. Each transaction is encoded as a packed bytes of
/// operation as a uint8 with 0 for a call or 1 for a delegatecall (=> 1 byte),
/// to as a address (=> 20 bytes),
/// value as a uint256 (=> 32 bytes),
/// data length as a uint256 (=> 32 bytes),
/// data as bytes.
/// see abi.encodePacked for more information on packed encoding
function multiSend(bytes memory transactions)
public
{
require(guard != GUARD_VALUE, "MultiSend should only be called via delegatecall");
// solium-disable-next-line security/no-inline-assembly
assembly {
let length := mload(transactions)
let i := 0x20
for { } lt(i, length) { } {
// First byte of the data is the operation.
// We shift by 248 bits (256 - 8 [operation byte]) it right since mload will always load 32 bytes (a word).
// This will also zero out unused data.
let operation := shr(0xf8, mload(add(transactions, i)))
// We offset the load address by 1 byte (operation byte)
// We shift it right by 96 bits (256 - 160 [20 address bytes]) to right-align the data and zero out unused data.
let to := shr(0x60, mload(add(transactions, add(i, 0x01))))
// We offset the load address by 21 byte (operation byte + 20 address bytes)
let value := mload(add(transactions, add(i, 0x15)))
// We offset the load address by 53 byte (operation byte + 20 address bytes + 32 value bytes)
let dataLength := mload(add(transactions, add(i, 0x35)))
// We offset the load address by 85 byte (operation byte + 20 address bytes + 32 value bytes + 32 data length bytes)
let data := add(transactions, add(i, 0x55))
let success := 0
switch operation
case 0 { success := call(gas, to, value, data, dataLength, 0, 0) }
case 1 { success := delegatecall(gas, to, data, dataLength, 0, 0) }
if eq(success, 0) { revert(0, 0) }
// Next entry starts at 85 byte + data length
i := add(i, add(0x55, dataLength))
}
}
}
}