Update to most recent multisig
This commit is contained in:
parent
78d4fc59a5
commit
ada5563b1f
@ -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 - <stefan.george@consensys.net>
|
||||
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.
|
||||
|
@ -17,33 +17,35 @@
|
||||
*/
|
||||
|
||||
// solhint-disable
|
||||
pragma solidity ^0.4.10;
|
||||
pragma solidity ^0.4.15;
|
||||
|
||||
import "./MultiSigWallet.sol";
|
||||
|
||||
|
||||
/// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed.
|
||||
/// @author Amir Bandeali - <amir@0xProject.com>
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user