2016-05-09 15:56:44 -03:00
|
|
|
'use strict';
|
|
|
|
|
|
2016-06-06 18:26:45 -03:00
|
|
|
// DO NOT INCLUDE STORAGE HERE \/ \/
|
2016-08-18 11:45:30 -03:00
|
|
|
angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, storageService, configService, rateService, uxLanguage, bwcService, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txStatus, txFormatService, $ionicModal) {
|
2016-08-12 11:10:26 -03:00
|
|
|
// DO NOT INCLUDE STORAGE HERE ^^
|
2016-08-15 10:25:43 -03:00
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// `wallet` is a decorated version of client.
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-05-09 15:56:44 -03:00
|
|
|
var root = {};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
|
2016-08-18 10:08:23 -03:00
|
|
|
// UI Related
|
|
|
|
|
root.openStatusModal = function(type, txp, cb) {
|
|
|
|
|
var scope = $rootScope.$new(true);
|
|
|
|
|
scope.type = type;
|
|
|
|
|
scope.tx = txFormatService.processTx(txp);
|
|
|
|
|
scope.color = txp.color;
|
|
|
|
|
scope.cb = cb;
|
|
|
|
|
|
|
|
|
|
$ionicModal.fromTemplateUrl('views/modals/tx-status.html', {
|
|
|
|
|
scope: scope,
|
|
|
|
|
animation: 'slide-in-up'
|
|
|
|
|
}).then(function(modal) {
|
|
|
|
|
scope.txStatusModal = modal;
|
|
|
|
|
scope.txStatusModal.show();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
var _signWithLedger = function(wallet, txp, cb) {
|
2016-05-09 15:56:44 -03:00
|
|
|
$log.info('Requesting Ledger Chrome app to sign the transaction');
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
ledger.signTx(txp, wallet.credentials.account, function(result) {
|
2016-05-09 15:56:44 -03:00
|
|
|
$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);
|
|
|
|
|
});
|
2016-08-15 10:25:43 -03:00
|
|
|
return wallet.signTxProposal(txp, cb);
|
2016-05-09 15:56:44 -03:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
var _signWithTrezor = function(wallet, txp, cb) {
|
2016-05-09 15:56:44 -03:00
|
|
|
$log.info('Requesting Trezor to sign the transaction');
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
var xPubKeys = lodash.pluck(wallet.credentials.publicKeyRing, 'xPubKey');
|
|
|
|
|
trezor.signTx(xPubKeys, txp, wallet.credentials.account, function(err, result) {
|
2016-05-09 15:56:44 -03:00
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
$log.debug('Trezor response', result);
|
|
|
|
|
txp.signatures = result.signatures;
|
2016-08-15 10:25:43 -03:00
|
|
|
return wallet.signTxProposal(txp, cb);
|
2016-05-09 15:56:44 -03:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 16:07:30 -03:00
|
|
|
root.requiresBackup = function(wallet) {
|
2016-08-15 10:25:43 -03:00
|
|
|
if (wallet.isPrivKeyExternal()) return false;
|
|
|
|
|
if (!wallet.credentials.mnemonic) return false;
|
|
|
|
|
if (wallet.credentials.network == 'testnet') return false;
|
2016-05-09 15:56:44 -03:00
|
|
|
|
2016-06-06 18:26:45 -03:00
|
|
|
return true;
|
2016-05-09 15:56:44 -03:00
|
|
|
};
|
|
|
|
|
|
2016-08-15 16:07:30 -03:00
|
|
|
root.needsBackup = function(wallet, cb) {
|
|
|
|
|
|
2016-08-17 15:53:17 -03:00
|
|
|
if (!root.requiresBackup(wallet))
|
2016-08-15 16:07:30 -03:00
|
|
|
return cb(false);
|
|
|
|
|
|
|
|
|
|
storageService.getBackupFlag(wallet.credentials.walletId, function(err, val) {
|
|
|
|
|
if (err) $log.error(err);
|
|
|
|
|
if (val) return cb(false);
|
|
|
|
|
return cb(true);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-12 11:10:26 -03:00
|
|
|
var _walletStatusHash = function(walletStatus) {
|
|
|
|
|
var bal;
|
|
|
|
|
if (walletStatus) {
|
|
|
|
|
bal = walletStatus.balance.totalAmount;
|
|
|
|
|
} else {
|
|
|
|
|
bal = self.totalBalanceSat;
|
|
|
|
|
}
|
|
|
|
|
return bal;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// This handles errors from BWS/index which normally
|
|
|
|
|
// trigger from async events (like updates).
|
|
|
|
|
// Debounce function avoids multiple popups
|
|
|
|
|
var _handleError = function(err) {
|
2016-08-15 10:25:43 -03:00
|
|
|
$log.warn('wallet ERROR: ', err);
|
2016-08-12 11:10:26 -03:00
|
|
|
|
|
|
|
|
$log.warn('TODO');
|
2016-08-15 10:25:43 -03:00
|
|
|
return; // TODO!!!
|
2016-08-12 11:10:26 -03:00
|
|
|
if (err instanceof errors.NOT_AUTHORIZED) {
|
2016-08-15 16:07:30 -03:00
|
|
|
|
2016-08-17 15:53:17 -03:00
|
|
|
console.log('[walletService.js.93] TODO NOT AUTH'); //TODO
|
|
|
|
|
// TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
|
2016-08-12 11:10:26 -03:00
|
|
|
self.notAuthorized = true;
|
|
|
|
|
go.walletHome();
|
|
|
|
|
} else if (err instanceof errors.NOT_FOUND) {
|
2016-08-18 10:08:23 -03:00
|
|
|
root.showErrorPopup(gettext('Could not access Wallet Service: Not found'));
|
2016-08-12 11:10:26 -03:00
|
|
|
} else {
|
|
|
|
|
var msg = ""
|
2016-08-18 10:08:23 -03:00
|
|
|
$rootScope.$emit('Local/ClientError', (err.error ? err.error : err));
|
2016-08-12 11:10:26 -03:00
|
|
|
var msg = bwcError.msg(err, gettext('Error at Wallet Service'));
|
2016-08-18 10:08:23 -03:00
|
|
|
root.showErrorPopup(msg);
|
2016-08-12 11:10:26 -03:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
root.handleError = lodash.debounce(_handleError, 1000);
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
|
|
|
|
|
root.setBalance = function(wallet, balance) {
|
|
|
|
|
if (!balance) return;
|
|
|
|
|
|
|
|
|
|
var config = configService.getSync().wallet.settings;
|
|
|
|
|
var COIN = 1e8;
|
|
|
|
|
|
|
|
|
|
// Address with Balance
|
|
|
|
|
wallet.balanceByAddress = balance.byAddress;
|
|
|
|
|
|
|
|
|
|
// Spend unconfirmed funds
|
|
|
|
|
if (wallet.spendUnconfirmed) {
|
|
|
|
|
wallet.totalBalanceSat = balance.totalAmount;
|
|
|
|
|
wallet.lockedBalanceSat = balance.lockedAmount;
|
|
|
|
|
wallet.availableBalanceSat = balance.availableAmount;
|
|
|
|
|
wallet.totalBytesToSendMax = balance.totalBytesToSendMax;
|
|
|
|
|
wallet.pendingAmount = null;
|
|
|
|
|
} else {
|
|
|
|
|
wallet.totalBalanceSat = balance.totalConfirmedAmount;
|
|
|
|
|
wallet.lockedBalanceSat = balance.lockedConfirmedAmount;
|
|
|
|
|
wallet.availableBalanceSat = balance.availableConfirmedAmount;
|
|
|
|
|
wallet.totalBytesToSendMax = balance.totalBytesToSendConfirmedMax;
|
|
|
|
|
wallet.pendingAmount = balance.totalAmount - balance.totalConfirmedAmount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Selected unit
|
|
|
|
|
wallet.unitToSatoshi = config.unitToSatoshi;
|
|
|
|
|
wallet.satToUnit = 1 / wallet.unitToSatoshi;
|
|
|
|
|
wallet.unitName = config.unitName;
|
|
|
|
|
|
|
|
|
|
//STR
|
2016-08-18 11:45:30 -03:00
|
|
|
wallet.totalBalanceStr = txFormatService.formatAmount(wallet.totalBalanceSat) + ' ' + wallet.unitName;
|
|
|
|
|
wallet.lockedBalanceStr = txFormatService.formatAmount(wallet.lockedBalanceSat) + ' ' + wallet.unitName;
|
|
|
|
|
wallet.availableBalanceStr = txFormatService.formatAmount(wallet.availableBalanceSat) + ' ' + wallet.unitName;
|
2016-08-15 10:25:43 -03:00
|
|
|
|
|
|
|
|
if (wallet.pendingAmount) {
|
2016-08-18 11:45:30 -03:00
|
|
|
wallet.pendingAmountStr = txFormatService.formatAmount(wallet.pendingAmount) + ' ' + wallet.unitName;
|
2016-08-15 10:25:43 -03:00
|
|
|
} else {
|
|
|
|
|
wallet.pendingAmountStr = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wallet.alternativeName = config.alternativeName;
|
|
|
|
|
wallet.alternativeIsoCode = config.alternativeIsoCode;
|
|
|
|
|
|
|
|
|
|
rateService.whenAvailable(function() {
|
|
|
|
|
|
|
|
|
|
var totalBalanceAlternative = rateService.toFiat(wallet.totalBalanceSat, wallet.alternativeIsoCode);
|
|
|
|
|
var lockedBalanceAlternative = rateService.toFiat(wallet.lockedBalanceSat, wallet.alternativeIsoCode);
|
|
|
|
|
var alternativeConversionRate = rateService.toFiat(100000000, wallet.alternativeIsoCode);
|
|
|
|
|
|
|
|
|
|
wallet.totalBalanceAlternative = $filter('formatFiatAmount')(totalBalanceAlternative);
|
|
|
|
|
wallet.lockedBalanceAlternative = $filter('formatFiatAmount')(lockedBalanceAlternative);
|
|
|
|
|
wallet.alternativeConversionRate = $filter('formatFiatAmount')(alternativeConversionRate);
|
|
|
|
|
|
|
|
|
|
wallet.alternativeBalanceAvailable = true;
|
|
|
|
|
wallet.isRateAvailable = true;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.setStatus = function(wallet, status) {
|
|
|
|
|
wallet.status = status;
|
|
|
|
|
wallet.statusUpdatedOn = Date.now();
|
|
|
|
|
wallet.isValid = true;
|
|
|
|
|
root.setBalance(wallet, status.balance);
|
2016-08-17 15:53:17 -03:00
|
|
|
wallet.email = status.preferences.email;
|
2016-08-18 10:08:23 -03:00
|
|
|
wallet.copayers = status.wallet.copayers;
|
2016-08-15 10:25:43 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.updateStatus = function(wallet, opts, cb, initStatusHash, tries) {
|
2016-08-12 11:10:26 -03:00
|
|
|
tries = tries || 0;
|
|
|
|
|
opts = opts || {};
|
|
|
|
|
|
2016-08-17 15:53:17 -03:00
|
|
|
if (wallet.isValid && !opts.force)
|
2016-08-15 10:25:43 -03:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var walletId = wallet.id;
|
2016-08-12 11:10:26 -03:00
|
|
|
|
|
|
|
|
if (opts.untilItChanges && lodash.isUndefined(initStatusHash)) {
|
|
|
|
|
initStatusHash = _walletStatusHash();
|
|
|
|
|
$log.debug('Updating status until it changes. initStatusHash:' + initStatusHash)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var get = function(cb) {
|
|
|
|
|
if (opts.walletStatus)
|
|
|
|
|
return cb(null, opts.walletStatus);
|
|
|
|
|
else {
|
2016-08-15 10:25:43 -03:00
|
|
|
return wallet.getStatus({
|
2016-08-12 11:10:26 -03:00
|
|
|
twoStep: true
|
|
|
|
|
}, function(err, ret) {
|
|
|
|
|
if (err)
|
|
|
|
|
return cb(bwcError.msg(err, gettext('Could not update Wallet')));
|
|
|
|
|
// TODO??
|
|
|
|
|
// self.isSingleAddress = !!ret.wallet.singleAddress;
|
|
|
|
|
// self.updating = ret.wallet.scanStatus == 'running';
|
2016-08-15 10:25:43 -03:00
|
|
|
return cb(null, ret);
|
2016-08-12 11:10:26 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// If not untilItChanges...trigger history update now
|
|
|
|
|
if (opts.triggerTxUpdate && !opts.untilItChanges) {
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
root.debounceUpdateHistory();
|
|
|
|
|
}, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
|
|
|
|
|
// if (!opts.quiet)
|
2016-08-15 10:25:43 -03:00
|
|
|
// self.updating = true;
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
$log.debug('Updating Status:', wallet.credentials.walletName, tries);
|
2016-08-12 11:10:26 -03:00
|
|
|
get(function(err, walletStatus) {
|
|
|
|
|
var currentStatusHash = _walletStatusHash(walletStatus);
|
|
|
|
|
$log.debug('Status update. hash:' + currentStatusHash + ' Try:' + tries);
|
|
|
|
|
if (!err && opts.untilItChanges && initStatusHash == currentStatusHash && tries < 7 && walletId == profileService.focusedClient.credentials.walletId) {
|
|
|
|
|
return $timeout(function() {
|
|
|
|
|
$log.debug('Retrying update... ' + walletId + ' Try:' + tries)
|
2016-08-15 10:25:43 -03:00
|
|
|
return root.updateStatus(wallet, {
|
2016-08-12 11:10:26 -03:00
|
|
|
walletStatus: null,
|
|
|
|
|
untilItChanges: true,
|
|
|
|
|
triggerTxUpdate: opts.triggerTxUpdate,
|
|
|
|
|
}, cb, initStatusHash, ++tries);
|
|
|
|
|
}, 1400 * tries);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
|
root.handleError(err);
|
|
|
|
|
return cb(err);
|
|
|
|
|
}
|
2016-08-15 10:25:43 -03:00
|
|
|
$log.debug('Got Wallet Status for:' + wallet.credentials.walletName);
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.setStatus(wallet, walletStatus);
|
2016-08-12 11:10:26 -03:00
|
|
|
|
|
|
|
|
// self.setPendingTxps(walletStatus.pendingTxps);
|
|
|
|
|
//
|
|
|
|
|
// // Status Shortcuts
|
|
|
|
|
// self.lastUpdate = Date.now();
|
|
|
|
|
// self.walletName = walletStatus.wallet.name;
|
|
|
|
|
// self.walletSecret = walletStatus.wallet.secret;
|
|
|
|
|
// self.walletStatus = walletStatus.wallet.status;
|
|
|
|
|
// self.walletScanStatus = walletStatus.wallet.scanStatus;
|
|
|
|
|
// self.copayers = walletStatus.wallet.copayers;
|
|
|
|
|
// self.preferences = walletStatus.preferences;
|
|
|
|
|
// self.setBalance(walletStatus.balance);
|
|
|
|
|
// self.otherWallets = lodash.filter(profileService.getWallets(self.network), function(w) {
|
|
|
|
|
// return w.id != self.walletId;
|
|
|
|
|
// });
|
|
|
|
|
//
|
|
|
|
|
// Notify external addons or plugins
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
if (opts.triggerTxUpdate && opts.untilItChanges) {
|
2016-08-15 10:25:43 -03:00
|
|
|
$timeout(function() {
|
|
|
|
|
root.debounceUpdateHistory();
|
|
|
|
|
}, 1);
|
2016-08-12 11:10:26 -03:00
|
|
|
}
|
2016-08-15 10:25:43 -03:00
|
|
|
return cb();
|
2016-08-12 11:10:26 -03:00
|
|
|
// } else {
|
|
|
|
|
// self.loadingWallet = false;
|
|
|
|
|
// }
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var getSavedTxs = function(walletId, cb) {
|
|
|
|
|
|
|
|
|
|
storageService.getTxHistory(walletId, function(err, txs) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
var localTxs = [];
|
|
|
|
|
|
|
|
|
|
if (!txs) {
|
|
|
|
|
return cb(null, localTxs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
localTxs = JSON.parse(txs);
|
|
|
|
|
} catch (ex) {
|
|
|
|
|
$log.warn(ex);
|
|
|
|
|
}
|
|
|
|
|
return cb(null, lodash.compact(localTxs));
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
var getTxsFromServer = function(wallet, skip, endingTxid, limit, cb) {
|
2016-08-12 11:10:26 -03:00
|
|
|
var res = [];
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.getTxHistory({
|
2016-08-12 11:10:26 -03:00
|
|
|
skip: skip,
|
|
|
|
|
limit: limit
|
|
|
|
|
}, function(err, txsFromServer) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
if (!txsFromServer.length)
|
|
|
|
|
return cb();
|
|
|
|
|
|
|
|
|
|
var res = lodash.takeWhile(txsFromServer, function(tx) {
|
|
|
|
|
return tx.txid != endingTxid;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return cb(null, res, res.length == limit);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
var updateLocalTxHistory = function(wallet, cb) {
|
2016-08-12 11:10:26 -03:00
|
|
|
var FIRST_LIMIT = 5;
|
|
|
|
|
var LIMIT = 50;
|
|
|
|
|
var requestLimit = FIRST_LIMIT;
|
2016-08-15 10:25:43 -03:00
|
|
|
var walletId = wallet.credentials.walletId;
|
2016-08-12 11:10:26 -03:00
|
|
|
var config = configService.getSync().wallet.settings;
|
|
|
|
|
|
|
|
|
|
var fixTxsUnit = function(txs) {
|
|
|
|
|
if (!txs || !txs[0] || !txs[0].amountStr) return;
|
|
|
|
|
|
|
|
|
|
var cacheUnit = txs[0].amountStr.split(' ')[1];
|
|
|
|
|
|
|
|
|
|
if (cacheUnit == config.unitName)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var name = ' ' + config.unitName;
|
|
|
|
|
|
|
|
|
|
$log.debug('Fixing Tx Cache Unit to:' + name)
|
|
|
|
|
lodash.each(txs, function(tx) {
|
|
|
|
|
|
2016-08-18 11:45:30 -03:00
|
|
|
tx.amountStr = txFormatService.formatAmount(tx.amount) + name;
|
|
|
|
|
tx.feeStr = txFormatService.formatAmount(tx.fees) + name;
|
2016-08-12 11:10:26 -03:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
getSavedTxs(walletId, function(err, txsFromLocal) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
fixTxsUnit(txsFromLocal);
|
|
|
|
|
|
|
|
|
|
var confirmedTxs = self.removeAndMarkSoftConfirmedTx(txsFromLocal);
|
|
|
|
|
var endingTxid = confirmedTxs[0] ? confirmedTxs[0].txid : null;
|
|
|
|
|
var endingTs = confirmedTxs[0] ? confirmedTxs[0].time : null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// First update
|
|
|
|
|
if (walletId == profileService.focusedClient.credentials.walletId) {
|
|
|
|
|
self.completeHistory = txsFromLocal;
|
|
|
|
|
setCompactTxHistory();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (historyUpdateInProgress[walletId])
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
historyUpdateInProgress[walletId] = true;
|
|
|
|
|
|
|
|
|
|
function getNewTxs(newTxs, skip, i_cb) {
|
2016-08-15 10:25:43 -03:00
|
|
|
getTxsFromServer(wallet, skip, endingTxid, requestLimit, function(err, res, shouldContinue) {
|
2016-08-12 11:10:26 -03:00
|
|
|
if (err) return i_cb(err);
|
|
|
|
|
|
|
|
|
|
newTxs = newTxs.concat(lodash.compact(res));
|
|
|
|
|
skip = skip + requestLimit;
|
|
|
|
|
|
|
|
|
|
$log.debug('Syncing TXs. Got:' + newTxs.length + ' Skip:' + skip, ' EndingTxid:', endingTxid, ' Continue:', shouldContinue);
|
|
|
|
|
|
|
|
|
|
if (!shouldContinue) {
|
|
|
|
|
newTxs = self.processNewTxs(newTxs);
|
|
|
|
|
$log.debug('Finished Sync: New / soft confirmed Txs: ' + newTxs.length);
|
|
|
|
|
return i_cb(null, newTxs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestLimit = LIMIT;
|
|
|
|
|
getNewTxs(newTxs, skip, i_cb);
|
|
|
|
|
|
|
|
|
|
// Progress update
|
|
|
|
|
if (walletId == profileService.focusedClient.credentials.walletId) {
|
|
|
|
|
self.txProgress = newTxs.length;
|
|
|
|
|
if (self.completeHistory < FIRST_LIMIT && txsFromLocal.length == 0) {
|
|
|
|
|
$log.debug('Showing partial history');
|
|
|
|
|
var newHistory = self.processNewTxs(newTxs);
|
|
|
|
|
newHistory = lodash.compact(newHistory.concat(confirmedTxs));
|
|
|
|
|
self.completeHistory = newHistory;
|
|
|
|
|
setCompactTxHistory();
|
|
|
|
|
}
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
getNewTxs([], 0, function(err, txs) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
var newHistory = lodash.uniq(lodash.compact(txs.concat(confirmedTxs)), function(x) {
|
|
|
|
|
return x.txid;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function updateNotes(cb2) {
|
|
|
|
|
if (!endingTs) return cb2();
|
|
|
|
|
|
|
|
|
|
$log.debug('Syncing notes from: ' + endingTs);
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.getTxNotes({
|
2016-08-12 11:10:26 -03:00
|
|
|
minTs: endingTs
|
|
|
|
|
}, function(err, notes) {
|
|
|
|
|
if (err) {
|
|
|
|
|
$log.warn(err);
|
|
|
|
|
return cb2();
|
|
|
|
|
};
|
|
|
|
|
lodash.each(notes, function(note) {
|
|
|
|
|
$log.debug('Note for ' + note.txid);
|
|
|
|
|
lodash.each(newHistory, function(tx) {
|
|
|
|
|
if (tx.txid == note.txid) {
|
|
|
|
|
$log.debug('...updating note for ' + note.txid);
|
|
|
|
|
tx.note = note;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return cb2();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateNotes(function() {
|
|
|
|
|
var historyToSave = JSON.stringify(newHistory);
|
|
|
|
|
|
|
|
|
|
lodash.each(txs, function(tx) {
|
|
|
|
|
tx.recent = true;
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
$log.debug('Tx History synced. Total Txs: ' + newHistory.length);
|
|
|
|
|
|
|
|
|
|
// Final update
|
|
|
|
|
if (walletId == profileService.focusedClient.credentials.walletId) {
|
|
|
|
|
self.completeHistory = newHistory;
|
|
|
|
|
setCompactTxHistory();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return storageService.setTxHistory(historyToSave, walletId, function() {
|
|
|
|
|
$log.debug('Tx History saved.');
|
|
|
|
|
|
|
|
|
|
return cb();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.updateHistory = function(wallet) {
|
|
|
|
|
var walletId = wallet.credentials.walletId;
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
if (!wallet.isComplete()) return;
|
2016-08-12 11:10:26 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
$log.debug('Updating Transaction History');
|
|
|
|
|
self.txHistoryError = false;
|
|
|
|
|
self.updatingTxHistory = true;
|
|
|
|
|
|
|
|
|
|
$timeout(function() {
|
2016-08-15 10:25:43 -03:00
|
|
|
updateLocalTxHistory(wallet, function(err) {
|
2016-08-12 11:10:26 -03:00
|
|
|
historyUpdateInProgress[walletId] = self.updatingTxHistory = false;
|
|
|
|
|
self.loadingWallet = false;
|
|
|
|
|
self.txProgress = 0;
|
|
|
|
|
if (err)
|
|
|
|
|
self.txHistoryError = true;
|
|
|
|
|
|
|
|
|
|
$timeout(function() {
|
|
|
|
|
self.newTx = false
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-09 15:56:44 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.isEncrypted = function(wallet) {
|
|
|
|
|
if (lodash.isEmpty(wallet)) return;
|
|
|
|
|
var isEncrypted = wallet.isPrivKeyEncrypted();
|
2016-05-09 15:56:44 -03:00
|
|
|
if (isEncrypted) $log.debug('Wallet is encrypted');
|
|
|
|
|
return isEncrypted;
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.lock = function(wallet) {
|
2016-05-09 15:56:44 -03:00
|
|
|
try {
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.lock();
|
2016-05-09 15:56:44 -03:00
|
|
|
} catch (e) {
|
|
|
|
|
$log.warn('Encrypting wallet:', e);
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.unlock = function(wallet, password) {
|
|
|
|
|
if (lodash.isEmpty(wallet))
|
2016-05-09 15:56:44 -03:00
|
|
|
return 'MISSING_PARAMETER';
|
|
|
|
|
if (lodash.isEmpty(password))
|
|
|
|
|
return 'NO_PASSWORD_GIVEN';
|
|
|
|
|
try {
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.unlock(password);
|
2016-05-09 15:56:44 -03:00
|
|
|
} catch (e) {
|
|
|
|
|
$log.warn('Decrypting wallet:', e);
|
|
|
|
|
return 'PASSWORD_INCORRECT';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.createTx = function(wallet, txp, cb) {
|
|
|
|
|
if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
|
2016-05-09 15:56:44 -03:00
|
|
|
return cb('MISSING_PARAMETER');
|
|
|
|
|
|
|
|
|
|
if (txp.sendMax) {
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.createTxProposal(txp, function(err, createdTxp) {
|
2016-05-09 15:56:44 -03:00
|
|
|
if (err) return cb(err);
|
|
|
|
|
else return cb(null, createdTxp);
|
|
|
|
|
});
|
|
|
|
|
} else {
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.getFeeLevels(wallet.credentials.network, function(err, levels) {
|
2016-05-09 15:56:44 -03:00
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
var feeLevelValue = lodash.find(levels, {
|
|
|
|
|
level: txp.feeLevel
|
|
|
|
|
});
|
2016-06-06 18:26:45 -03:00
|
|
|
|
2016-05-09 15:56:44 -03:00
|
|
|
if (!feeLevelValue || !feeLevelValue.feePerKB)
|
|
|
|
|
return cb({
|
|
|
|
|
message: 'Could not get dynamic fee for level: ' + feeLevel
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$log.debug('Dynamic fee: ' + txp.feeLevel + ' ' + feeLevelValue.feePerKB + ' SAT');
|
|
|
|
|
|
|
|
|
|
txp.feePerKb = feeLevelValue.feePerKB;
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.createTxProposal(txp, function(err, createdTxp) {
|
2016-05-09 15:56:44 -03:00
|
|
|
if (err) return cb(err);
|
|
|
|
|
else {
|
|
|
|
|
$log.debug('Transaction created');
|
|
|
|
|
return cb(null, createdTxp);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.publishTx = function(wallet, txp, cb) {
|
|
|
|
|
if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
|
2016-05-09 15:56:44 -03:00
|
|
|
return cb('MISSING_PARAMETER');
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.publishTxProposal({
|
2016-06-06 18:26:45 -03:00
|
|
|
txp: txp
|
|
|
|
|
}, function(err, publishedTx) {
|
2016-05-09 15:56:44 -03:00
|
|
|
if (err) return cb(err);
|
|
|
|
|
else {
|
|
|
|
|
$log.debug('Transaction published');
|
|
|
|
|
return cb(null, publishedTx);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.signTx = function(wallet, txp, cb) {
|
|
|
|
|
if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
|
2016-05-09 15:56:44 -03:00
|
|
|
return cb('MISSING_PARAMETER');
|
2016-06-06 18:26:45 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
if (wallet.isPrivKeyExternal()) {
|
|
|
|
|
switch (wallet.getPrivKeyExternalSourceName()) {
|
2016-05-09 15:56:44 -03:00
|
|
|
case 'ledger':
|
2016-08-15 10:25:43 -03:00
|
|
|
return _signWithLedger(wallet, txp, cb);
|
2016-05-09 15:56:44 -03:00
|
|
|
case 'trezor':
|
2016-08-15 10:25:43 -03:00
|
|
|
return _signWithTrezor(wallet, txp, cb);
|
2016-05-09 15:56:44 -03:00
|
|
|
default:
|
2016-08-15 10:25:43 -03:00
|
|
|
var msg = 'Unsupported External Key:' + wallet.getPrivKeyExternalSourceName();
|
2016-05-09 15:56:44 -03:00
|
|
|
$log.error(msg);
|
|
|
|
|
return cb(msg);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
try {
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.signTxProposal(txp, function(err, signedTxp) {
|
2016-05-09 15:56:44 -03:00
|
|
|
$log.debug('Transaction signed');
|
|
|
|
|
return cb(err, signedTxp);
|
|
|
|
|
});
|
|
|
|
|
} catch (e) {
|
|
|
|
|
$log.warn('Error at signTxProposal:', e);
|
|
|
|
|
return cb(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.broadcastTx = function(wallet, txp, cb) {
|
|
|
|
|
if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
|
2016-05-09 15:56:44 -03:00
|
|
|
return cb('MISSING_PARAMETER');
|
2016-06-06 18:26:45 -03:00
|
|
|
|
2016-05-09 15:56:44 -03:00
|
|
|
if (txp.status != 'accepted')
|
|
|
|
|
return cb('TX_NOT_ACCEPTED');
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.broadcastTxProposal(txp, function(err, broadcastedTxp, memo) {
|
2016-06-06 18:26:45 -03:00
|
|
|
if (err)
|
2016-05-09 15:56:44 -03:00
|
|
|
return cb(err);
|
|
|
|
|
|
|
|
|
|
$log.debug('Transaction broadcasted');
|
|
|
|
|
if (memo) $log.info(memo);
|
|
|
|
|
|
|
|
|
|
return cb(null, broadcastedTxp);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.rejectTx = function(wallet, txp, cb) {
|
|
|
|
|
if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
|
2016-05-09 15:56:44 -03:00
|
|
|
return cb('MISSING_PARAMETER');
|
2016-06-06 18:26:45 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.rejectTxProposal(txp, null, function(err, rejectedTxp) {
|
2016-05-09 15:56:44 -03:00
|
|
|
$log.debug('Transaction rejected');
|
|
|
|
|
return cb(err, rejectedTxp);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.removeTx = function(wallet, txp, cb) {
|
|
|
|
|
if (lodash.isEmpty(txp) || lodash.isEmpty(wallet))
|
2016-05-09 15:56:44 -03:00
|
|
|
return cb('MISSING_PARAMETER');
|
2016-06-06 18:26:45 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.removeTxProposal(txp, function(err) {
|
2016-05-09 15:56:44 -03:00
|
|
|
$log.debug('Transaction removed');
|
|
|
|
|
return cb(err);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-06-06 18:26:45 -03:00
|
|
|
root.updateRemotePreferences = function(clients, prefs, cb) {
|
|
|
|
|
prefs = prefs || {};
|
|
|
|
|
|
|
|
|
|
if (!lodash.isArray(clients))
|
|
|
|
|
clients = [clients];
|
|
|
|
|
|
|
|
|
|
function updateRemotePreferencesFor(clients, prefs, cb) {
|
2016-08-15 10:25:43 -03:00
|
|
|
var wallet = clients.shift();
|
|
|
|
|
if (!wallet) return cb();
|
|
|
|
|
$log.debug('Saving remote preferences', wallet.credentials.walletName, prefs);
|
2016-06-06 18:26:45 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.savePreferences(prefs, function(err) {
|
2016-06-06 18:26:45 -03:00
|
|
|
// we ignore errors here
|
|
|
|
|
if (err) $log.warn(err);
|
|
|
|
|
|
|
|
|
|
updateRemotePreferencesFor(clients, prefs, cb);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Update this JIC.
|
|
|
|
|
var config = configService.getSync().wallet.settings;
|
|
|
|
|
|
|
|
|
|
//prefs.email (may come from arguments)
|
2016-06-07 10:37:39 -03:00
|
|
|
prefs.language = uxLanguage.getCurrentLanguage();
|
2016-06-06 18:26:45 -03:00
|
|
|
prefs.unit = config.unitCode;
|
|
|
|
|
|
|
|
|
|
updateRemotePreferencesFor(clients, prefs, function(err) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
lodash.each(clients, function(c) {
|
|
|
|
|
c.preferences = lodash.assign(prefs, c.preferences);
|
|
|
|
|
});
|
|
|
|
|
return cb();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-12 11:10:26 -03:00
|
|
|
var setCompactTxHistory = function() {
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
self.isSearching = false;
|
|
|
|
|
self.nextTxHistory = self.historyShowMoreLimit;
|
|
|
|
|
self.txHistory = self.completeHistory ? self.completeHistory.slice(0, self.historyShowLimit) : null;
|
|
|
|
|
self.historyShowMore = self.completeHistory ? self.completeHistory.length > self.historyShowLimit : null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.debounceUpdateHistory = lodash.debounce(function() {
|
|
|
|
|
root.updateHistory();
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
|
|
self.throttledUpdateHistory = lodash.throttle(function() {
|
|
|
|
|
root.updateHistory();
|
|
|
|
|
}, 5000);
|
|
|
|
|
|
2016-08-18 10:08:23 -03:00
|
|
|
root.showErrorPopup = function(msg, cb) {
|
2016-08-12 11:10:26 -03:00
|
|
|
$log.warn('Showing err popup:' + msg);
|
|
|
|
|
|
2016-08-18 10:08:23 -03:00
|
|
|
// An alert dialog
|
|
|
|
|
var alertPopup = $ionicPopup.alert({
|
|
|
|
|
title: title,
|
|
|
|
|
template: msg
|
|
|
|
|
});
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-18 10:08:23 -03:00
|
|
|
if (!cb) cb = function() {};
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-18 10:08:23 -03:00
|
|
|
alertPopup.then(cb);
|
2016-08-12 11:10:26 -03:00
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.recreate = function(wallet, cb) {
|
2016-08-12 11:10:26 -03:00
|
|
|
ongoingProcess.set('recreating', true);
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.recreateWallet(function(err) {
|
2016-08-12 11:10:26 -03:00
|
|
|
self.notAuthorized = false;
|
|
|
|
|
ongoingProcess.set('recreating', false);
|
|
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
|
self.handleError(err);
|
|
|
|
|
$rootScope.$apply();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
profileService.bindWalletClient(wallet, {
|
2016-08-12 11:10:26 -03:00
|
|
|
force: true
|
|
|
|
|
});
|
2016-08-15 10:25:43 -03:00
|
|
|
self.startScan(wallet);
|
2016-08-12 11:10:26 -03:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.startScan = function(wallet) {
|
|
|
|
|
$log.debug('Scanning wallet ' + wallet.credentials.walletId);
|
|
|
|
|
if (!wallet.isComplete()) return;
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
// self.updating = true;
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
wallet.startScan({
|
2016-08-12 11:10:26 -03:00
|
|
|
includeCopayerBranches: true,
|
|
|
|
|
}, function(err) {
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// if (err && self.walletId == walletId) {
|
|
|
|
|
// self.updating = false;
|
|
|
|
|
// self.handleError(err);
|
|
|
|
|
// $rootScope.$apply();
|
|
|
|
|
// }
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-08-15 10:25:43 -03:00
|
|
|
root.expireAddress = function(wallet, cb) {
|
|
|
|
|
$log.debug('Cleaning Address ' + wallet.id);
|
|
|
|
|
storageService.clearLastAddress(wallet.id, function(err) {
|
|
|
|
|
return cb(err);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.isUsed = function(wallet, byAddress, cb) {
|
|
|
|
|
storageService.getLastAddress(wallet.id, function(err, addr) {
|
|
|
|
|
var used = lodash.find(byAddress, {
|
|
|
|
|
address: addr
|
|
|
|
|
});
|
|
|
|
|
return cb(null, used);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-15 11:56:59 -03:00
|
|
|
var createAddress = function(wallet, cb) {
|
2016-08-15 10:25:43 -03:00
|
|
|
$log.debug('Creating address for wallet:', wallet.id);
|
|
|
|
|
|
|
|
|
|
wallet.createAddress({}, function(err, addr) {
|
|
|
|
|
if (err) {
|
|
|
|
|
var prefix = gettextCatalog.getString('Could not create address');
|
|
|
|
|
if (err.error && err.error.match(/locked/gi)) {
|
|
|
|
|
$log.debug(err.error);
|
|
|
|
|
return $timeout(function() {
|
2016-08-15 11:56:59 -03:00
|
|
|
createAddress(wallet, cb);
|
2016-08-15 10:25:43 -03:00
|
|
|
}, 5000);
|
|
|
|
|
} else if (err.message && err.message == 'MAIN_ADDRESS_GAP_REACHED') {
|
|
|
|
|
$log.warn(err.message);
|
|
|
|
|
prefix = null;
|
|
|
|
|
wallet.getMainAddresses({
|
|
|
|
|
reverse: true,
|
|
|
|
|
limit: 1
|
|
|
|
|
}, function(err, addr) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
return cb(null, addr[0].address);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return bwcError.cb(err, prefix, cb);
|
|
|
|
|
}
|
|
|
|
|
return cb(null, addr.address);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.getAddress = function(wallet, forceNew, cb) {
|
2016-08-17 15:53:17 -03:00
|
|
|
console.log('[walletService.js.786:wallet:]', wallet, forceNew); //TODO
|
2016-08-15 10:25:43 -03:00
|
|
|
|
|
|
|
|
var firstStep;
|
|
|
|
|
if (forceNew) {
|
|
|
|
|
firstStep = storageService.clearLastAddress;
|
|
|
|
|
} else {
|
|
|
|
|
firstStep = function(walletId, cb) {
|
|
|
|
|
return cb();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
firstStep(wallet.id, function(err) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
storageService.getLastAddress(wallet.id, function(err, addr) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
if (addr) return cb(null, addr);
|
|
|
|
|
|
2016-08-15 11:56:59 -03:00
|
|
|
createAddress(wallet, function(err, addr) {
|
2016-08-15 10:25:43 -03:00
|
|
|
if (err) return cb(err);
|
|
|
|
|
storageService.storeLastAddress(wallet.id, addr, function() {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
return cb(null, addr);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-12 11:10:26 -03:00
|
|
|
|
2016-08-15 16:07:30 -03:00
|
|
|
root.isReady = function(wallet, cb) {
|
|
|
|
|
if (!wallet.isComplete())
|
|
|
|
|
return cb('WALLET_NOT_COMPLETE');
|
|
|
|
|
|
|
|
|
|
root.needsBackup(wallet, function(needsBackup) {
|
|
|
|
|
if (needsBackup)
|
|
|
|
|
return cb('WALLET_NEEDS_BACKUP');
|
|
|
|
|
return cb();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-08-18 10:08:23 -03:00
|
|
|
// An alert dialog
|
|
|
|
|
var askPassword = function(name, cb) {
|
|
|
|
|
var scope = $rootScope.$new(true);
|
|
|
|
|
scope.data = [];
|
|
|
|
|
var pass = $ionicPopup.show({
|
|
|
|
|
template: '<input type="password" ng-model="data.pass">',
|
|
|
|
|
title: 'Enter Spending Password',
|
|
|
|
|
subTitle: name,
|
|
|
|
|
scope: scope,
|
|
|
|
|
buttons: [{
|
|
|
|
|
text: 'Cancel'
|
|
|
|
|
}, {
|
|
|
|
|
text: '<b>OK</b>',
|
|
|
|
|
type: 'button-positive',
|
|
|
|
|
onTap: function(e) {
|
|
|
|
|
if (!scope.data.pass) {
|
|
|
|
|
//don't allow the user to close unless he enters wifi password
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
return;
|
2016-08-15 16:07:30 -03:00
|
|
|
|
2016-08-18 10:08:23 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return scope.data.pass;
|
|
|
|
|
}
|
|
|
|
|
}]
|
|
|
|
|
});
|
|
|
|
|
pass.then(function(res) {
|
|
|
|
|
console.log('Tapped!', res);
|
|
|
|
|
return cb(res);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.handleEncryptedWallet = function(wallet, cb) {
|
|
|
|
|
if (!root.isEncrypted(wallet)) return cb();
|
|
|
|
|
|
|
|
|
|
askPassword(wallet.name, function(password) {
|
|
|
|
|
if (!password) return cb('no password');
|
|
|
|
|
return cb(root.unlock(wallet, password));
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.onlyPublish = function(wallet, txp, cb) {
|
|
|
|
|
ongoingProcess.set('sendingTx', true);
|
|
|
|
|
root.publishTx(wallet, txp, function(err, publishedTxp) {
|
|
|
|
|
ongoingProcess.set('sendingTx', false);
|
2016-08-17 17:31:45 -03:00
|
|
|
if (err) return cb(err);
|
2016-08-18 10:08:23 -03:00
|
|
|
|
|
|
|
|
var type = txStatus.notify(createdTxp);
|
|
|
|
|
root.openStatusModal(type, createdTxp, function() {
|
|
|
|
|
// TODO?
|
|
|
|
|
//return $scope.$emit('Local/TxProposalAction');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return cb(null, publishedTxp);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
root.publishAndSign = function(wallet, txp, cb) {
|
|
|
|
|
|
|
|
|
|
var publishFn = root.publishTx;
|
|
|
|
|
|
|
|
|
|
// Already published?
|
|
|
|
|
if (txp.status == 'pending') {
|
|
|
|
|
publishFn = function(wallet, txp, cb) {
|
|
|
|
|
return cb(null, txp);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fingerprintService.check(wallet, function(err) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
root.handleEncryptedWallet(wallet, function(err) {
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
ongoingProcess.set('sendingTx', true);
|
|
|
|
|
publishFn(wallet, txp, function(err, publishedTxp) {
|
|
|
|
|
ongoingProcess.set('sendingTx', false);
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
ongoingProcess.set('signingTx', true);
|
|
|
|
|
root.signTx(wallet, txp, function(err, signedTxp) {
|
|
|
|
|
ongoingProcess.set('signingTx', false);
|
|
|
|
|
root.lock(wallet);
|
|
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
|
// TODO?
|
|
|
|
|
//$scope.$emit('Local/TxProposalAction');
|
|
|
|
|
var msg = err.message ?
|
|
|
|
|
err.message :
|
|
|
|
|
gettext('The payment was created but could not be completed. Please try again from home screen');
|
|
|
|
|
return cb(err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (signedTxp.status == 'accepted') {
|
|
|
|
|
ongoingProcess.set('broadcastingTx', true);
|
|
|
|
|
root.broadcastTx(wallet, signedTxp, function(err, broadcastedTxp) {
|
|
|
|
|
ongoingProcess.set('broadcastingTx', false);
|
|
|
|
|
if (err) return cb(err);
|
|
|
|
|
|
|
|
|
|
var type = txStatus.notify(broadcastedTxp);
|
|
|
|
|
root.openStatusModal(type, broadcastedTxp, function() {
|
|
|
|
|
// TODO?
|
|
|
|
|
//$scope.$emit('Local/TxProposalAction', broadcastedTxp.status == 'broadcasted');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return cb(null, broadcastedTxp)
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
var type = txStatus.notify(signedTxp);
|
|
|
|
|
root.openStatusModal(type, signedTxp, function() {
|
|
|
|
|
// TODO?
|
|
|
|
|
//$scope.$emit('Local/TxProposalAction');
|
|
|
|
|
});
|
|
|
|
|
return cb(null, signedTxp);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2016-08-17 17:31:45 -03:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-05-09 15:56:44 -03:00
|
|
|
return root;
|
|
|
|
|
});
|