forked from BitGo/eth-multisig-v4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBatcher.sol
131 lines (117 loc) · 4.1 KB
/
Batcher.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
pragma solidity 0.8.10;
// SPDX-License-Identifier: Apache-2.0
/**
*
* Batcher
* =======
*
* Contract that can take a batch of transfers, presented in the form of a recipients array and a values array, and
* funnel off those funds to the correct accounts in a single transaction. This is useful for saving on gas when a
* bunch of funds need to be transferred to different accounts.
*
* If more ETH is sent to `batch` than it is instructed to transfer, contact the contract owner in order to recover the excess.
* If any tokens are accidentally transferred to this account, contact the contract owner in order to recover them.
*
*/
contract Batcher {
event BatchTransfer(address sender, address recipient, uint256 value);
event OwnerChange(address prevOwner, address newOwner);
event TransferGasLimitChange(
uint256 prevTransferGasLimit,
uint256 newTransferGasLimit
);
address public owner;
uint256 public lockCounter;
uint256 public transferGasLimit;
constructor() {
lockCounter = 1;
owner = msg.sender;
emit OwnerChange(address(0), owner);
transferGasLimit = 20000;
emit TransferGasLimitChange(0, transferGasLimit);
}
modifier lockCall() {
lockCounter++;
uint256 localCounter = lockCounter;
_;
require(localCounter == lockCounter, 'Reentrancy attempt detected');
}
modifier onlyOwner() {
require(msg.sender == owner, 'Not owner');
_;
}
/**
* Transfer funds in a batch to each of recipients
* @param recipients The list of recipients to send to
* @param values The list of values to send to recipients.
* The recipient with index i in recipients array will be sent values[i].
* Thus, recipients and values must be the same length
*/
function batch(address[] calldata recipients, uint256[] calldata values)
external
payable
lockCall
{
require(recipients.length != 0, 'Must send to at least one person');
require(
recipients.length == values.length,
'Unequal recipients and values'
);
require(recipients.length < 256, 'Too many recipients');
// Try to send all given amounts to all given recipients
// Revert everything if any transfer fails
for (uint8 i = 0; i < recipients.length; i++) {
require(recipients[i] != address(0), 'Invalid recipient address');
(bool success, ) = recipients[i].call{
value: values[i],
gas: transferGasLimit
}('');
require(success, 'Send failed');
emit BatchTransfer(msg.sender, recipients[i], values[i]);
}
}
/**
* Recovery function for the contract owner to recover any ERC20 tokens or ETH that may get lost in the control of this contract.
* @param to The recipient to send to
* @param value The ETH value to send with the call
* @param data The data to send along with the call
*/
function recover(
address to,
uint256 value,
bytes calldata data
) external onlyOwner returns (bytes memory) {
(bool success, bytes memory returnData) = to.call{ value: value }(data);
require(success, 'Recover failed');
return returnData;
}
/**
* Transfers ownership of the contract ot the new owner
* @param newOwner The address to transfer ownership of the contract to
*/
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), 'Invalid new owner');
emit OwnerChange(owner, newOwner);
owner = newOwner;
}
/**
* Change the gas limit that is sent along with batched transfers.
* This is intended to protect against any EVM level changes that would require
* a new amount of gas for an internal send to complete.
* @param newTransferGasLimit The new gas limit to send along with batched transfers
*/
function changeTransferGasLimit(uint256 newTransferGasLimit)
external
onlyOwner
{
require(newTransferGasLimit >= 2300, 'Transfer gas limit too low');
emit TransferGasLimitChange(transferGasLimit, newTransferGasLimit);
transferGasLimit = newTransferGasLimit;
}
fallback() external payable {
revert('Invalid fallback');
}
receive() external payable {
revert('Invalid receive');
}
}