<commit_before>'use strict';

angular.module('copayApp.services').factory('walletService', function($rootScope, $log, $timeout, $ionicLoading, lodash, trezor, ledger, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService, bitlox, platformInfo, txUtil) {
  // `wallet` is a decorated version of client.

  var root = {};

  root.WALLET_STATUS_MAX_TRIES = 7;
  root.WALLET_STATUS_DELAY_BETWEEN_TRIES = 1.4 * 1000;
  root.SOFT_CONFIRMATION_LIMIT = 12;
  root.SAFE_CONFIRMATIONS = 6;

  var errors = bwcService.getErrors();

  var _signWithLedger = function(wallet, txp, cb) {
    $log.info('Requesting Ledger Chrome app to sign the transaction');

    ledger.signTx(txp, wallet.credentials.account, function(result) {
      $log.debug('Ledger response', result);
      if (!result.success)
        return cb(result.message || result.error);

      txp.signatures = lodash.map(result.signatures, function(s) {
        return s.substring(0, s.length - 2);
      });
      return wallet.signTxProposal(txp, cb);
    });
  };

  var _signWithTrezor = function(wallet, txp, cb) {
    $log.info('Requesting Trezor  to sign the transaction');

    var xPubKeys = lodash.pluck(wallet.credentials.publicKeyRing, 'xPubKey');
    trezor.signTx(xPubKeys, txp, wallet.credentials.account, function(err, result) {
      if (err) return cb(err);

      $log.debug('Trezor response', result);
      txp.signatures = result.signatures;
      return wallet.signTxProposal(txp, cb);
    });
  };

  var _signWithBitlox = function(wallet, txp, cb) {
    console.log(txp)
      if(platformInfo.isMobile && bitlox.api.getStatus() !== bitlox.api.STATUS_CONNECTED && bitlox.api.getStatus() !== bitlox.api.STATUS_IDLE) {
        var newScope = $rootScope.$new();
        var successListener;
        var errorListener
        $ionicModal.fromTemplateUrl('views/bitlox/tab-attach-bitlox-modal.html', {
            scope: newScope,
            animation: 'slide-in-up',
            hardwareBackButtonClose: false
          }).then(function(modal) {
            newScope.modal = modal;
            newScope.modal.show();
          }).catch(function(err) {
            $log.debug('modal error', err)
          });
          newScope.closeModal = function() {
            newScope.modal.remove();
          };
          // Cleanup the modal when we're done with it!
          newScope.$on('$destroy', function() {
            newScope.modal.remove();
          });
          // Execute action on hide modal
          newScope.$on('modal.hidden', function() {
            // Execute action
          });

          newScope.$on('modal.removed', function() {
            // Execute action
            successListener()
            errorListener()
            setTimeout(function() {_bitloxSend(wallet,txp,cb)},1000)
          });
          successListener = newScope.$on('bitloxConnectSuccess', function() {
            // Execute action
            newScope.modal.remove()
          });
          errorListener = newScope.$on('bitloxConnectError', function() {
            // Execute action
          });          
      } else {
        _bitloxSend(wallet,txp,cb)
      }
  }
  function _bitloxSend(wallet,txp,cb) {
    $ionicLoading.show({
      template: 'Check Your BitLox...'
    });    
    if(platformInfo.isMobile && bitlox.api.getStatus() !== bitlox.api.STATUS_IDLE && bitlox.api.getStatus() !== bitlox.api.STATUS_CONNECTED) {

      return cb(new Error("Unable to connect to BitLox"))
    }

    try {

      var tx = new bitlox.transaction({
          outputs: txp.outputs,
          fee: txp.fee,
          inputs: txp.inputs,
          changeAddress: txp.changeAddress.address,
          // forceSmallChange: forceSmallChange,
      });
    } catch(e) {
      return cb(e)
    }
    tx.bwsInputs = txp.inputs


    $log.info('Requesting Bitlox to sign the transaction');
    var xPubKeys = lodash.pluck(wallet.credentials.publicKeyRing, 'xPubKey');
    // var opts = {tx: txp, rawTx: bwcService.getUtils().buildTx(txp).uncheckedSerialize()}
    if(!xPubKeys) {
      return cb(new Error("Unable to connect to BitLox, pub key error"))
    }
    $log.debug('xPubKeys', xPubKeys)

    return bitlox.api.getDeviceUUID().then(function(results) {
      var externalSource = wallet.getPrivKeyExternalSourceName()
      var bitloxInfo = externalSource.split('/')
      if(bitloxInfo[1] !== results.payload.device_uuid.toString('hex')) {
        return cb(new Error('This wallet is not on the connected BitLox device or has been moved. Select the correct Bitlox or contact support.'))
      }
      $log.debug(bitloxInfo)
      return bitlox.wallet.list()
      .then(function(wallets) {
        for(var i=0; i<wallets.length;i++) {
          thisWallet = wallets[i]

          if(thisWallet._uuid.toString("hex") === bitloxInfo[2]) {
            return thisWallet.open()
            .then(function() {
                $log.debug("WALLET LOADED", thisWallet.xpub)

                if(thisWallet.xpub !== xPubKeys[0]) {
                  $log.debug('pubkeys do not match')
                  return cb(new Error('pubkeys do not match'))
                }
                var changeIndex = txp.changeAddress.path.split('/')[2]
                $log.debug('changeIndex', changeIndex)
                return bitlox.api.setChangeAddress(changeIndex).then(function() {
                  $log.debug('Done setting change address')
                  return bitlox.api.signTransaction(tx)
                  .then(function(result) {
                    $log.debug('Bitlox response', result);
                    if(result.type === bitlox.api.TYPE_SIGNATURE_RETURN) {
                      txp.signatures = result.payload.signedScripts;
                      tx.replaceScripts(txp.signatures)
                      return root.removeTx(wallet, txp, function() {
                        // return txUtil.submit(tx.signedHex).then(function() {
                        //   return cb(null, txp)
                        // }, function(err) {
                        //   return cb(err)
                        // })
                        return cb(null,txp)
                      })
                    } else {
                      $log.debug('TX parse error', result)
                      return cb(new Error("TX parse error"))
                    }<commit_msg>more async lovelies, finalizing sending TX on BLE<commit_after>'use strict';

angular.module('copayApp.services').factory('walletService', function($rootScope, $log, $timeout, $ionicLoading, lodash, trezor, ledger, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService, bitlox, platformInfo, txUtil) {
  // `wallet` is a decorated version of client.

  var root = {};

  root.WALLET_STATUS_MAX_TRIES = 7;
  root.WALLET_STATUS_DELAY_BETWEEN_TRIES = 1.4 * 1000;
  root.SOFT_CONFIRMATION_LIMIT = 12;
  root.SAFE_CONFIRMATIONS = 6;

  var errors = bwcService.getErrors();

  var _signWithLedger = function(wallet, txp, cb) {
    $log.info('Requesting Ledger Chrome app to sign the transaction');

    ledger.signTx(txp, wallet.credentials.account, function(result) {
      $log.debug('Ledger response', result);
      if (!result.success)
        return cb(result.message || result.error);

      txp.signatures = lodash.map(result.signatures, function(s) {
        return s.substring(0, s.length - 2);
      });
      return wallet.signTxProposal(txp, cb);
    });
  };

  var _signWithTrezor = function(wallet, txp, cb) {
    $log.info('Requesting Trezor  to sign the transaction');

    var xPubKeys = lodash.pluck(wallet.credentials.publicKeyRing, 'xPubKey');
    trezor.signTx(xPubKeys, txp, wallet.credentials.account, function(err, result) {
      if (err) return cb(err);

      $log.debug('Trezor response', result);
      txp.signatures = result.signatures;
      return wallet.signTxProposal(txp, cb);
    });
  };

  var _signWithBitlox = function(wallet, txp, cb) {
    console.log(txp)
      if(platformInfo.isMobile && bitlox.api.getStatus() !== bitlox.api.STATUS_CONNECTED && bitlox.api.getStatus() !== bitlox.api.STATUS_IDLE) {
        var newScope = $rootScope.$new();
        var successListener;
        var errorListener
        $ionicModal.fromTemplateUrl('views/bitlox/tab-attach-bitlox-modal.html', {
            scope: newScope,
            animation: 'slide-in-up',
            hardwareBackButtonClose: false
          }).then(function(modal) {
            newScope.modal = modal;
            newScope.modal.show();
          }).catch(function(err) {
            $log.debug('modal error', err)
          });
          newScope.closeModal = function() {
            newScope.modal.remove();
          };
          // Cleanup the modal when we're done with it!
          newScope.$on('$destroy', function() {
            newScope.modal.remove();
          });
          // Execute action on hide modal
          newScope.$on('modal.hidden', function() {
            // Execute action
          });

          newScope.$on('modal.removed', function() {
            // Execute action
            successListener()
            errorListener()
            setTimeout(function() {_bitloxSend(wallet,txp,cb)},1000)
          });
          successListener = newScope.$on('bitloxConnectSuccess', function() {
            // Execute action
            newScope.modal.remove()
          });
          errorListener = newScope.$on('bitloxConnectError', function() {
            // Execute action
          });          
      } else {
        _bitloxSend(wallet,txp,cb)
      }
  }
  function _bitloxSend(wallet,txp,cb) {
    $ionicLoading.show({
      template: 'Check Your BitLox...'
    });    
    if(platformInfo.isMobile && bitlox.api.getStatus() !== bitlox.api.STATUS_IDLE && bitlox.api.getStatus() !== bitlox.api.STATUS_CONNECTED) {

      return cb(new Error("Unable to connect to BitLox"))
    }

    try {

      var tx = new bitlox.transaction({
          outputs: txp.outputs,
          fee: txp.fee,
          inputs: txp.inputs,
          changeAddress: txp.changeAddress.address,
          // forceSmallChange: forceSmallChange,
      });
    } catch(e) {
      return cb(e)
    }
    tx.bwsInputs = txp.inputs


    $log.info('Requesting Bitlox to sign the transaction');
    var xPubKeys = lodash.pluck(wallet.credentials.publicKeyRing, 'xPubKey');
    // var opts = {tx: txp, rawTx: bwcService.getUtils().buildTx(txp).uncheckedSerialize()}
    if(!xPubKeys) {
      return cb(new Error("Unable to connect to BitLox, pub key error"))
    }
    $log.debug('xPubKeys', xPubKeys)

    return bitlox.api.getDeviceUUID().then(function(results) {
      var externalSource = wallet.getPrivKeyExternalSourceName()
      var bitloxInfo = externalSource.split('/')
      if(bitloxInfo[1] !== results.payload.device_uuid.toString('hex')) {
        return cb(new Error('This wallet is not on the connected BitLox device or has been moved. Select the correct Bitlox or contact support.'))
      }
      $log.debug(bitloxInfo)
      return bitlox.wallet.list()
      .then(function(wallets) {
        for(var i=0; i<wallets.length;i++) {
          thisWallet = wallets[i]

          if(thisWallet._uuid.toString("hex") === bitloxInfo[2]) {
            return thisWallet.open()
            .then(function() {
                $log.debug("WALLET LOADED", thisWallet.xpub)

                if(thisWallet.xpub !== xPubKeys[0]) {
                  $log.debug('pubkeys do not match')
                  return cb(new Error('pubkeys do not match'))
                }
                var changeIndex = txp.changeAddress.path.split('/')[2]
                $log.debug('changeIndex', changeIndex)
                return bitlox.api.setChangeAddress(changeIndex).then(function() {
                  $log.debug('Done setting change address')
                  return bitlox.api.signTransaction(tx)
                  .then(function(result) {
                    $log.debug('Bitlox response', result);
                    if(result.type === bitlox.api.TYPE_SIGNATURE_RETURN) {
                      txp.signatures = result.payload.signedScripts;
                      tx.replaceScripts(txp.signatures)
                      return root.removeTx(wallet, txp, function() {
                        // comment out thes 5 lines and send `return cb(null,txp) to skip broadcast`
                        return txUtil.submit(tx.signedHex).then(function() {
                          return cb(null, txp)
                        }, function(err) {
                          return cb(err)
                        })
                        // return cb(null,txp) 
                      })
                    } else {
                      $log.debug('TX parse error', result)
                      return cb(new Error("TX parse error"))
                    }
{'fraction_non_alphanumeric': 0.12543819539704312, 'fraction_numerical': 0.0032769394909312605, 'mean_word_length': 2.169806763285024, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1535084', 'n_tokens_mistral': 3940, 'n_tokens_neox': 3857, 'n_words': 759}