2017-07-05 10:28:15 +00:00
|
|
|
pragma solidity ^0.4.11;
|
|
|
|
|
|
|
|
|
|
|
|
import "./ownership/Multisig.sol";
|
|
|
|
import "./ownership/Shareable.sol";
|
|
|
|
import "./DayLimit.sol";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MultisigWallet
|
|
|
|
* Usage:
|
|
|
|
* bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
|
|
|
|
* Wallet(w).from(anotherOwner).confirm(h);
|
|
|
|
*/
|
|
|
|
contract MultisigWallet is Multisig, Shareable, DayLimit {
|
|
|
|
|
|
|
|
struct Transaction {
|
|
|
|
address to;
|
|
|
|
uint256 value;
|
|
|
|
bytes data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor, sets the owners addresses, number of approvals required, and daily spending limit
|
|
|
|
* @param _owners A list of owners.
|
|
|
|
* @param _required The amount required for a transaction to be approved.
|
|
|
|
*/
|
2018-07-14 21:42:01 +00:00
|
|
|
constructor(address[] memory _owners, uint256 _required, uint256 _daylimit)
|
2018-06-25 13:02:20 +00:00
|
|
|
Shareable(_owners, _required)
|
2018-07-04 17:20:51 +00:00
|
|
|
DayLimit(_daylimit) public { }
|
2017-07-05 10:28:15 +00:00
|
|
|
|
2018-07-04 17:20:51 +00:00
|
|
|
/**
|
|
|
|
* @dev destroys the contract sending everything to `_to`.
|
2017-07-05 10:28:15 +00:00
|
|
|
*/
|
2018-09-12 14:21:43 +00:00
|
|
|
function destroy(address payable _to) onlymanyowners(keccak256(msg.data)) external {
|
2017-07-05 10:28:15 +00:00
|
|
|
selfdestruct(_to);
|
|
|
|
}
|
|
|
|
|
2018-07-04 17:20:51 +00:00
|
|
|
/**
|
|
|
|
* @dev Fallback function, receives value and emits a deposit event.
|
2017-07-05 10:28:15 +00:00
|
|
|
*/
|
2018-06-28 16:08:45 +00:00
|
|
|
function() external payable {
|
2017-07-05 10:28:15 +00:00
|
|
|
// just being sent some cash?
|
|
|
|
if (msg.value > 0)
|
2018-06-27 08:35:38 +00:00
|
|
|
emit Deposit(msg.sender, msg.value);
|
2017-07-05 10:28:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-07-04 17:20:51 +00:00
|
|
|
* @dev Outside-visible transaction entry point. Executes transaction immediately if below daily
|
|
|
|
* spending limit. If not, goes into multisig process. We provide a hash on return to allow the
|
|
|
|
* sender to provide shortcuts for the other confirmations (allowing them to avoid replicating
|
|
|
|
* the _to, _value, and _data arguments). They still get the option of using them if they want,
|
2017-07-05 10:28:15 +00:00
|
|
|
* anyways.
|
|
|
|
* @param _to The receiver address
|
|
|
|
* @param _value The value to send
|
|
|
|
* @param _data The data part of the transaction
|
|
|
|
*/
|
2018-08-07 20:12:52 +00:00
|
|
|
function execute(address _to, uint256 _value, bytes calldata _data) external onlyOwner returns (bytes32 _r) {
|
2017-07-05 10:28:15 +00:00
|
|
|
// first, take the opportunity to check that we're under the daily limit.
|
|
|
|
if (underLimit(_value)) {
|
2018-06-27 08:35:38 +00:00
|
|
|
emit SingleTransact(msg.sender, _value, _to, _data);
|
2017-07-05 10:28:15 +00:00
|
|
|
// yes - just execute the call.
|
2018-08-15 22:39:19 +00:00
|
|
|
(bool success,) = _to.call.value(_value)(_data);
|
|
|
|
require(success);
|
2017-07-05 10:28:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// determine our operation hash.
|
2018-06-14 10:28:33 +00:00
|
|
|
_r = keccak256(abi.encodePacked(msg.data, block.number));
|
2018-06-12 09:05:49 +00:00
|
|
|
if (!confirm(_r) && txs[_r].to == address(0)) {
|
2017-07-05 10:28:15 +00:00
|
|
|
txs[_r].to = _to;
|
|
|
|
txs[_r].value = _value;
|
|
|
|
txs[_r].data = _data;
|
2018-06-27 08:35:38 +00:00
|
|
|
emit ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
|
2017-07-05 10:28:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-07-04 17:20:51 +00:00
|
|
|
* @dev Confirm a transaction by providing just the hash. We use the previous transactions map,
|
2017-07-05 10:28:15 +00:00
|
|
|
* txs, in order to determine the body of the transaction from the hash provided.
|
|
|
|
* @param _h The transaction hash to approve.
|
|
|
|
*/
|
2018-07-04 17:20:51 +00:00
|
|
|
function confirm(bytes32 _h) onlymanyowners(_h) public returns (bool) {
|
2018-06-12 09:05:49 +00:00
|
|
|
if (txs[_h].to != address(0)) {
|
2018-08-15 22:39:19 +00:00
|
|
|
(bool success,) = txs[_h].to.call.value(txs[_h].value)(txs[_h].data);
|
|
|
|
require(success);
|
2018-06-27 08:35:38 +00:00
|
|
|
emit MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
|
2017-07-05 10:28:15 +00:00
|
|
|
delete txs[_h];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-04 17:20:51 +00:00
|
|
|
/**
|
|
|
|
* @dev Updates the daily limit value.
|
2017-07-05 10:28:15 +00:00
|
|
|
* @param _newLimit uint256 to represent the new limit.
|
|
|
|
*/
|
|
|
|
function setDailyLimit(uint256 _newLimit) onlymanyowners(keccak256(msg.data)) external {
|
|
|
|
_setDailyLimit(_newLimit);
|
|
|
|
}
|
|
|
|
|
2018-07-04 17:20:51 +00:00
|
|
|
/**
|
2017-07-05 10:28:15 +00:00
|
|
|
* @dev Resets the value spent to enable more spending
|
|
|
|
*/
|
|
|
|
function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
|
|
|
|
_resetSpentToday();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// INTERNAL METHODS
|
2018-07-04 17:20:51 +00:00
|
|
|
/**
|
2017-07-05 10:28:15 +00:00
|
|
|
* @dev Clears the list of transactions pending approval.
|
|
|
|
*/
|
|
|
|
function clearPending() internal {
|
|
|
|
uint256 length = pendingsIndex.length;
|
|
|
|
for (uint256 i = 0; i < length; ++i) {
|
|
|
|
delete txs[pendingsIndex[i]];
|
|
|
|
}
|
|
|
|
super.clearPending();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FIELDS
|
|
|
|
|
|
|
|
// pending transactions we have at present.
|
|
|
|
mapping (bytes32 => Transaction) txs;
|
|
|
|
}
|