Merge pull request #4 from OpenZeppelin/master

Merge multisig fixes
pull/83/head
Arseniy Klempner 8 years ago committed by GitHub
commit c7f14083c1
  1. 2
      contracts/DayLimit.sol
  2. 2
      contracts/Multisig.sol
  3. 93
      contracts/MultisigWallet.sol

@ -53,7 +53,7 @@ contract DayLimit is Shareable {
// checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and
// returns true. otherwise just returns false. // returns true. otherwise just returns false.
function underLimit(uint _value) internal onlyowner returns (bool) { function underLimit(uint _value) internal onlyOwner returns (bool) {
// reset the spend limit if we're on a different day to last time. // reset the spend limit if we're on a different day to last time.
if (today() > lastDay) { if (today() > lastDay) {
spentToday = 0; spentToday = 0;

@ -3,7 +3,7 @@ pragma solidity ^0.4.4;
/* /*
* Multisig * Multisig
* interface contract for multisig proxy contracts; see below for docs. * Interface contract for multisig proxy contracts; see below for docs.
*/ */
contract Multisig { contract Multisig {
// EVENTS // EVENTS

@ -1,34 +1,18 @@
pragma solidity ^0.4.4; pragma solidity ^0.4.4;
// interface contract for multisig proxy contracts; see below for docs. import "./Multisig.sol";
contract multisig { import "./Shareable.sol";
// EVENTS import "./DayLimit.sol";
// logged events:
// Funds has arrived into the wallet (record how much). /*
event Deposit(address _from, uint value); * MultisigWallet
// Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). * usage:
event SingleTransact(address owner, uint value, address to, bytes data); * bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
// Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going). * Wallet(w).from(anotherOwner).confirm(h);
event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data); */
// Confirmation still needed for a transaction. contract MultisigWallet is Multisig, Shareable, DayLimit {
event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data);
// FUNCTIONS
// TODO: document
function changeOwner(address _from, address _to) external;
function execute(address _to, uint _value, bytes _data) external returns (bytes32);
function confirm(bytes32 _h) returns (bool);
}
// usage:
// bytes32 h = Wallet(w).from(oneOwner).execute(to, value, data);
// Wallet(w).from(anotherOwner).confirm(h);
contract Wallet is multisig, Shareable, daylimit {
// TYPES // TYPES
// Transaction structure to remember details of transaction lest it need be saved for a later call. // Transaction structure to remember details of transaction lest it need be saved for a later call.
@ -38,13 +22,17 @@ contract Wallet is multisig, Shareable, daylimit {
bytes data; bytes data;
} }
// METHODS
// constructor - just pass on the owner array to the multiowned and // CONSTRUCTOR
// just pass on the owner array to the multiowned and
// the limit to daylimit // the limit to daylimit
function Wallet(address[] _owners, uint _required, uint _daylimit) function MultisigWallet(address[] _owners, uint _required, uint _daylimit)
multiowned(_owners, _required) daylimit(_daylimit) { Shareable(_owners, _required)
} DayLimit(_daylimit) { }
// METHODS
// kills the contract sending everything to `_to`. // kills the contract sending everything to `_to`.
function kill(address _to) onlymanyowners(sha3(msg.data)) external { function kill(address _to) onlymanyowners(sha3(msg.data)) external {
@ -52,7 +40,7 @@ contract Wallet is multisig, Shareable, daylimit {
} }
// gets called when no other function matches // gets called when no other function matches
function() { function() payable {
// just being sent some cash? // just being sent some cash?
if (msg.value > 0) if (msg.value > 0)
Deposit(msg.sender, msg.value); Deposit(msg.sender, msg.value);
@ -62,46 +50,53 @@ contract Wallet is multisig, Shareable, daylimit {
// If not, goes into multisig process. We provide a hash on return to allow the sender to provide // 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 // 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. // and _data arguments). They still get the option of using them if they want, anyways.
function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 _r) { function execute(address _to, uint _value, bytes _data) external onlyOwner returns (bytes32 _r) {
// first, take the opportunity to check that we're under the daily limit. // first, take the opportunity to check that we're under the daily limit.
if (underLimit(_value)) { if (underLimit(_value)) {
SingleTransact(msg.sender, _value, _to, _data); SingleTransact(msg.sender, _value, _to, _data);
// yes - just execute the call. // yes - just execute the call.
_to.call.value(_value)(_data); if (!_to.call.value(_value)(_data)) {
throw;
}
return 0; return 0;
} }
// determine our operation hash. // determine our operation hash.
_r = sha3(msg.data, block.number); _r = sha3(msg.data, block.number);
if (!confirm(_r) && m_txs[_r].to == 0) { if (!confirm(_r) && txs[_r].to == 0) {
m_txs[_r].to = _to; txs[_r].to = _to;
m_txs[_r].value = _value; txs[_r].value = _value;
m_txs[_r].data = _data; txs[_r].data = _data;
ConfirmationNeeded(_r, msg.sender, _value, _to, _data); ConfirmationNeeded(_r, msg.sender, _value, _to, _data);
} }
} }
// confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order // confirm a transaction through just the hash. we use the previous transactions map, txs, in order
// to determine the body of the transaction from the hash provided. // to determine the body of the transaction from the hash provided.
function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) { function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) {
if (m_txs[_h].to != 0) { if (txs[_h].to != 0) {
m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data); if (!txs[_h].to.call.value(txs[_h].value)(txs[_h].data)) {
MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data); throw;
delete m_txs[_h]; }
MultiTransact(msg.sender, _h, txs[_h].value, txs[_h].to, txs[_h].data);
delete txs[_h];
return true; return true;
} }
} }
// INTERNAL METHODS // INTERNAL METHODS
function clearPending() internal { function clearPending() internal {
uint length = m_pendingIndex.length; uint length = pendingsIndex.length;
for (uint i = 0; i < length; ++i) for (uint i = 0; i < length; ++i) {
delete m_txs[m_pendingIndex[i]]; delete txs[pendingsIndex[i]];
}
super.clearPending(); super.clearPending();
} }
// FIELDS // FIELDS
// pending transactions we have at present. // pending transactions we have at present.
mapping (bytes32 => Transaction) m_txs; mapping (bytes32 => Transaction) txs;
} }

Loading…
Cancel
Save