github.com/XinFinOrg/xdcchain@v1.1.0/contracts/multisigwallet/contract/MultiSigWallet.sol (about)

     1  pragma solidity ^0.4.21;
     2  
     3  
     4  /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
     5  /// @author Stefan George - <stefan.george@consensys.net>
     6  contract MultiSigWallet {
     7  
     8      /*
     9       *  Events
    10       */
    11      event Confirmation(address indexed sender, uint indexed transactionId);
    12      event Revocation(address indexed sender, uint indexed transactionId);
    13      event Submission(uint indexed transactionId);
    14      event Execution(uint indexed transactionId);
    15      event ExecutionFailure(uint indexed transactionId);
    16      event Deposit(address indexed sender, uint value);
    17      event OwnerAddition(address indexed owner);
    18      event OwnerRemoval(address indexed owner);
    19      event RequirementChange(uint required);
    20  
    21      /*
    22       *  Constants
    23       */
    24      uint constant public MAX_OWNER_COUNT = 50;
    25  
    26      /*
    27       *  Storage
    28       */
    29      mapping (uint => Transaction) public transactions;
    30      mapping (uint => mapping (address => bool)) public confirmations;
    31      mapping (address => bool) public isOwner;
    32      address[] public owners;
    33      uint public required;
    34      uint public transactionCount;
    35  
    36      struct Transaction {
    37          address destination;
    38          uint value;
    39          bytes data;
    40          bool executed;
    41      }
    42  
    43      /*
    44       *  Modifiers
    45       */
    46      modifier onlyWallet() {
    47          require(msg.sender == address(this));
    48          _;
    49      }
    50  
    51      modifier ownerDoesNotExist(address owner) {
    52          require(!isOwner[owner]);
    53          _;
    54      }
    55  
    56      modifier ownerExists(address owner) {
    57          require(isOwner[owner]);
    58          _;
    59      }
    60  
    61      modifier transactionExists(uint transactionId) {
    62          require(transactions[transactionId].destination != 0);
    63          _;
    64      }
    65  
    66      modifier confirmed(uint transactionId, address owner) {
    67          require(confirmations[transactionId][owner]);
    68          _;
    69      }
    70  
    71      modifier notConfirmed(uint transactionId, address owner) {
    72          require(!confirmations[transactionId][owner]);
    73          _;
    74      }
    75  
    76      modifier notExecuted(uint transactionId) {
    77          require(!transactions[transactionId].executed);
    78          _;
    79      }
    80  
    81      modifier notNull(address _address) {
    82          require(_address != 0);
    83          _;
    84      }
    85  
    86      modifier validRequirement(uint ownerCount, uint _required) {
    87          require(ownerCount <= MAX_OWNER_COUNT
    88          && _required <= ownerCount
    89          && _required != 0
    90          && ownerCount != 0);
    91          _;
    92      }
    93  
    94      /// @dev Fallback function allows to deposit ether.
    95      function()
    96      payable
    97      {
    98          if (msg.value > 0)
    99              Deposit(msg.sender, msg.value);
   100      }
   101  
   102      /*
   103       * Public functions
   104       */
   105      /// @dev Contract constructor sets initial owners and required number of confirmations.
   106      /// @param _owners List of initial owners.
   107      /// @param _required Number of required confirmations.
   108      function MultiSigWallet(address[] _owners, uint _required)
   109      public
   110      validRequirement(_owners.length, _required)
   111      {
   112          for (uint i=0; i<_owners.length; i++) {
   113              require(!isOwner[_owners[i]] && _owners[i] != 0);
   114              isOwner[_owners[i]] = true;
   115          }
   116          owners = _owners;
   117          required = _required;
   118      }
   119  
   120      /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
   121      /// @param owner Address of new owner.
   122      function addOwner(address owner)
   123      public
   124      onlyWallet
   125      ownerDoesNotExist(owner)
   126      notNull(owner)
   127      validRequirement(owners.length + 1, required)
   128      {
   129          isOwner[owner] = true;
   130          owners.push(owner);
   131          OwnerAddition(owner);
   132      }
   133  
   134      /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
   135      /// @param owner Address of owner.
   136      function removeOwner(address owner)
   137      public
   138      onlyWallet
   139      ownerExists(owner)
   140      {
   141          isOwner[owner] = false;
   142          for (uint i=0; i<owners.length - 1; i++)
   143              if (owners[i] == owner) {
   144                  owners[i] = owners[owners.length - 1];
   145                  break;
   146              }
   147          owners.length -= 1;
   148          if (required > owners.length)
   149              changeRequirement(owners.length);
   150          OwnerRemoval(owner);
   151      }
   152  
   153      /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
   154      /// @param owner Address of owner to be replaced.
   155      /// @param newOwner Address of new owner.
   156      function replaceOwner(address owner, address newOwner)
   157      public
   158      onlyWallet
   159      ownerExists(owner)
   160      ownerDoesNotExist(newOwner)
   161      {
   162          for (uint i=0; i<owners.length; i++)
   163              if (owners[i] == owner) {
   164                  owners[i] = newOwner;
   165                  break;
   166              }
   167          isOwner[owner] = false;
   168          isOwner[newOwner] = true;
   169          OwnerRemoval(owner);
   170          OwnerAddition(newOwner);
   171      }
   172  
   173      /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
   174      /// @param _required Number of required confirmations.
   175      function changeRequirement(uint _required)
   176      public
   177      onlyWallet
   178      validRequirement(owners.length, _required)
   179      {
   180          required = _required;
   181          RequirementChange(_required);
   182      }
   183  
   184      /// @dev Allows an owner to submit and confirm a transaction.
   185      /// @param destination Transaction target address.
   186      /// @param value Transaction ether value.
   187      /// @param data Transaction data payload.
   188      /// @return Returns transaction ID.
   189      function submitTransaction(address destination, uint value, bytes data)
   190      public
   191      returns (uint transactionId)
   192      {
   193          transactionId = addTransaction(destination, value, data);
   194          confirmTransaction(transactionId);
   195      }
   196  
   197      /// @dev Allows an owner to confirm a transaction.
   198      /// @param transactionId Transaction ID.
   199      function confirmTransaction(uint transactionId)
   200      public
   201      ownerExists(msg.sender)
   202      transactionExists(transactionId)
   203      notConfirmed(transactionId, msg.sender)
   204      {
   205          confirmations[transactionId][msg.sender] = true;
   206          Confirmation(msg.sender, transactionId);
   207          executeTransaction(transactionId);
   208      }
   209  
   210      /// @dev Allows an owner to revoke a confirmation for a transaction.
   211      /// @param transactionId Transaction ID.
   212      function revokeConfirmation(uint transactionId)
   213      public
   214      ownerExists(msg.sender)
   215      confirmed(transactionId, msg.sender)
   216      notExecuted(transactionId)
   217      {
   218          confirmations[transactionId][msg.sender] = false;
   219          Revocation(msg.sender, transactionId);
   220      }
   221  
   222      /// @dev Allows anyone to execute a confirmed transaction.
   223      /// @param transactionId Transaction ID.
   224      function executeTransaction(uint transactionId)
   225      public
   226      ownerExists(msg.sender)
   227      confirmed(transactionId, msg.sender)
   228      notExecuted(transactionId)
   229      {
   230          if (isConfirmed(transactionId)) {
   231              Transaction storage txn = transactions[transactionId];
   232              txn.executed = true;
   233              if (txn.destination.call.value(txn.value)(txn.data))
   234                  Execution(transactionId);
   235              else {
   236                  ExecutionFailure(transactionId);
   237                  txn.executed = false;
   238              }
   239          }
   240      }
   241  
   242      /// @dev Returns the confirmation status of a transaction.
   243      /// @param transactionId Transaction ID.
   244      /// @return Confirmation status.
   245      function isConfirmed(uint transactionId)
   246      public
   247      constant
   248      returns (bool)
   249      {
   250          uint count = 0;
   251          for (uint i=0; i<owners.length; i++) {
   252              if (confirmations[transactionId][owners[i]])
   253                  count += 1;
   254              if (count == required)
   255                  return true;
   256          }
   257      }
   258  
   259      /*
   260       * Internal functions
   261       */
   262      /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
   263      /// @param destination Transaction target address.
   264      /// @param value Transaction ether value.
   265      /// @param data Transaction data payload.
   266      /// @return Returns transaction ID.
   267      function addTransaction(address destination, uint value, bytes data)
   268      internal
   269      notNull(destination)
   270      returns (uint transactionId)
   271      {
   272          transactionId = transactionCount;
   273          transactions[transactionId] = Transaction({
   274              destination: destination,
   275              value: value,
   276              data: data,
   277              executed: false
   278              });
   279          transactionCount += 1;
   280          Submission(transactionId);
   281      }
   282  
   283      /*
   284       * Web3 call functions
   285       */
   286      /// @dev Returns number of confirmations of a transaction.
   287      /// @param transactionId Transaction ID.
   288      /// @return Number of confirmations.
   289      function getConfirmationCount(uint transactionId)
   290      public
   291      constant
   292      returns (uint count)
   293      {
   294          for (uint i=0; i<owners.length; i++)
   295              if (confirmations[transactionId][owners[i]])
   296                  count += 1;
   297      }
   298  
   299      /// @dev Returns total number of transactions after filers are applied.
   300      /// @param pending Include pending transactions.
   301      /// @param executed Include executed transactions.
   302      /// @return Total number of transactions after filters are applied.
   303      function getTransactionCount(bool pending, bool executed)
   304      public
   305      constant
   306      returns (uint count)
   307      {
   308          for (uint i=0; i<transactionCount; i++)
   309              if (   pending && !transactions[i].executed
   310              || executed && transactions[i].executed)
   311                  count += 1;
   312      }
   313  
   314      /// @dev Returns list of owners.
   315      /// @return List of owner addresses.
   316      function getOwners()
   317      public
   318      constant
   319      returns (address[])
   320      {
   321          return owners;
   322      }
   323  
   324      /// @dev Returns array with owner addresses, which confirmed transaction.
   325      /// @param transactionId Transaction ID.
   326      /// @return Returns array of owner addresses.
   327      function getConfirmations(uint transactionId)
   328      public
   329      constant
   330      returns (address[] _confirmations)
   331      {
   332          address[] memory confirmationsTemp = new address[](owners.length);
   333          uint count = 0;
   334          uint i;
   335          for (i=0; i<owners.length; i++)
   336              if (confirmations[transactionId][owners[i]]) {
   337                  confirmationsTemp[count] = owners[i];
   338                  count += 1;
   339              }
   340          _confirmations = new address[](count);
   341          for (i=0; i<count; i++)
   342              _confirmations[i] = confirmationsTemp[i];
   343      }
   344  
   345      /// @dev Returns list of transaction IDs in defined range.
   346      /// @param from Index start position of transaction array.
   347      /// @param to Index end position of transaction array.
   348      /// @param pending Include pending transactions.
   349      /// @param executed Include executed transactions.
   350      /// @return Returns array of transaction IDs.
   351      function getTransactionIds(uint from, uint to, bool pending, bool executed)
   352      public
   353      constant
   354      returns (uint[] _transactionIds)
   355      {
   356          uint[] memory transactionIdsTemp = new uint[](transactionCount);
   357          uint count = 0;
   358          uint i;
   359          for (i=0; i<transactionCount; i++)
   360              if (   pending && !transactions[i].executed
   361              || executed && transactions[i].executed)
   362              {
   363                  transactionIdsTemp[count] = i;
   364                  count += 1;
   365              }
   366          _transactionIds = new uint[](to - from);
   367          for (i=from; i<to; i++)
   368              _transactionIds[i - from] = transactionIdsTemp[i];
   369      }
   370  }