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
|
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.
*/
constructor(address[] memory _owners, uint256 _required, uint256 _daylimit)
Shareable(_owners, _required)
DayLimit(_daylimit) public { }
/**
* @dev destroys the contract sending everything to `_to`.
*/
function destroy(address payable _to) onlymanyowners(keccak256(msg.data)) external {
selfdestruct(_to);
}
/**
* @dev Fallback function, receives value and emits a deposit event.
*/
function() external payable {
// just being sent some cash?
if (msg.value > 0)
emit Deposit(msg.sender, msg.value);
}
/**
* @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,
* anyways.
* @param _to The receiver address
* @param _value The value to send
* @param _data The data part of the transaction
*/
function execute(address _to, uint256 _value, bytes calldata _data) external onlyOwner returns (bytes32 _r) {
// first, take the opportunity to check that we're under the daily limit.
if (underLimit(_value)) {
emit SingleTransact(msg.sender, _value, _to, _data);
// yes - just execute the call.
(bool success,) = _to.call.value(_value)(_data);
require(success);
return 0;
}
// determine our operation hash.
_r = keccak256(abi.encodePacked(msg.data, block.number));
if (!confirm(_r) && txs[_r].to == address(0)) {
txs[_r].to = _to;
txs[_r].value = _value;
txs[_r].data = _data;
emit ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
}
}
/**
* @dev Confirm a transaction by providing just the hash. We use the previous transactions map,
* txs, in order to determine the body of the transaction from the hash provided.
* @param _h The transaction hash to approve.
*/
function confirm(bytes32 _h) onlymanyowners(_h) public returns (bool) {
if (txs[_h].to != address(0)) {
(bool success,) = txs[_h].to.call.value(txs[_h].value)(txs[_h].data);
require(success);
emit MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
delete txs[_h];
return true;
}
}
/**
* @dev Updates the daily limit value.
* @param _newLimit uint256 to represent the new limit.
*/
function setDailyLimit(uint256 _newLimit) onlymanyowners(keccak256(msg.data)) external {
_setDailyLimit(_newLimit);
}
/**
* @dev Resets the value spent to enable more spending
*/
function resetSpentToday() onlymanyowners(keccak256(msg.data)) external {
_resetSpentToday();
}
// INTERNAL METHODS
/**
* @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;
}
|