From ada5563b1fd2024ef310786eb8b1f32f3ecee4f0 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 31 Aug 2018 15:20:58 -0700 Subject: Update to most recent multisig --- .../src/2.0.0/multisig/MultiSigWallet.sol | 90 ++++++++++++++-------- .../2.0.0/multisig/MultiSigWalletWithTimeLock.sol | 55 ++++++------- .../protocol/AssetProxyOwner/AssetProxyOwner.sol | 15 ++-- 3 files changed, 89 insertions(+), 71 deletions(-) (limited to 'packages/contracts/src') diff --git a/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol b/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol index eb54fe047..516e7391c 100644 --- a/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol +++ b/packages/contracts/src/2.0.0/multisig/MultiSigWallet.sol @@ -1,13 +1,14 @@ // solhint-disable -pragma solidity ^0.4.10; +pragma solidity ^0.4.15; /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. /// @author Stefan George - contract MultiSigWallet { - uint constant public MAX_OWNER_COUNT = 50; - + /* + * Events + */ event Confirmation(address indexed sender, uint indexed transactionId); event Revocation(address indexed sender, uint indexed transactionId); event Submission(uint indexed transactionId); @@ -18,6 +19,14 @@ contract MultiSigWallet { event OwnerRemoval(address indexed owner); event RequirementChange(uint required); + /* + * Constants + */ + uint constant public MAX_OWNER_COUNT = 50; + + /* + * Storage + */ mapping (uint => Transaction) public transactions; mapping (uint => mapping (address => bool)) public confirmations; mapping (address => bool) public isOwner; @@ -32,60 +41,54 @@ contract MultiSigWallet { bool executed; } + /* + * Modifiers + */ modifier onlyWallet() { - if (msg.sender != address(this)) - throw; + require(msg.sender == address(this)); _; } modifier ownerDoesNotExist(address owner) { - if (isOwner[owner]) - throw; + require(!isOwner[owner]); _; } modifier ownerExists(address owner) { - if (!isOwner[owner]) - throw; + require(isOwner[owner]); _; } modifier transactionExists(uint transactionId) { - if (transactions[transactionId].destination == 0) - throw; + require(transactions[transactionId].destination != 0); _; } modifier confirmed(uint transactionId, address owner) { - if (!confirmations[transactionId][owner]) - throw; + require(confirmations[transactionId][owner]); _; } modifier notConfirmed(uint transactionId, address owner) { - if (confirmations[transactionId][owner]) - throw; + require(!confirmations[transactionId][owner]); _; } modifier notExecuted(uint transactionId) { - if (transactions[transactionId].executed) - throw; + require(!transactions[transactionId].executed); _; } modifier notNull(address _address) { - if (_address == 0) - throw; + require(_address != 0); _; } modifier validRequirement(uint ownerCount, uint _required) { - if ( ownerCount > MAX_OWNER_COUNT - || _required > ownerCount - || _required == 0 - || ownerCount == 0) - throw; + require(ownerCount <= MAX_OWNER_COUNT + && _required <= ownerCount + && _required != 0 + && ownerCount != 0); _; } @@ -108,8 +111,7 @@ contract MultiSigWallet { validRequirement(_owners.length, _required) { for (uint i=0; i<_owners.length; i++) { - if (isOwner[_owners[i]] || _owners[i] == 0) - throw; + require(!isOwner[_owners[i]] && _owners[i] != 0); isOwner[_owners[i]] = true; } owners = _owners; @@ -151,7 +153,7 @@ contract MultiSigWallet { /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. /// @param owner Address of owner to be replaced. - /// @param owner Address of new owner. + /// @param newOwner Address of new owner. function replaceOwner(address owner, address newOwner) public onlyWallet @@ -222,20 +224,44 @@ contract MultiSigWallet { /// @param transactionId Transaction ID. function executeTransaction(uint transactionId) public + ownerExists(msg.sender) + confirmed(transactionId, msg.sender) notExecuted(transactionId) { if (isConfirmed(transactionId)) { - Transaction tx = transactions[transactionId]; - tx.executed = true; - if (tx.destination.call.value(tx.value)(tx.data)) + Transaction storage txn = transactions[transactionId]; + txn.executed = true; + if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) Execution(transactionId); else { ExecutionFailure(transactionId); - tx.executed = false; + txn.executed = false; } } } + // call has been separated into its own function in order to take advantage + // of the Solidity's code generator to produce a loop that copies tx.data into memory. + function external_call(address destination, uint value, uint dataLength, bytes data) internal returns (bool) { + bool result; + assembly { + let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention) + let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that + result := call( + sub(gas, 34710), // 34710 is the value that solidity is currently emitting + // It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) + + // callNewAccountGas (25000, in case the destination address does not exist and needs creating) + destination, + value, + d, + dataLength, // Size of the input (in bytes) - this is what fixes the padding problem + x, + 0 // Output is ignored, therefore the output size is zero + ) + } + return result; + } + /// @dev Returns the confirmation status of a transaction. /// @param transactionId Transaction ID. /// @return Confirmation status. @@ -364,4 +390,4 @@ contract MultiSigWallet { for (i=from; i -contract MultiSigWalletWithTimeLock is MultiSigWallet { +contract MultiSigWalletWithTimeLock is + MultiSigWallet +{ - event ConfirmationTimeSet(uint indexed transactionId, uint confirmationTime); - event TimeLockChange(uint secondsTimeLocked); + event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime); + event TimeLockChange(uint256 secondsTimeLocked); - uint public secondsTimeLocked; + uint256 public secondsTimeLocked; - mapping (uint => uint) public confirmationTimes; + mapping (uint256 => uint256) public confirmationTimes; - modifier notFullyConfirmed(uint transactionId) { + modifier notFullyConfirmed(uint256 transactionId) { require(!isConfirmed(transactionId)); _; } - modifier fullyConfirmed(uint transactionId) { + modifier fullyConfirmed(uint256 transactionId) { require(isConfirmed(transactionId)); _; } - modifier pastTimeLock(uint transactionId) { + modifier pastTimeLock(uint256 transactionId) { require(block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked); _; } @@ -56,7 +58,11 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet { /// @param _owners List of initial owners. /// @param _required Number of required confirmations. /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds. - function MultiSigWalletWithTimeLock(address[] _owners, uint _required, uint _secondsTimeLocked) + function MultiSigWalletWithTimeLock( + address[] _owners, + uint256 _required, + uint256 _secondsTimeLocked + ) public MultiSigWallet(_owners, _required) { @@ -65,7 +71,7 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet { /// @dev Changes the duration of the time lock for transactions. /// @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it becomes executable, in seconds. - function changeTimeLock(uint _secondsTimeLocked) + function changeTimeLock(uint256 _secondsTimeLocked) public onlyWallet { @@ -75,7 +81,7 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet { /// @dev Allows an owner to confirm a transaction. /// @param transactionId Transaction ID. - function confirmTransaction(uint transactionId) + function confirmTransaction(uint256 transactionId) public ownerExists(msg.sender) transactionExists(transactionId) @@ -89,34 +95,21 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet { } } - /// @dev Allows an owner to revoke a confirmation for a transaction. - /// @param transactionId Transaction ID. - function revokeConfirmation(uint transactionId) - public - ownerExists(msg.sender) - confirmed(transactionId, msg.sender) - notExecuted(transactionId) - notFullyConfirmed(transactionId) - { - confirmations[transactionId][msg.sender] = false; - Revocation(msg.sender, transactionId); - } - /// @dev Allows anyone to execute a confirmed transaction. /// @param transactionId Transaction ID. - function executeTransaction(uint transactionId) + function executeTransaction(uint256 transactionId) public notExecuted(transactionId) fullyConfirmed(transactionId) pastTimeLock(transactionId) { - Transaction storage tx = transactions[transactionId]; - tx.executed = true; - if (tx.destination.call.value(tx.value)(tx.data)) + Transaction storage txn = transactions[transactionId]; + txn.executed = true; + if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) Execution(transactionId); else { ExecutionFailure(transactionId); - tx.executed = false; + txn.executed = false; } } @@ -125,7 +118,7 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet { */ /// @dev Sets the time of when a submission first passed. - function setConfirmationTime(uint transactionId, uint confirmationTime) + function setConfirmationTime(uint256 transactionId, uint256 confirmationTime) internal { confirmationTimes[transactionId] = confirmationTime; diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol b/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol index 5f69198e9..6ec710f25 100644 --- a/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol +++ b/packages/contracts/src/2.0.0/protocol/AssetProxyOwner/AssetProxyOwner.sol @@ -38,13 +38,13 @@ contract AssetProxyOwner is /// @dev Function will revert if the transaction does not call `removeAuthorizedAddressAtIndex` /// on an approved AssetProxy contract. modifier validRemoveAuthorizedAddressAtIndexTx(uint256 transactionId) { - Transaction storage tx = transactions[transactionId]; + Transaction storage txn = transactions[transactionId]; require( - isAssetProxyRegistered[tx.destination], + isAssetProxyRegistered[txn.destination], "UNREGISTERED_ASSET_PROXY" ); require( - tx.data.readBytes4(0) == REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR, + txn.data.readBytes4(0) == REMOVE_AUTHORIZED_ADDRESS_AT_INDEX_SELECTOR, "INVALID_FUNCTION_SELECTOR" ); _; @@ -96,14 +96,13 @@ contract AssetProxyOwner is fullyConfirmed(transactionId) validRemoveAuthorizedAddressAtIndexTx(transactionId) { - Transaction storage tx = transactions[transactionId]; - tx.executed = true; - // solhint-disable-next-line avoid-call-value - if (tx.destination.call.value(tx.value)(tx.data)) + Transaction storage txn = transactions[transactionId]; + txn.executed = true; + if (external_call(txn.destination, txn.value, txn.data.length, txn.data)) emit Execution(transactionId); else { emit ExecutionFailure(transactionId); - tx.executed = false; + txn.executed = false; } } } -- cgit v1.2.3