'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.default = undefined;var _extends = Object.assign || function (target) {for (var i = 1; i < arguments.length; i++) {var source = arguments[i];for (var key in source) {if (Object.prototype.hasOwnProperty.call(source, key)) {target[key] = source[key];}}}return target;};var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var _createClass = function () {function defineProperties(target, props) {for (var i = 0; i < props.length; i++) {var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);}}return function (Constructor, protoProps, staticProps) {if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};}(); // Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

var _bignumber = require('bignumber.js');var _bignumber2 = _interopRequireDefault(_bignumber);
var _lodash = require('lodash');

var _consensysWallet = require('./wallets/consensys-wallet');var _consensysWallet2 = _interopRequireDefault(_consensysWallet);
var _foundationWallet = require('./wallets/foundation-wallet');var _foundationWallet2 = _interopRequireDefault(_foundationWallet);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };}function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}

var CONSENSYS_WALLET = 'CONSENSYS_WALLET';
var FOUNDATION_WALLET = 'FOUNDATION_WALLET';

var _cachedWalletLookup = {};
var _cachedWalletTypes = {};
var _cachedAccounts = {};var

WalletsUtils = function () {function WalletsUtils() {_classCallCheck(this, WalletsUtils);}_createClass(WalletsUtils, null, [{ key: 'cacheAccounts', value: function cacheAccounts(
    accounts) {
      _cachedAccounts = accounts;
    } }, { key: 'delegateCall', value: function delegateCall(

    api, address, method) {var args = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
      return WalletsUtils.getWalletType(api, address).
      then(function (walletType) {
        if (walletType === CONSENSYS_WALLET) {
          return _consensysWallet2.default[method].apply(null, args);
        }

        return _foundationWallet2.default[method].apply(null, args);
      });
    } }, { key: 'fetchDailylimit', value: function fetchDailylimit(

    walletContract) {var
      api = walletContract.api;

      return WalletsUtils.
      delegateCall(api, walletContract.address, 'fetchDailylimit', [walletContract]);
    } }, { key: 'fetchOwners', value: function fetchOwners(

    walletContract) {var
      api = walletContract.api;

      return WalletsUtils.
      delegateCall(api, walletContract.address, 'fetchOwners', [walletContract]);
    } }, { key: 'fetchRequire', value: function fetchRequire(

    walletContract) {var
      api = walletContract.api;

      return WalletsUtils.
      delegateCall(api, walletContract.address, 'fetchRequire', [walletContract]);
    } }, { key: 'fetchPendingTransactions', value: function fetchPendingTransactions(

    walletContract, cache) {var
      api = walletContract.api;

      return WalletsUtils.
      delegateCall(api, walletContract.address, 'fetchPendingTransactions', [walletContract, cache]);
    } }, { key: 'fetchTransactions', value: function fetchTransactions(

    walletContract) {var
      api = walletContract.api;

      return WalletsUtils.
      delegateCall(api, walletContract.address, 'fetchTransactions', [walletContract]).
      then(function (transactions) {
        return transactions.sort(function (txA, txB) {
          var bnA = txA.blockNumber;
          var bnB = txB.blockNumber;

          if (!bnA) {
            console.warn('could not find block number in transaction', txA);
            return 1;
          }

          if (!bnB) {
            console.warn('could not find block number in transaction', txB);
            return -1;
          }

          var comp = bnA.comparedTo(bnB);

          if (comp !== 0) {
            return comp;
          }

          var txIdxA = txA.transactionIndex;
          var txIdxB = txB.transactionIndex;

          if (!txIdxA) {
            console.warn('could not find transaction index in transaction', txA);
            return 1;
          }

          if (!txIdxB) {
            console.warn('could not find transaction index in transaction', txB);
            return -1;
          }

          return txIdxA.comparedTo(txIdxB);
        });
      });
    } }, { key: 'getCallArgs', value: function getCallArgs(

    api, options) {var values = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
      var walletAddress = options.from;
      var walletContract = void 0;
      var submitMethod = void 0;

      return Promise.
      all([
      WalletsUtils.getWalletContract(api, walletAddress),
      WalletsUtils.delegateCall(api, walletAddress, 'getSubmitMethod')]).

      then(function (_ref) {var _ref2 = _slicedToArray(_ref, 2),_walletContract = _ref2[0],_submitMethod = _ref2[1];
        walletContract = _walletContract;
        submitMethod = _submitMethod;

        return WalletsUtils.fetchOwners(walletContract);
      }).
      then(function (owners) {
        var addresses = Object.keys(_cachedAccounts);
        var ownerAddress = (0, _lodash.intersection)(addresses, owners).pop();

        if (!ownerAddress) {
          return false;
        }

        var account = _cachedAccounts[ownerAddress];
        var _options = _extends({}, options);var
        to = _options.to,_options$value = _options.value,value = _options$value === undefined ? new _bignumber2.default(0) : _options$value,data = _options.data;

        delete _options.data;

        var nextValues = [to, value, data];
        var nextOptions = _extends({},
        _options, {
          from: options.sender || ownerAddress,
          to: walletAddress,
          value: new _bignumber2.default(0) });


        var execFunc = walletContract.instance[submitMethod];
        var callArgs = { func: execFunc, options: nextOptions, values: nextValues };

        if (!account.wallet) {
          return callArgs;
        }

        var nextData = walletContract.getCallData(execFunc, nextOptions, nextValues);

        return WalletsUtils.getCallArgs(api, _extends({}, nextOptions, { data: nextData }), nextValues);
      });
    } }, { key: 'getChangeMethod', value: function getChangeMethod(

    api, address, change) {
      return WalletsUtils.
      delegateCall(api, address, 'getChangeMethod', [api, address, change]);
    } }, { key: 'getDeployArgs', value: function getDeployArgs(

    contract, options, values) {var
      api = contract.api;
      var func = contract.constructors[0];

      options.data = contract.getCallData(func, options, values);
      options.to = '0x';

      return WalletsUtils.
      getCallArgs(api, options, values).
      then(function (callArgs) {
        if (!callArgs) {
          console.error('no call args', callArgs);
          throw new Error('you do not own this wallet');
        }

        return callArgs;
      });
    } }, { key: 'getWalletContract', value: function getWalletContract(

    api, address) {
      return WalletsUtils.
      delegateCall(api, address, 'getWalletContract', [api]).
      then(function (walletContract) {
        return walletContract.at(address);
      });
    } }, { key: 'getWalletType', value: function getWalletType(

    api, address) {
      if (_cachedWalletTypes[address] === undefined) {
        _cachedWalletTypes[address] = Promise.resolve(null).
        then(function (result) {
          if (result) {
            return result;
          }

          return _foundationWallet2.default.isWallet(api, address).
          then(function (isWallet) {return isWallet && FOUNDATION_WALLET;});
        }).
        then(function (result) {
          if (result) {
            return result;
          }

          return _consensysWallet2.default.isWallet(api, address).
          then(function (isWallet) {return isWallet && CONSENSYS_WALLET;});
        }).
        then(function (result) {
          _cachedWalletTypes[address] = result || null;

          return _cachedWalletTypes[address];
        });
      }

      return Promise.resolve(_cachedWalletTypes[address]);
    }

    /**
       * Check whether the given address could be
       * a Wallet. The result is cached in order not
       * to make unnecessary calls on non-wallet accounts
       */ }, { key: 'isWallet', value: function isWallet(
    api, address) {
      if (!address) {
        return Promise.resolve(false);
      }

      if (!_cachedWalletLookup[address]) {
        _cachedWalletLookup[address] = WalletsUtils.getWalletType(api, address).
        then(function (walletType) {return walletType !== null;}).
        then(function (bool) {
          _cachedWalletLookup[address] = Promise.resolve(bool);
          return bool;
        });
      }

      return _cachedWalletLookup[address];
    } }, { key: 'logToUpdate', value: function logToUpdate(

    api, address, log) {
      return WalletsUtils.
      delegateCall(api, address, 'logToUpdate', [log]);
    } }, { key: 'parseTransactionLogs', value: function parseTransactionLogs(

    api, options, rawLogs) {
      return WalletsUtils.
      delegateCall(api, options.from, 'parseTransactionLogs', [api, options, rawLogs]);
    } }, { key: 'postModifyOperation', value: function postModifyOperation(

    api, walletAddress, modification, owner, operation) {
      var options = { from: owner };
      var values = [operation];

      return Promise.
      all([
      WalletsUtils.
      getWalletContract(api, walletAddress),
      WalletsUtils.
      delegateCall(api, walletAddress, 'getModifyOperationMethod', [modification])]).

      then(function (_ref3) {var _ref4 = _slicedToArray(_ref3, 2),wallet = _ref4[0],method = _ref4[1];
        return wallet.instance[method].
        estimateGas(options, values).
        then(function (gas) {
          options.gas = gas.mul(1.5);
          return wallet.instance[method].postTransaction(options, values);
        });
      });
    } }]);return WalletsUtils;}();exports.default = WalletsUtils;