Merge pull request #3742 from bitpay/v1.6

Updates master from v1.6
This commit is contained in:
Gustavo Maximiliano Cortez 2016-01-05 17:30:45 -03:00
commit 490fb4ae34
9 changed files with 164 additions and 119 deletions

View file

@ -99,7 +99,7 @@
</div> </div>
<div ng-hide="hideAdv" class="row"> <div ng-hide="hideAdv" class="row">
<div class="large-12 columns"> <div class="large-12 columns m20b">
<div> <div>
<label for="bws" class="oh"> <label for="bws" class="oh">
<span>Wallet Service URL</span> <span>Wallet Service URL</span>
@ -173,11 +173,11 @@
</div> <!-- columns --> </div> <!-- columns -->
</div> <!-- advanced --> </div> <!-- advanced -->
<button type="submit" class="button round black expand m0" ng-show="totalCopayers != 1" ng-disabled="setupForm.$invalid || create.loading || create.hwWallet"> <button type="submit" class="button round black expand" ng-show="totalCopayers != 1" ng-disabled="setupForm.$invalid || create.loading || create.hwWallet">
<span translate>Create {{requiredCopayers}}-of-{{totalCopayers}} wallet</span> <span translate>Create {{requiredCopayers}}-of-{{totalCopayers}} wallet</span>
</button> </button>
<button type="submit" class="button round black expand m0" ng-show="totalCopayers == 1" ng-disabled="setupForm.$invalid || create.loading || create.hwWallet"> <button type="submit" class="button round black expand" ng-show="totalCopayers == 1" ng-disabled="setupForm.$invalid || create.loading || create.hwWallet">
<span translate>Create new wallet</span> <span translate>Create new wallet</span>
</button> </button>

View file

@ -106,7 +106,7 @@
Please, enter the code below Please, enter the code below
</p> </p>
<form name="sellForm" <form name="sellForm"
ng-submit="sell.createTx(index.glideraToken, index.glideraPermissions, twoFaCode, index.feeRateToSendMax)" novalidate> ng-submit="sell.createTx(index.glideraToken, index.glideraPermissions, twoFaCode)" novalidate>
<input type="number" ng-model="twoFaCode" required> <input type="number" ng-model="twoFaCode" required>
<input class="button black expand round" <input class="button black expand round"
ng-style="{'background-color':index.backgroundColor}" ng-style="{'background-color':index.backgroundColor}"

View file

@ -387,8 +387,8 @@
<h4 class="title m0"> <h4 class="title m0">
<available-balance></available-balance> <available-balance></available-balance>
<a <a
ng-if="index.feeToSendMaxStr && index.availableBalanceSat > 0 && !home.blockUx && !home.lockAmount" ng-show="!home.lockedCurrentFeePerKb && index.feeToSendMaxStr && index.availableBalanceSat > 0 && !home.blockUx && !home.lockAmount"
ng-click="home.sendAll(index.availableMaxBalance, index.feeToSendMaxStr)" ng-click="home.sendAll()"
translate> Send All translate> Send All
</a> </a>
</h4> </h4>
@ -403,7 +403,7 @@
</div> </div>
<div class="row m20t"> <div class="row m20t">
<div class="large-12 large-centered columns"> <div class="large-12 large-centered columns">
<form name="sendForm" ng-submit="home.submitForm(index.feeRateToSendMax)" ng-disabled="home.blockUx || home.onGoingProcess" novalidate> <form name="sendForm" ng-submit="home.submitForm()" ng-disabled="home.blockUx || home.onGoingProcess" novalidate>
<div ng-hide="home._paypro || home.hideAddress"> <div ng-hide="home._paypro || home.hideAddress">
<div class="row collapse"> <div class="row collapse">

View file

@ -630,7 +630,7 @@ to prevent collapsing during animation*/
height: 100%; height: 100%;
width: 100%; width: 100%;
top: 45px; top: 45px;
padding-bottom: 33px; padding-bottom: 50px;
-webkit-transform: translate3d(0,0,0); -webkit-transform: translate3d(0,0,0);
background: #f6f7f9; background: #f6f7f9;
} }

View file

@ -371,14 +371,15 @@ angular.module('copayApp.controllers').controller('indexController', function($r
}); });
}; };
self.setSpendUnconfirmed = function() { self.setSpendUnconfirmed = function(spendUnconfirmed) {
self.spendUnconfirmed = configService.getSync().wallet.spendUnconfirmed; self.spendUnconfirmed = spendUnconfirmed || configService.getSync().wallet.spendUnconfirmed;
}; };
self.setSendMax = function() { self.setFeeAndSendMax = function(cb) {
self.feeToSendMaxStr = null; self.feeToSendMaxStr = null;
self.feeRateToSendMax = null; self.availableMaxBalance = null;
self.currentFeePerKb = null;
// Set Send max // Set Send max
if (self.currentFeeLevel && self.totalBytesToSendMax) { if (self.currentFeeLevel && self.totalBytesToSendMax) {
@ -386,12 +387,14 @@ angular.module('copayApp.controllers').controller('indexController', function($r
// KB to send max // KB to send max
var feeToSendMaxSat = parseInt(((self.totalBytesToSendMax * feePerKb) / 1000.).toFixed(0)); var feeToSendMaxSat = parseInt(((self.totalBytesToSendMax * feePerKb) / 1000.).toFixed(0));
self.feeRateToSendMax = feePerKb; self.currentFeePerKb = feePerKb;
if (self.availableBalanceSat > feeToSendMaxSat) { if (self.availableBalanceSat > feeToSendMaxSat) {
self.availableMaxBalance = strip((self.availableBalanceSat - feeToSendMaxSat) * self.satToUnit); self.availableMaxBalance = strip((self.availableBalanceSat - feeToSendMaxSat) * self.satToUnit);
self.feeToSendMaxStr = profileService.formatAmount(feeToSendMaxSat) + ' ' + self.unitName; self.feeToSendMaxStr = profileService.formatAmount(feeToSendMaxSat) + ' ' + self.unitName;
} }
if (cb) return cb(self.currentFeePerKb, self.availableMaxBalance, self.feeToSendMaxStr);
}); });
} }
@ -399,7 +402,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.setCurrentFeeLevel = function(level) { self.setCurrentFeeLevel = function(level) {
self.currentFeeLevel = level || configService.getSync().wallet.settings.feeLevel || 'normal'; self.currentFeeLevel = level || configService.getSync().wallet.settings.feeLevel || 'normal';
self.setSendMax(); self.setFeeAndSendMax();
}; };
@ -501,6 +504,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
message: 'test multi-output', message: 'test multi-output',
fee: 1000, fee: 1000,
createdOn: new Date() / 1000, createdOn: new Date() / 1000,
type: 'multiple_output',
outputs: [] outputs: []
}; };
function addOutput(n) { function addOutput(n) {
@ -611,16 +615,18 @@ angular.module('copayApp.controllers').controller('indexController', function($r
// Address with Balance // Address with Balance
self.balanceByAddress = balance.byAddress; self.balanceByAddress = balance.byAddress;
// SAT // Spend unconfirmed funds
if (self.spendUnconfirmed) { if (self.spendUnconfirmed) {
self.totalBalanceSat = balance.totalAmount; self.totalBalanceSat = balance.totalAmount;
self.lockedBalanceSat = balance.lockedAmount; self.lockedBalanceSat = balance.lockedAmount;
self.availableBalanceSat = balance.availableAmount; self.availableBalanceSat = balance.availableAmount;
self.totalBytesToSendMax = balance.totalBytesToSendMax;
self.pendingAmount = null; self.pendingAmount = null;
} else { } else {
self.totalBalanceSat = balance.totalConfirmedAmount; self.totalBalanceSat = balance.totalConfirmedAmount;
self.lockedBalanceSat = balance.lockedConfirmedAmount; self.lockedBalanceSat = balance.lockedConfirmedAmount;
self.availableBalanceSat = balance.availableConfirmedAmount; self.availableBalanceSat = balance.availableConfirmedAmount;
self.totalBytesToSendMax = balance.totalBytesToSendConfirmedMax;
self.pendingAmount = balance.totalAmount - balance.totalConfirmedAmount; self.pendingAmount = balance.totalAmount - balance.totalConfirmedAmount;
} }
@ -643,8 +649,7 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.alternativeName = config.alternativeName; self.alternativeName = config.alternativeName;
self.alternativeIsoCode = config.alternativeIsoCode; self.alternativeIsoCode = config.alternativeIsoCode;
// Other // Set fee level and max value to send all
self.totalBytesToSendMax = balance.totalBytesToSendMax;
self.setCurrentFeeLevel(); self.setCurrentFeeLevel();
// Check address // Check address
@ -1185,8 +1190,8 @@ angular.module('copayApp.controllers').controller('indexController', function($r
}); });
}); });
$rootScope.$on('Local/SpendUnconfirmedUpdated', function(event) { $rootScope.$on('Local/SpendUnconfirmedUpdated', function(event, spendUnconfirmed) {
self.setSpendUnconfirmed(); self.setSpendUnconfirmed(spendUnconfirmed);
self.updateAll(); self.updateAll();
}); });
@ -1194,6 +1199,10 @@ angular.module('copayApp.controllers').controller('indexController', function($r
self.setCurrentFeeLevel(level); self.setCurrentFeeLevel(level);
}); });
$rootScope.$on('Local/SetFeeSendMax', function(event, cb) {
self.setFeeAndSendMax(cb);
});
$rootScope.$on('Local/ProfileBound', function() { $rootScope.$on('Local/ProfileBound', function() {
storageService.getRemotePrefsStoredFlag(function(err, val) { storageService.getRemotePrefsStoredFlag(function(err, val) {
if (err || val) return; if (err || val) return;
@ -1449,4 +1458,5 @@ angular.module('copayApp.controllers').controller('indexController', function($r
$rootScope.$apply(); $rootScope.$apply();
}); });
}); });
}); });

View file

@ -24,7 +24,7 @@ angular.module('copayApp.controllers').controller('preferencesGlobalController',
} }
}; };
configService.set(opts, function(err) { configService.set(opts, function(err) {
$rootScope.$emit('Local/SpendUnconfirmedUpdated'); $rootScope.$emit('Local/SpendUnconfirmedUpdated', newVal);
if (err) $log.debug(err); if (err) $log.debug(err);
}); });
}); });

View file

@ -1,7 +1,7 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('sellGlideraController', angular.module('copayApp.controllers').controller('sellGlideraController',
function($scope, $timeout, $log, $modal, configService, profileService, addressService, glideraService, bwsError, lodash, isChromeApp, animationService) { function($scope, $timeout, $log, $modal, configService, profileService, addressService, feeService, glideraService, bwsError, lodash, isChromeApp, animationService) {
var self = this; var self = this;
var config = configService.getSync(); var config = configService.getSync();
@ -11,6 +11,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
this.error = null; this.error = null;
this.loading = null; this.loading = null;
this.currentSpendUnconfirmed = config.wallet.spendUnconfirmed; this.currentSpendUnconfirmed = config.wallet.spendUnconfirmed;
this.currentFeeLevel = config.wallet.settings.feeLevel || 'normal';
var fc; var fc;
var otherWallets = function(testnet) { var otherWallets = function(testnet) {
@ -122,7 +123,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
}, 100); }, 100);
}; };
this.createTx = function(token, permissions, twoFaCode, currentFeePerKb) { this.createTx = function(token, permissions, twoFaCode) {
var self = this; var self = this;
self.error = null; self.error = null;
@ -142,62 +143,65 @@ angular.module('copayApp.controllers').controller('sellGlideraController',
} }
var amount = parseInt((self.sellPrice.qty * 100000000).toFixed(0)); var amount = parseInt((self.sellPrice.qty * 100000000).toFixed(0));
fc.sendTxProposal({ feeService.getCurrentFeeValue(self.currentFeeLevel, function(err, feePerKb) {
toAddress: sellAddress, if (err) $log.debug(err);
amount: amount, fc.sendTxProposal({
message: 'Glidera transaction', toAddress: sellAddress,
customData: {'glideraToken': token}, amount: amount,
payProUrl: null, message: 'Glidera transaction',
feePerKb: currentFeePerKb, customData: {'glideraToken': token},
excludeUnconfirmedUtxos: self.currentSpendUnconfirmed ? false : true payProUrl: null,
}, function(err, txp) { feePerKb: feePerKb,
if (err) { excludeUnconfirmedUtxos: self.currentSpendUnconfirmed ? false : true
profileService.lockFC(); }, function(err, txp) {
$log.error(err);
$timeout(function() {
self.loading = null;
self.error = bwsError.msg(err, 'Error');
}, 1);
return;
}
if (!fc.canSign()) {
self.loading = null;
$log.info('No signing proposal: No private key');
return;
}
_signTx(txp, function(err, txp, rawTx) {
profileService.lockFC();
if (err) { if (err) {
self.loading = null; profileService.lockFC();
self.error = err; $log.error(err);
$scope.$apply(); $timeout(function() {
}
else {
var data = {
refundAddress: refundAddress,
signedTransaction: rawTx,
priceUuid: self.sellPrice.priceUuid,
useCurrentPrice: self.sellPrice.priceUuid ? false : true,
ip: null
};
glideraService.sell(token, twoFaCode, data, function(err, data) {
self.loading = null; self.loading = null;
if (err) { self.error = bwsError.msg(err, 'Error');
self.error = err; }, 1);
fc.removeTxProposal(txp, function(err, txpb) { return;
$timeout(function() {
$scope.$emit('Local/GlideraError');
}, 100);
});
}
else {
self.success = data;
$scope.$emit('Local/GlideraTx');
}
});
} }
if (!fc.canSign()) {
self.loading = null;
$log.info('No signing proposal: No private key');
return;
}
_signTx(txp, function(err, txp, rawTx) {
profileService.lockFC();
if (err) {
self.loading = null;
self.error = err;
$scope.$apply();
}
else {
var data = {
refundAddress: refundAddress,
signedTransaction: rawTx,
priceUuid: self.sellPrice.priceUuid,
useCurrentPrice: self.sellPrice.priceUuid ? false : true,
ip: null
};
glideraService.sell(token, twoFaCode, data, function(err, data) {
self.loading = null;
if (err) {
self.error = err;
fc.removeTxProposal(txp, function(err, txpb) {
$timeout(function() {
$scope.$emit('Local/GlideraError');
}, 100);
});
}
else {
self.success = data;
$scope.$emit('Local/GlideraTx');
}
});
}
});
}); });
}); });
}); });

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $rootScope, $timeout, $filter, $modal, $log, notification, txStatus, isCordova, profileService, lodash, configService, rateService, storageService, bitcore, isChromeApp, gettext, gettextCatalog, nodeWebkit, addressService, ledger, bwsError, confirmDialog, txFormatService, animationService, addressbookService, go) { angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $rootScope, $timeout, $filter, $modal, $log, notification, txStatus, isCordova, profileService, lodash, configService, rateService, storageService, bitcore, isChromeApp, gettext, gettextCatalog, nodeWebkit, addressService, ledger, bwsError, confirmDialog, txFormatService, animationService, addressbookService, go, feeService) {
var self = this; var self = this;
$rootScope.hideMenuBar = false; $rootScope.hideMenuBar = false;
@ -26,6 +26,7 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
this.showScanner = false; this.showScanner = false;
this.isMobile = isMobile.any(); this.isMobile = isMobile.any();
this.addr = {}; this.addr = {};
this.lockedCurrentFeePerKb = null;
var disableScannerListener = $rootScope.$on('dataScanned', function(event, data) { var disableScannerListener = $rootScope.$on('dataScanned', function(event, data) {
self.setForm(data); self.setForm(data);
@ -826,10 +827,11 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
}; };
}; };
this.submitForm = function(currentFeePerKb) { this.submitForm = function() {
var fc = profileService.focusedClient; var fc = profileService.focusedClient;
var unitToSat = this.unitToSatoshi; var unitToSat = this.unitToSatoshi;
var currentSpendUnconfirmed = configWallet.spendUnconfirmed; var currentSpendUnconfirmed = configWallet.spendUnconfirmed;
var currentFeeLevel = walletSettings.feeLevel || 'normal';
if (isCordova && this.isWindowsPhoneApp) { if (isCordova && this.isWindowsPhoneApp) {
this.hideAddress = false; this.hideAddress = false;
@ -859,6 +861,14 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
return self.setSendError(gettext(msg)); return self.setSendError(gettext(msg));
} }
var getFee = function(cb) {
if (self.lockedCurrentFeePerKb) {
cb(null, self.lockedCurrentFeePerKb);
} else {
feeService.getCurrentFeeValue(currentFeeLevel, cb);
}
};
self.setOngoingProcess(gettext('Creating transaction')); self.setOngoingProcess(gettext('Creating transaction'));
$timeout(function() { $timeout(function() {
var paypro = self._paypro; var paypro = self._paypro;
@ -878,40 +888,43 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
return; return;
} }
fc.sendTxProposal({ getFee(function(err, feePerKb) {
toAddress: address, if (err) $log.debug(err);
amount: amount, fc.sendTxProposal({
message: comment, toAddress: address,
payProUrl: paypro ? paypro.url : null, amount: amount,
feePerKb: currentFeePerKb, message: comment,
excludeUnconfirmedUtxos: currentSpendUnconfirmed ? false : true payProUrl: paypro ? paypro.url : null,
}, function(err, txp) { feePerKb: feePerKb,
if (err) { excludeUnconfirmedUtxos: currentSpendUnconfirmed ? false : true
self.setOngoingProcess(); }, function(err, txp) {
profileService.lockFC();
return self.setSendError(err);
}
if (!fc.canSign() && !fc.isPrivKeyExternal()) {
$log.info('No signing proposal: No private key')
self.setOngoingProcess();
self.resetForm();
txStatus.notify(txp, function() {
return $scope.$emit('Local/TxProposalAction');
});
return;
}
self.signAndBroadcast(txp, function(err) {
self.setOngoingProcess();
self.resetForm();
if (err) { if (err) {
self.error = err.message ? err.message : gettext('The payment was created but could not be completed. Please try again from home screen'); self.setOngoingProcess();
$scope.$emit('Local/TxProposalAction'); profileService.lockFC();
$timeout(function() { return self.setSendError(err);
$scope.$digest(); }
}, 1);
} else go.walletHome(); if (!fc.canSign() && !fc.isPrivKeyExternal()) {
$log.info('No signing proposal: No private key')
self.setOngoingProcess();
self.resetForm();
txStatus.notify(txp, function() {
return $scope.$emit('Local/TxProposalAction');
});
return;
}
self.signAndBroadcast(txp, function(err) {
self.setOngoingProcess();
self.resetForm();
if (err) {
self.error = err.message ? err.message : gettext('The payment was created but could not be completed. Please try again from home screen');
$scope.$emit('Local/TxProposalAction');
$timeout(function() {
$scope.$digest();
}, 1);
} else go.walletHome();
});
}); });
}); });
}); });
@ -996,6 +1009,7 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
this.resetForm = function() { this.resetForm = function() {
this.resetError(); this.resetError();
this._paypro = null; this._paypro = null;
this.lockedCurrentFeePerKb = null;
this.lockAddress = false; this.lockAddress = false;
this.lockAmount = false; this.lockAmount = false;
@ -1257,16 +1271,30 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
this.setForm(null, amount, null); this.setForm(null, amount, null);
}; };
this.sendAll = function(amount, feeStr) { this.sendAll = function() {
var self = this; var self = this;
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees", { self.error = null;
fee: feeStr self.setOngoingProcess(gettext('Getting fee'));
}); $rootScope.$emit('Local/SetFeeSendMax', function(currentFeePerKb, availableMaxBalance, feeToSendMaxStr) {
self.setOngoingProcess();
confirmDialog.show(msg, function(confirmed) { if (lodash.isNull(currentFeePerKb)) {
if (confirmed) { self.error = gettext('Could not calculate fee');
self._doSendAll(amount); $scope.$apply();
return;
} }
self.lockedCurrentFeePerKb = currentFeePerKb;
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees", {
fee: feeToSendMaxStr
});
$scope.$apply();
confirmDialog.show(msg, function(confirmed) {
if (confirmed) {
self._doSendAll(availableMaxBalance);
} else {
self.resetForm();
}
});
}); });
}; };

View file

@ -24,9 +24,12 @@ angular.module('copayApp.services').factory('txFormatService', function(profileS
root.processTx = function(tx) { root.processTx = function(tx) {
if (!tx) return; if (!tx) return;
if (lodash.isArray(tx.outputs) && tx.outputs.length > 0 && tx.action != 'received') { var outputs = lodash.isArray(tx.outputs) ? tx.outputs.length : 0;
tx.hasMultiplesOutputs = true; if (outputs && tx.action != 'received') {
tx.recipientCount = tx.outputs.length; if ((tx.type && tx.type == 'multiple_output') || (tx.proposalType && tx.proposalType == 'multiple_output')) {
tx.hasMultiplesOutputs = true;
tx.recipientCount = outputs;
}
tx.amount = lodash.reduce(tx.outputs, function(total, o) { tx.amount = lodash.reduce(tx.outputs, function(total, o) {
o.amountStr = formatAmountStr(o.amount); o.amountStr = formatAmountStr(o.amount);
o.alternativeAmountStr = formatAlternativeStr(o.amount); o.alternativeAmountStr = formatAlternativeStr(o.amount);