From 419cb4cdb89b996031927380eae24d5d74157581 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 15 Jun 2017 19:30:28 -0300 Subject: [PATCH 01/84] Debit card: topup improvements --- src/js/controllers/topup.js | 212 +++++++++++++++++------------- src/js/directives/countdown.js | 67 ++++++++++ src/js/services/onGoingProcess.js | 3 +- src/sass/views/bitpayCard.scss | 3 + www/views/topup.html | 26 +++- 5 files changed, 219 insertions(+), 92 deletions(-) create mode 100644 src/js/directives/countdown.js diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index ce9ff7964..80341cb20 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -1,24 +1,14 @@ 'use strict'; -angular.module('copayApp.controllers').controller('topUpController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, bitpayService, bitpayCardService, payproService, bwcError, txFormatService, sendMaxService) { +angular.module('copayApp.controllers').controller('topUpController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, bitpayService, bitpayCardService, payproService, bwcError, txFormatService, sendMaxService, gettextCatalog) { - var amount; - var currency; + var dataSrc = {}; var cardId; var sendMax; - - $scope.isCordova = platformInfo.isCordova; - - $scope.$on("$ionicView.beforeLeave", function(event, data) { - $ionicConfig.views.swipeBackEnabled(true); - }); - - $scope.$on("$ionicView.enter", function(event, data) { - $ionicConfig.views.swipeBackEnabled(false); - }); + var configWallet = configService.getSync().wallet; var showErrorAndBack = function(title, msg) { - title = title || 'Error'; + title = title || gettextCatalog.getString('Error'); $scope.sendStatus = ''; $log.error(msg); msg = msg.errors ? msg.errors[0].message : msg; @@ -28,7 +18,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }; var showError = function(title, msg) { - title = title || 'Error'; + title = title || gettextCatalog.getString('Error'); $scope.sendStatus = ''; $log.error(msg); msg = msg.errors ? msg.errors[0].message : msg; @@ -37,7 +27,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s var publishAndSign = function (wallet, txp, onSendStatusChange, cb) { if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { - var err = 'No signing proposal: No private key'; + var err = gettextCatalog.getString('No signing proposal: No private key'); $log.info(err); return cb(err); } @@ -50,7 +40,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s var statusChangeHandler = function (processName, showName, isOn) { $log.debug('statusChangeHandler: ', processName, showName, isOn); - if ( processName == 'topup' && !isOn) { + if ( processName == 'sendingTx' && !isOn) { $scope.sendStatus = 'success'; $timeout(function() { $scope.$digest(); @@ -60,21 +50,57 @@ angular.module('copayApp.controllers').controller('topUpController', function($s } }; + var createInvoice = function() { + $scope.expirationTime = null; + ongoingProcess.set('creatingInvoice', true); + bitpayCardService.topUp(cardId, dataSrc, function(err, invoiceId) { + if (err) { + ongoingProcess.set('creatingInvoice', false); + showErrorAndBack(gettextCatalog.getString('Could not create the invoice'), err); + return; + } + + bitpayCardService.getInvoice(invoiceId, function(err, inv) { + ongoingProcess.set('creatingInvoice', false); + if (err) { + showError(gettextCatalog.getString('Could not get the invoice'), err); + return; + } + $scope.invoice = inv; + $scope.expirationTime = ($scope.invoice.expirationTime - $scope.invoice.invoiceTime) / 1000; + $timeout(function() { + $scope.$digest(); + }, 1); + }); + }); + }; + + $scope.$on("$ionicView.beforeLeave", function(event, data) { + $ionicConfig.views.swipeBackEnabled(true); + }); + + $scope.$on("$ionicView.enter", function(event, data) { + $ionicConfig.views.swipeBackEnabled(false); + }); + $scope.$on("$ionicView.beforeEnter", function(event, data) { + $scope.wallet = null; + $scope.isCordova = platformInfo.isCordova; + cardId = data.stateParams.id; sendMax = data.stateParams.useSendMax; if (!cardId) { - showErrorAndBack(null, 'No card selected'); + showErrorAndBack(null, gettextCatalog.getString('No card selected')); return; } - + var parsedAmount = txFormatService.parseAmount( - data.stateParams.amount, + data.stateParams.amount, data.stateParams.currency); - amount = parsedAmount.amount; - currency = parsedAmount.currency; + dataSrc['amount'] = parsedAmount.amount; + dataSrc['currency'] = parsedAmount.currency; $scope.amountUnitStr = parsedAmount.amountUnitStr; $scope.network = bitpayService.getEnvironment().network; @@ -86,7 +112,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }); if (lodash.isEmpty($scope.wallets)) { - showErrorAndBack(null, 'Insufficient funds'); + showErrorAndBack(null, gettextCatalog.getString('Insufficient funds')); return; } $scope.onWalletSelect($scope.wallets[0]); // Default first wallet @@ -107,90 +133,88 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }); $scope.topUpConfirm = function() { - - var config = configService.getSync(); - var configWallet = config.wallet; - var walletSettings = configWallet.settings; - - var message = 'Add ' + amount + ' ' + currency + ' to debit card'; - var okText = 'Confirm'; - var cancelText = 'Cancel'; - popupService.showConfirm(null, message, okText, cancelText, function(ok) { + var title; + var message = gettextCatalog.getString("Top up {{amountStr}} to debit card ({{cardLastNumber}})", { + amountStr: $scope.amountUnitStr, + cardLastNumber: $scope.cardInfo.lastFourDigits + }); + var okText = gettextCatalog.getString('Continue'); + var cancelText = gettextCatalog.getString('Cancel'); + popupService.showConfirm(title, message, okText, cancelText, function(ok) { if (!ok) return; - var dataSrc = { - amount: amount, - currency: currency - }; ongoingProcess.set('topup', true, statusChangeHandler); - bitpayCardService.topUp(cardId, dataSrc, function(err, invoiceId) { + + var payProUrl = ($scope.invoice && $scope.invoice.paymentUrls) ? $scope.invoice.paymentUrls.BIP73 : null; + + if (!payProUrl) { + ongoingProcess.set('topup', false, statusChangeHandler); + showError(gettextCatalog.getString('Error in Payment Protocol'), gettextCatalog.getString('Invalid URL')); + return; + } + + payproService.getPayProDetails(payProUrl, function(err, payProDetails) { if (err) { ongoingProcess.set('topup', false, statusChangeHandler); - showErrorAndBack('Could not create the invoice', err); + showError(gettextCatalog.getString('Error fetching invoice'), err); return; } - bitpayCardService.getInvoice(invoiceId, function(err, invoice) { + var outputs = []; + var toAddress = payProDetails.toAddress; + var amountSat = payProDetails.amount; + + outputs.push({ + 'toAddress': toAddress, + 'amount': amountSat, + 'message': message + }); + + var txp = { + toAddress: toAddress, + amount: amountSat, + outputs: outputs, + message: message, + payProUrl: payProUrl, + excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true, + feeLevel: configWallet.settings.feeLevel || 'normal' + }; + + walletService.createTx($scope.wallet, txp, function(err, ctxp) { if (err) { ongoingProcess.set('topup', false, statusChangeHandler); - showError('Could not get the invoice', err); + showError(gettextCatalog.getString('Could not create transaction'), bwcError.msg(err)); return; } - var payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null; - - if (!payProUrl) { + title = gettextCatalog.getString('Sending {{amountStr}} from {{name}}', { + amountStr: txFormatService.formatAmountStr(ctxp.amount, true), + name: $scope.wallet.name + }); + message = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", { + fee: txFormatService.formatAmountStr(ctxp.fee) + }); + okText = gettextCatalog.getString('Confirm'); + popupService.showConfirm(title, message, okText, cancelText, function(ok) { ongoingProcess.set('topup', false, statusChangeHandler); - showError('Error in Payment Protocol', 'Invalid URL'); - return; - } - - payproService.getPayProDetails(payProUrl, function(err, payProDetails) { - if (err) { - ongoingProcess.set('topup', false, statusChangeHandler); - showError('Error fetching invoice', err); + if (!ok) { + $scope.sendStatus = ''; return; } - var outputs = []; - var toAddress = payProDetails.toAddress; - var amountSat = payProDetails.amount; - var comment = 'Top up ' + amount + ' ' + currency + ' to Debit Card (' + $scope.cardInfo.lastFourDigits + ')'; - - outputs.push({ - 'toAddress': toAddress, - 'amount': amountSat, - 'message': comment - }); - - var txp = { - toAddress: toAddress, - amount: amountSat, - outputs: outputs, - message: comment, - payProUrl: payProUrl, - excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true, - feeLevel: walletSettings.feeLevel || 'normal' - }; - - walletService.createTx($scope.wallet, txp, function(err, ctxp) { + $scope.expirationTime = null; // Disable countdown + ongoingProcess.set('sendingTx', true, statusChangeHandler); + publishAndSign($scope.wallet, ctxp, function() {}, function(err, txSent) { + ongoingProcess.set('sendingTx', false, statusChangeHandler); if (err) { - ongoingProcess.set('topup', false, statusChangeHandler); - showError('Could not create transaction', bwcError.msg(err)); + showError(gettextCatalog.getString('Could not send transaction'), err); return; } - publishAndSign($scope.wallet, ctxp, function() {}, function(err, txSent) { - ongoingProcess.set('topup', false, statusChangeHandler); - if (err) { - showError('Could not send transaction', err); - return; - } - }); }); - }, true); // Disable loader + }); }); - }); - }); + }, true); // Disable loader + }); }; $scope.showWalletSelector = function() { @@ -199,6 +223,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }; $scope.onWalletSelect = function(wallet) { + if ($scope.wallet && (wallet.id == $scope.wallet.id)) return; $scope.wallet = wallet; if (sendMax) { ongoingProcess.set('retrievingInputs', true); @@ -208,23 +233,30 @@ angular.module('copayApp.controllers').controller('topUpController', function($s showErrorAndBack(null, err); return; } - var config = configService.getSync().wallet.settings; - var unitName = config.unitName; + var unitName = configWallet.settings.unitName; var amountUnit = txFormatService.satToUnit(values.amount); var parsedAmount = txFormatService.parseAmount( - amountUnit, + amountUnit, unitName); - amount = parsedAmount.amount; - currency = parsedAmount.currency; + dataSrc['amount'] = parsedAmount.amount; + dataSrc['currency'] = parsedAmount.currency; $scope.amountUnitStr = parsedAmount.amountUnitStr; + createInvoice(); $timeout(function() { $scope.$digest(); }, 100); }); + } else { + createInvoice(); } }; + $scope.invoiceExpired = function() { + $scope.sendStatus = ''; + showErrorAndBack(gettextCatalog.getString('Invoice Expired'), gettextCatalog.getString('This invoice has expired. An invoice is only valid for 15 minutes.')); + }; + $scope.goBackHome = function() { $scope.sendStatus = ''; $ionicHistory.nextViewOptions({ diff --git a/src/js/directives/countdown.js b/src/js/directives/countdown.js new file mode 100644 index 000000000..1e9ee4100 --- /dev/null +++ b/src/js/directives/countdown.js @@ -0,0 +1,67 @@ +'use strict'; + +angular.module('copayApp.directives') + .directive('timer', function() { + return { + restrict: 'EAC', + replace: false, + scope: { + countdown: "=", + interval: "=", + active: "=", + onZeroCallback: "=" + }, + template:"{{formatted}}", + controller: function ($scope, $attrs, $timeout, lodash) { + $scope.format = $attrs.outputFormat; + + var queueTick = function () { + $scope.timer = $timeout(function () { + if ($scope.countdown > 0) { + $scope.countdown -= 1; + + if ($scope.countdown > 0) { + queueTick(); + } else { + $scope.countdown = 0; + $scope.active = false; + if (!lodash.isUndefined($scope.onZeroCallback)) { + $scope.onZeroCallback(); + } + } + } + }, $scope.interval); + }; + + if ($scope.active) { + queueTick(); + } + + $scope.$watch('active', function (newValue, oldValue) { + if (newValue !== oldValue) { + if (newValue === true) { + if ($scope.countdown > 0) { + queueTick(); + } else { + $scope.active = false; + } + } else { + $timeout.cancel($scope.timer); + } + } + }); + $scope.$watch('countdown', function () { + updateFormatted(); + }); + + var updateFormatted = function () { + $scope.formatted = moment($scope.countdown * $scope.interval).format($scope.format); + }; + updateFormatted(); + + $scope.$on('$destroy', function () { + $timeout.cancel($scope.timer); + }); + } + }; + }); diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js index 7a2fd1ff9..19e492e47 100644 --- a/src/js/services/onGoingProcess.js +++ b/src/js/services/onGoingProcess.js @@ -45,7 +45,8 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti 'cancelingGiftCard': 'Canceling Gift Card...', 'creatingGiftCard': 'Creating Gift Card...', 'buyingGiftCard': 'Buying Gift Card...', - 'topup': 'Top up in progress...' + 'topup': gettext('Top up in progress...'), + 'creatingInvoice': gettext('Creating invoice...') }; root.clear = function() { diff --git a/src/sass/views/bitpayCard.scss b/src/sass/views/bitpayCard.scss index a1ae39918..ff5d3e9b5 100644 --- a/src/sass/views/bitpayCard.scss +++ b/src/sass/views/bitpayCard.scss @@ -93,6 +93,9 @@ stroke: $v-bitcoin-orange; } } + .total { + font-weight: bold; + } } .tx-icon { margin-right: 25px; diff --git a/www/views/topup.html b/www/views/topup.html index 61e8c800c..0310914f2 100644 --- a/www/views/topup.html +++ b/www/views/topup.html @@ -19,7 +19,7 @@
{{amountUnitStr}}
- @ + @ {{rate | currency:cardInfo.currencySymbol:2}} per BTC ...
@@ -54,6 +54,30 @@ {{cardInfo.email}}
+ +
+ Invoice +
+
+ Expire in + + {{formatted}} + +
+
+ Fee + + {{invoice.buyerPaidBtcMinerFee}} + +
+
+ Total + + {{invoice.buyerTotalBtcAmount}} + +
+
From 70944013125cad208b88a557ac050f21a2043ce8 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 15 Jun 2017 19:42:00 -0300 Subject: [PATCH 02/84] Add strings to translate --- i18n/po/template.pot | 233 ++++++++++++++++++++++++++---------- src/js/controllers/topup.js | 4 +- www/views/topup.html | 24 ++-- 3 files changed, 185 insertions(+), 76 deletions(-) diff --git a/i18n/po/template.pot b/i18n/po/template.pot index b267e4465..8931363d3 100644 --- a/i18n/po/template.pot +++ b/i18n/po/template.pot @@ -53,6 +53,7 @@ msgid "Accepted" msgstr "" #: www/views/preferencesInformation.html:66 +#: www/views/topup.html:52 msgid "Account" msgstr "" @@ -192,7 +193,7 @@ msgstr "" msgid "Amount too big" msgstr "" -#: src/js/controllers/tab-home.js:143 +#: src/js/controllers/tab-home.js:141 msgid "An update to this app is available. For your security, please update to the latest version." msgstr "" @@ -366,7 +367,7 @@ msgstr "" msgid "Buy & Sell Bitcoin" msgstr "" -#: www/views/tab-send.html:31 +#: www/views/tab-send.html:35 msgid "Buy Bitcoin" msgstr "" @@ -379,6 +380,7 @@ msgid "Calculating fee" msgstr "" #: src/js/controllers/confirm.js:498 +#: src/js/controllers/topup.js:142 #: src/js/services/popupService.js:59 #: www/views/addressbook.add.html:10 #: www/views/feedback/send.html:5 @@ -400,6 +402,10 @@ msgstr "" msgid "Cannot join the same wallet more that once" msgstr "" +#: www/views/topup.html:46 +msgid "Card" +msgstr "" + #: www/views/includes/bitpayCardsCard.html:4 msgid "Cards" msgstr "" @@ -463,6 +469,7 @@ msgstr "" #: src/js/controllers/confirm.js:497 #: src/js/controllers/copayers.js:55 +#: src/js/controllers/topup.js:197 #: www/views/backup.html:53 #: www/views/backup.html:72 #: www/views/confirm.html:4 @@ -516,10 +523,11 @@ msgstr "" msgid "Connection reset by peer" msgstr "" -#: www/views/tab-send.html:41 +#: www/views/tab-send.html:45 msgid "Contacts" msgstr "" +#: src/js/controllers/topup.js:141 #: www/views/onboarding/notifications.html:9 msgid "Continue" msgstr "" @@ -587,6 +595,14 @@ msgstr "" msgid "Could not create address" msgstr "" +#: src/js/controllers/topup.js:59 +msgid "Could not create the invoice" +msgstr "" + +#: src/js/controllers/topup.js:186 +msgid "Could not create transaction" +msgstr "" + #: src/js/services/profileService.js:342 msgid "Could not create using the specified extended private key" msgstr "" @@ -599,7 +615,7 @@ msgstr "" msgid "Could not create: Invalid wallet recovery phrase" msgstr "" -#: src/js/controllers/import.js:83 +#: src/js/controllers/import.js:99 msgid "Could not decrypt file, check your password" msgstr "" @@ -615,13 +631,17 @@ msgstr "" msgid "Could not get dynamic fee for level: {{feeLevel}}" msgstr "" +#: src/js/controllers/topup.js:66 +msgid "Could not get the invoice" +msgstr "" + #: src/js/controllers/bitpayCard.js:69 msgid "Could not get transactions" msgstr "" #: src/js/services/profileService.js:595 -#: src/js/services/profileService.js:627 -#: src/js/services/profileService.js:650 +#: src/js/services/profileService.js:629 +#: src/js/services/profileService.js:652 msgid "Could not import" msgstr "" @@ -654,6 +674,10 @@ msgstr "" msgid "Could not send payment" msgstr "" +#: src/js/controllers/topup.js:210 +msgid "Could not send transaction" +msgstr "" + #: www/views/walletDetails.html:197 msgid "Could not update transaction history" msgstr "" @@ -679,7 +703,7 @@ msgstr "" #: www/views/onboarding/tour.html:51 #: www/views/tab-home.html:76 -#: www/views/tab-send.html:32 +#: www/views/tab-send.html:36 msgid "Create bitcoin wallet" msgstr "" @@ -704,6 +728,10 @@ msgstr "" msgid "Creating Wallet..." msgstr "" +#: src/js/services/onGoingProcess.js:49 +msgid "Creating invoice..." +msgstr "" + #: src/js/services/onGoingProcess.js:17 msgid "Creating transaction" msgstr "" @@ -747,6 +775,10 @@ msgstr "" msgid "Deleting payment proposal" msgstr "" +#: www/views/topup.html:42 +msgid "Deposit into" +msgstr "" + #: www/views/join.html:138 #: www/views/tab-create-personal.html:109 #: www/views/tab-create-shared.html:138 @@ -880,24 +912,24 @@ msgstr "" #: src/js/controllers/export.js:47 #: src/js/controllers/export.js:53 #: src/js/controllers/feedback/send.js:23 -#: src/js/controllers/import.js:100 -#: src/js/controllers/import.js:118 -#: src/js/controllers/import.js:168 -#: src/js/controllers/import.js:196 -#: src/js/controllers/import.js:205 -#: src/js/controllers/import.js:220 -#: src/js/controllers/import.js:232 -#: src/js/controllers/import.js:243 -#: src/js/controllers/import.js:253 -#: src/js/controllers/import.js:266 -#: src/js/controllers/import.js:278 -#: src/js/controllers/import.js:288 -#: src/js/controllers/import.js:298 -#: src/js/controllers/import.js:322 -#: src/js/controllers/import.js:334 -#: src/js/controllers/import.js:54 -#: src/js/controllers/import.js:67 -#: src/js/controllers/import.js:88 +#: src/js/controllers/import.js:104 +#: src/js/controllers/import.js:116 +#: src/js/controllers/import.js:134 +#: src/js/controllers/import.js:185 +#: src/js/controllers/import.js:213 +#: src/js/controllers/import.js:222 +#: src/js/controllers/import.js:237 +#: src/js/controllers/import.js:249 +#: src/js/controllers/import.js:260 +#: src/js/controllers/import.js:270 +#: src/js/controllers/import.js:294 +#: src/js/controllers/import.js:307 +#: src/js/controllers/import.js:317 +#: src/js/controllers/import.js:327 +#: src/js/controllers/import.js:351 +#: src/js/controllers/import.js:364 +#: src/js/controllers/import.js:70 +#: src/js/controllers/import.js:83 #: src/js/controllers/join.js:120 #: src/js/controllers/join.js:134 #: src/js/controllers/join.js:141 @@ -911,8 +943,10 @@ msgstr "" #: src/js/controllers/preferencesBitpayServices.js:50 #: src/js/controllers/preferencesDelete.js:37 #: src/js/controllers/preferencesExternal.js:20 -#: src/js/controllers/tab-home.js:170 +#: src/js/controllers/tab-home.js:168 #: src/js/controllers/tabsController.js:7 +#: src/js/controllers/topup.js:11 +#: src/js/controllers/topup.js:21 #: src/js/controllers/tx-details.js:106 #: src/js/services/incomingData.js:98 msgid "Error" @@ -926,6 +960,14 @@ msgstr "" msgid "Error creating wallet" msgstr "" +#: src/js/controllers/topup.js:159 +msgid "Error fetching invoice" +msgstr "" + +#: src/js/controllers/topup.js:152 +msgid "Error in Payment Protocol" +msgstr "" + #: src/js/controllers/bitpayCardIntro.js:14 msgid "Error pairing BitPay Account" msgstr "" @@ -946,6 +988,10 @@ msgstr "" msgid "Exceeded daily limit of $500 per user" msgstr "" +#: www/views/topup.html:62 +msgid "Expire in" +msgstr "" + #: src/js/controllers/confirm.js:342 #: www/views/confirm.html:27 #: www/views/modals/txp-details.html:120 @@ -997,6 +1043,7 @@ msgid "Family vacation funds" msgstr "" #: www/views/modals/txp-details.html:101 +#: www/views/topup.html:69 #: www/views/tx-details.html:81 msgid "Fee" msgstr "" @@ -1039,6 +1086,7 @@ msgstr "" #: www/views/confirm.html:65 #: www/views/modals/txp-details.html:74 +#: www/views/topup.html:32 #: www/views/tx-details.html:52 msgid "From" msgstr "" @@ -1047,6 +1095,10 @@ msgstr "" msgid "From BitPay account" msgstr "" +#: www/views/tab-import-phrase.html:54 +msgid "From Hardware Wallet" +msgstr "" + #: www/views/tab-export-qrCode.html:5 msgid "From the destination device, go to Add wallet > Import wallet and scan this QR code" msgstr "" @@ -1063,6 +1115,10 @@ msgstr "" msgid "Funds transferred" msgstr "" +#: www/views/topup.html:113 +msgid "Funds were added to debit card" +msgstr "" + #: www/views/paperWallet.html:22 msgid "Funds will be transferred to" msgstr "" @@ -1100,12 +1156,12 @@ msgstr "" msgid "Getting fee levels..." msgstr "" -#: src/js/controllers/bitpayCard.js:171 -#: src/js/controllers/bitpayCard.js:181 +#: src/js/controllers/bitpayCard.js:179 +#: src/js/controllers/bitpayCard.js:189 #: src/js/controllers/onboarding/terms.js:23 #: src/js/controllers/preferencesAbout.js:16 #: src/js/controllers/preferencesLanguage.js:14 -#: src/js/controllers/tab-home.js:145 +#: src/js/controllers/tab-home.js:143 #: src/js/controllers/tab-settings.js:48 #: src/js/controllers/tx-details.js:169 msgid "Go Back" @@ -1140,7 +1196,7 @@ msgstr "" msgid "Help & Support" msgstr "" -#: src/js/controllers/bitpayCard.js:169 +#: src/js/controllers/bitpayCard.js:177 #: src/js/controllers/tab-settings.js:46 msgid "Help and support information is available at the website." msgstr "" @@ -1249,7 +1305,7 @@ msgid "If you take a screenshot, your backup may be viewed by other apps. You ca msgstr "" #: www/views/tab-import-hardware.html:42 -#: www/views/tab-import-phrase.html:63 +#: www/views/tab-import-phrase.html:77 msgid "Import" msgstr "" @@ -1293,10 +1349,11 @@ msgid "Incorrect address network" msgstr "" #. Trying to import a malformed wallet export QR code -#: src/js/controllers/import.js:54 +#: src/js/controllers/import.js:70 msgid "Incorrect code format" msgstr "" +#: src/js/controllers/topup.js:115 #: src/js/services/bwcError.js:44 #: www/views/confirm.html:99 msgid "Insufficient funds" @@ -1310,8 +1367,12 @@ msgstr "" msgid "Invalid" msgstr "" +#: src/js/controllers/topup.js:152 +msgid "Invalid URL" +msgstr "" + #: src/js/controllers/create.js:175 -#: src/js/controllers/import.js:298 +#: src/js/controllers/import.js:327 #: src/js/controllers/join.js:141 msgid "Invalid account number" msgstr "" @@ -1325,7 +1386,7 @@ msgid "Invalid data" msgstr "" #: src/js/controllers/create.js:155 -#: src/js/controllers/import.js:232 +#: src/js/controllers/import.js:249 #: src/js/controllers/join.js:120 msgid "Invalid derivation path" msgstr "" @@ -1334,6 +1395,14 @@ msgstr "" msgid "Invitation to share a {{appName}} Wallet" msgstr "" +#: www/views/topup.html:58 +msgid "Invoice" +msgstr "" + +#: src/js/controllers/topup.js:257 +msgid "Invoice Expired" +msgstr "" + #: src/js/controllers/feedback/send.js:79 msgid "Is there anything we could do better?" msgstr "" @@ -1544,6 +1613,10 @@ msgstr "" msgid "No backup, no bitcoin." msgstr "" +#: src/js/controllers/topup.js:94 +msgid "No card selected" +msgstr "" + #: www/views/addressbook.html:19 msgid "No contacts yet" msgstr "" @@ -1564,6 +1637,10 @@ msgstr "" msgid "No recent transactions" msgstr "" +#: src/js/controllers/topup.js:30 +msgid "No signing proposal: No private key" +msgstr "" + #: www/views/walletDetails.html:191 msgid "No transactions yet" msgstr "" @@ -1662,7 +1739,7 @@ msgstr "" msgid "On this screen you can see all your wallets, accounts, and assets." msgstr "" -#: src/js/controllers/bitpayCard.js:170 +#: src/js/controllers/bitpayCard.js:178 #: src/js/controllers/tab-settings.js:47 msgid "Open" msgstr "" @@ -1679,7 +1756,7 @@ msgstr "" msgid "Open GitHub Project" msgstr "" -#: src/js/controllers/bitpayCard.js:180 +#: src/js/controllers/bitpayCard.js:188 #: src/js/controllers/tx-details.js:168 msgid "Open Insight" msgstr "" @@ -1715,7 +1792,7 @@ msgstr "" msgid "Password" msgstr "" -#: src/js/controllers/import.js:67 +#: src/js/controllers/import.js:83 msgid "Password required. Make sure to enter your password in advanced options" msgstr "" @@ -1795,10 +1872,6 @@ msgstr "" msgid "Payment request" msgstr "" -#: www/views/includes/cardActivity.html:41 -msgid "Pending" -msgstr "" - #: www/views/proposals.html:5 msgid "Pending Proposals" msgstr "" @@ -1819,7 +1892,7 @@ msgstr "" msgid "Please connect a camera to get started." msgstr "" -#: src/js/controllers/import.js:243 +#: src/js/controllers/import.js:260 msgid "Please enter the recovery phrase" msgstr "" @@ -1840,7 +1913,7 @@ msgstr "" msgid "Please upgrade Copay to perform this action" msgstr "" -#: src/js/controllers/import.js:205 +#: src/js/controllers/import.js:222 msgid "Please, select your backup file" msgstr "" @@ -1965,7 +2038,7 @@ msgid "Recent Transactions" msgstr "" #: www/views/amount.html:18 -#: www/views/tab-send.html:8 +#: www/views/tab-send.html:9 msgid "Recipient" msgstr "" @@ -2083,6 +2156,10 @@ msgstr "" msgid "Scan addresses for funds" msgstr "" +#: www/views/modals/fingerprintCheck.html:11 +msgid "Scan again" +msgstr "" + #: src/js/services/fingerprintService.js:56 msgid "Scan your fingerprint please" msgstr "" @@ -2099,7 +2176,7 @@ msgstr "" msgid "Search Transactions" msgstr "" -#: www/views/tab-send.html:11 +#: www/views/tab-send.html:13 msgid "Search or enter bitcoin address" msgstr "" @@ -2196,8 +2273,13 @@ msgstr "" msgid "Sending {{amountStr}} from your {{name}} wallet" msgstr "" +#: src/js/controllers/topup.js:190 +msgid "Sending {{amountStr}} from {{walletName}}" +msgstr "" + #: www/views/includes/walletHistory.html:37 #: www/views/modals/tx-status.html:9 +#: www/views/topup.html:110 #: www/views/tx-details.html:17 msgid "Sent" msgstr "" @@ -2267,11 +2349,11 @@ msgstr "" msgid "Show advanced options" msgstr "" -#: www/views/tab-send.html:33 +#: www/views/tab-send.html:37 msgid "Show bitcoin address" msgstr "" -#: www/views/tab-send.html:55 +#: www/views/tab-send.html:59 msgid "Show more" msgstr "" @@ -2319,7 +2401,7 @@ msgstr "" msgid "Spending Password needed" msgstr "" -#: www/views/tab-send.html:24 +#: www/views/tab-send.html:28 msgid "Start sending bitcoin" msgstr "" @@ -2331,6 +2413,10 @@ msgstr "" msgid "Startup Lock" msgstr "" +#: www/views/topup.html:111 +msgid "Success" +msgstr "" + #: src/js/services/feeService.js:12 msgid "Super Economy" msgstr "" @@ -2377,7 +2463,7 @@ msgid "Terms of Use" msgstr "" #: www/views/tab-create-personal.html:116 -#: www/views/tab-import-phrase.html:58 +#: www/views/tab-import-phrase.html:65 msgid "Testnet" msgstr "" @@ -2483,9 +2569,9 @@ msgstr "" msgid "There is a new version of {{appName}} available" msgstr "" -#: src/js/controllers/import.js:196 -#: src/js/controllers/import.js:220 -#: src/js/controllers/import.js:288 +#: src/js/controllers/import.js:213 +#: src/js/controllers/import.js:237 +#: src/js/controllers/import.js:317 msgid "There is an error in the form" msgstr "" @@ -2506,6 +2592,10 @@ msgstr "" msgid "This bitcoin payment request has expired." msgstr "" +#: src/js/controllers/topup.js:257 +msgid "This invoice has expired. An invoice is only valid for 15 minutes." +msgstr "" + #: www/views/join.html:130 #: www/views/tab-create-personal.html:101 #: www/views/tab-create-shared.html:130 @@ -2539,15 +2629,24 @@ msgstr "" msgid "To" msgstr "" -#: www/views/tab-send.html:28 +#: www/views/tab-send.html:32 msgid "To get started, buy bitcoin or share your address. You can receive bitcoin from any wallet or service." msgstr "" -#: www/views/tab-send.html:29 +#: www/views/tab-send.html:33 msgid "To get started, you'll need to create a bitcoin wallet and get some bitcoin." msgstr "" +#: src/js/services/onGoingProcess.js:48 +msgid "Top up in progress..." +msgstr "" + +#: src/js/controllers/topup.js:137 +msgid "Top up {{amountStr}} to debit card ({{cardLastNumber}})" +msgstr "" + #: www/views/modals/wallet-balance.html:23 +#: www/views/topup.html:75 msgid "Total" msgstr "" @@ -2581,12 +2680,16 @@ msgstr "" msgid "Transaction created" msgstr "" +#: www/views/topup.html:114 +msgid "Transaction initiated" +msgstr "" + #: src/js/controllers/tx-details.js:106 msgid "Transaction not available at this time" msgstr "" #: src/js/controllers/activity.js:45 -#: src/js/controllers/tab-home.js:170 +#: src/js/controllers/tab-home.js:168 msgid "Transaction not found" msgstr "" @@ -2594,7 +2697,7 @@ msgstr "" msgid "Transfer to" msgstr "" -#: www/views/tab-send.html:63 +#: www/views/tab-send.html:67 msgid "Transfer to Wallet" msgstr "" @@ -2634,7 +2737,7 @@ msgstr "" msgid "Unused Addresses Limit" msgstr "" -#: src/js/controllers/tab-home.js:142 +#: src/js/controllers/tab-home.js:140 msgid "Update Available" msgstr "" @@ -2662,6 +2765,10 @@ msgstr "" msgid "Validating recovery phrase..." msgstr "" +#: www/views/modals/fingerprintCheck.html:4 +msgid "Verify your identity" +msgstr "" + #: www/views/preferencesAbout.html:14 #: www/views/preferencesExternal.html:25 msgid "Version" @@ -2679,12 +2786,12 @@ msgstr "" msgid "View Terms of Service" msgstr "" -#: src/js/controllers/bitpayCard.js:179 +#: src/js/controllers/bitpayCard.js:187 #: src/js/controllers/tx-details.js:167 msgid "View Transaction on Insight" msgstr "" -#: src/js/controllers/tab-home.js:144 +#: src/js/controllers/tab-home.js:142 msgid "View Update" msgstr "" @@ -2783,7 +2890,7 @@ msgid "Wallet Recovery Phrase is invalid" msgstr "" #: www/views/preferencesAdvanced.html:25 -#: www/views/tab-import-phrase.html:53 +#: www/views/tab-import-phrase.html:70 msgid "Wallet Service URL" msgstr "" @@ -2792,6 +2899,7 @@ msgid "Wallet Settings" msgstr "" #: www/views/tab-import-hardware.html:11 +#: www/views/tab-import-phrase.html:58 msgid "Wallet Type" msgstr "" @@ -2841,7 +2949,7 @@ msgstr "" msgid "Wallet not found" msgstr "" -#: src/js/controllers/tab-home.js:216 +#: src/js/controllers/tab-home.js:214 msgid "Wallet not registered" msgstr "" @@ -2926,7 +3034,7 @@ msgstr "" msgid "Would you like to receive push notifications about payments?" msgstr "" -#: src/js/controllers/import.js:253 +#: src/js/controllers/import.js:270 msgid "Wrong number of recovery words:" msgstr "" @@ -3067,6 +3175,7 @@ msgid "{{appName}} depends on Bitcore Wallet Service (BWS) for blockchain inform msgstr "" #: src/js/controllers/confirm.js:211 +#: src/js/controllers/topup.js:194 msgid "{{fee}} will be deducted for bitcoin networking fees." msgstr "" diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index 80341cb20..c177a11d5 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -187,9 +187,9 @@ angular.module('copayApp.controllers').controller('topUpController', function($s return; } - title = gettextCatalog.getString('Sending {{amountStr}} from {{name}}', { + title = gettextCatalog.getString('Sending {{amountStr}} from {{walletName}}', { amountStr: txFormatService.formatAmountStr(ctxp.amount, true), - name: $scope.wallet.name + walletName: $scope.wallet.name }); message = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", { fee: txFormatService.formatAmountStr(ctxp.fee) diff --git a/www/views/topup.html b/www/views/topup.html index 0310914f2..b0be31e40 100644 --- a/www/views/topup.html +++ b/www/views/topup.html @@ -29,7 +29,7 @@
-
From
+
From
@@ -39,40 +39,40 @@
-
+
Deposit into
- Card + Card xxxx-xxxx-xxxx-{{cardInfo.lastFourDigits}}
- Account + Account {{cardInfo.email}}
-
+
Invoice
- Expire in + Expire in {{formatted}}
- Fee + Fee {{invoice.buyerPaidBtcMinerFee}}
- Total + Total {{invoice.buyerTotalBtcAmount}} @@ -107,11 +107,11 @@ slide-success-show="sendStatus === 'success'" slide-success-on-confirm="goBackHome()" slide-success-hide-on-confirm="true"> - Sent - Success + Sent + Success
- Funds were added to debit card - Transaction initiated + Funds were added to debit card + Transaction initiated
From 5b063dfefe45090420e2874196d0a3e8c5235b15 Mon Sep 17 00:00:00 2001 From: Peter Banik Date: Thu, 15 Jun 2017 23:50:49 +0200 Subject: [PATCH 03/84] Watch PO files --- Gruntfile.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index bae9c9032..049f8696e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -93,7 +93,14 @@ module.exports = function(grunt) { 'src/js/controllers/**/*.js' ], tasks: ['concat:js'] - } + }, + gettext: { + files: [ + 'i18n/po/*.po', + 'i18n/po/*.pot' + ], + tasks: ['nggettext_compile','concat'] + }, }, sass: { dist: { From a9c7be18895e77bdb44b1b930ebcc99f4e3b3ecc Mon Sep 17 00:00:00 2001 From: JDonadio Date: Mon, 19 Jun 2017 11:29:44 -0300 Subject: [PATCH 04/84] display fee values - txp details --- src/js/controllers/modals/txpDetails.js | 10 ++++++++++ src/sass/views/includes/txp-details.scss | 9 +++++++-- www/views/modals/txp-details.html | 9 +++++---- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index 01ab9277b..b59c11897 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -16,11 +16,21 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.data = {}; $scope.displayAmount = getDisplayAmount($scope.tx.amountStr); $scope.displayUnit = getDisplayUnit($scope.tx.amountStr); + displayFeeValues(); initActionList(); checkPaypro(); applyButtonText(); }; + function displayFeeValues() { + txFormatService.formatAlternativeStr($scope.tx.fee, function(v) { + $scope.tx.feeFiatStr = v; + }); + $scope.tx.feeRateStr = ($scope.tx.fee / ($scope.tx.amount + $scope.tx.fee) * 100).toFixed(2) + '%'; + if ($scope.tx.feeLevel == 'superEconomy') $scope.tx.feeLevelStr = gettextCatalog.getString('Super Economy'); + else $scope.tx.feeLevelStr = $scope.tx.feeLevelStr = $scope.tx.feeLevel.charAt(0).toUpperCase() + $scope.tx.feeLevel.slice(1); + }; + function applyButtonText() { $scope.buttonText = $scope.isCordova ? gettextCatalog.getString('Slide') + ' ' : gettextCatalog.getString('Click') + ' '; diff --git a/src/sass/views/includes/txp-details.scss b/src/sass/views/includes/txp-details.scss index d08087180..c68841a4c 100644 --- a/src/sass/views/includes/txp-details.scss +++ b/src/sass/views/includes/txp-details.scss @@ -5,7 +5,12 @@ $item-vertical-padding: 10px; $item-border-color: #EFEFEF; $item-label-color: #6C6C6E; - + .item-note { + float: none; + .fee-rate { + display: inline-block; + } + } .list { background: #f5f5f5; } @@ -107,7 +112,7 @@ margin-top: 5px; font-size: 14px; color: $item-label-color; - } + } .item-divider { padding-top: 1.2rem; color: $item-label-color; diff --git a/www/views/modals/txp-details.html b/www/views/modals/txp-details.html index d18128132..a093ba441 100644 --- a/www/views/modals/txp-details.html +++ b/www/views/modals/txp-details.html @@ -97,10 +97,11 @@ {{tx.message}}
-
- Fee - - {{tx.feeStr}} +
+ {{'Fee:' | translate}} {{tx.feeLevelStr | translate}} + {{tx.feeStr || '...'}} + + {{tx.feeFiatStr || '...'}} - {{tx.feeRateStr}} of the transaction
From 9b90b8f2aaa9aa284b2be5c2449c0b7ce2844dbd Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Tue, 20 Jun 2017 12:14:21 -0300 Subject: [PATCH 05/84] confirm controller refactor / wip1 --- src/js/controllers/confirm.js | 626 +++++++++++++++--------------- src/js/controllers/paperWallet.js | 2 +- src/js/services/bwcError.js | 2 +- src/js/services/feeService.js | 42 +- src/js/services/sendMax.js | 2 +- www/views/confirm.html | 52 +-- 6 files changed, 367 insertions(+), 359 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 105c51f7f..4e3a2765a 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -1,14 +1,29 @@ 'use strict'; angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError) { - var cachedTxp = {}; - var feeLevel; - var feePerKb; - var toAmount; - var isChromeApp = platformInfo.isChromeApp; + var countDown = null; - var cachedSendMax = {}; - $scope.isCordova = platformInfo.isCordova; + + var tx = {}; + + // Config Related values + var config = configService.getSync(); + var walletConfig = config.wallet; + var unitToSatoshi = walletConfig.settings.unitToSatoshi; + var unitDecimals = walletConfig.settings.unitDecimals; + var satToUnit = 1 / unitToSatoshi; + var touchIdEnabled = config.touchIdFor && config.touchIdFor[wallet.id]; + var configFeeLevel = walletConfig.settings.feeLevel ? walletConfig.settings.feeLevel : 'normal'; + + + // Platform info + var isChromeApp = platformInfo.isChromeApp; + var isCordova = platformInfo.isCordova; + + + $scope.showWalletSelector = function() { + $scope.walletSelector = true; + }; $scope.$on("$ionicView.beforeLeave", function(event, data) { $ionicConfig.views.swipeBackEnabled(true); @@ -20,17 +35,83 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.$on("$ionicView.beforeEnter", function(event, data) { - toAmount = data.stateParams.toAmount; - cachedSendMax = {}; + function setWalletSelector(minAmount, cb) { + console.log('[confirm.js.38:minAmount:]', minAmount); //TODO + $scope.wallets = profileService.getWallets({ + onlyComplete: true, + network: $scope.network + }); + + if (!$scope.wallets || !$scope.wallets.length) { + $scope.noMatchingWallet = true; + $log.warn('No ' + $scope.network + ' wallets to make the payment'); + $timeout(function() { + $scope.$apply(); + }); + return; + } + + var filteredWallets = []; + var index = 0; + var walletsUpdated = 0; + + lodash.each($scope.wallets, function(w) { + walletService.getStatus(w, {}, function(err, status) { + if (err || !status) { + $log.error(err); + } else { + walletsUpdated++; + w.status = status; + + if (!status.availableBalanceSat) + $log.debug('No balance available in: ' + w.name); + + console.log('[confirm.js.68]', status.availableBalanceSat, minAmount); //TODO + if (status.availableBalanceSat > minAmount) { + filteredWallets.push(w); + } + } + + if (++index == $scope.wallets.length) { + if (!walletsUpdated) + return cb('Could not update any wallet'); + + if (lodash.isEmpty(filteredWallets)) { + $scope.insufficientFunds = true; + $log.warn('No wallet available to make the payment'); + } + $scope.wallets = lodash.clone(filteredWallets); + return cb(); + } + }); + }); + }; + + // Setup $scope + + // Grab stateParams + tx = { + toAmount: parseInt(data.stateParams.toAmount), + sendMax: data.stateParams.useSendMax == 'true' ? true : false, + toAddress: data.stateParams.toAddress, + description: data.stateParams.description, + paypro: data.stateParams.paypro, + + feeLevel: configFeeLevel, + spendUnconfirmed: walletConfig.spendUnconfirmed, + + // Vanity tx info (not in the real tx) + recipientType: data.stateParams.recipientType || null, + toName: data.stateParams.toName, + toEmail: data.stateParams.toEmail, + toColor: data.stateParams.toColor, + network: (new bitcore.Address(data.stateParams.toAddress)).network.name, + }; + + + // Other Scope vars + $scope.isCordova = isCordova; $scope.showAddress = false; - $scope.useSendMax = data.stateParams.useSendMax == 'true' ? true : false; - $scope.recipientType = data.stateParams.recipientType || null; - $scope.toAddress = data.stateParams.toAddress; - $scope.toName = data.stateParams.toName; - $scope.toEmail = data.stateParams.toEmail; - $scope.toColor = data.stateParams.toColor; - $scope.description = data.stateParams.description; - $scope.paypro = data.stateParams.paypro; $scope.insufficientFunds = false; $scope.noMatchingWallet = false; $scope.paymentExpired = { @@ -39,218 +120,223 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.remainingTimeStr = { value: null }; - $scope.network = (new bitcore.Address($scope.toAddress)).network.name; - setFee(); - resetValues(); - setwallets(); - applyButtonText(); + + + $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); + + console.log('[confirm.js.126:tx:]', tx); //TODO + + setWalletSelector(tx.toAmount, function(err) { + if (err) { + $log.debug('Error updating wallets:' + err); + popupService.showAlert(gettextCatalog.getString('Could not update wallets'), bwcError.msg(err), function() { + $ionicHistory.nextViewOptions({ + disableAnimate: true, + historyRoot: true + }); + $ionicHistory.clearHistory(); + $state.go('tabs.send'); + }); + } + + $log.debug('Wallet selector is setup'); + + if ($scope.wallets.length > 1) { + $scope.showWalletSelector(); + } else { + setWallet($scope.wallets[0], tx); + } + }); }); - function setFee(customFeeLevel, cb) { - feeService.getCurrentFeeValue($scope.network, customFeeLevel, function(err, currentFeePerKb) { - var config = configService.getSync().wallet; - var configFeeLevel = (config.settings && config.settings.feeLevel) ? config.settings.feeLevel : 'normal'; - feePerKb = currentFeePerKb; - feeLevel = customFeeLevel ? customFeeLevel : configFeeLevel; - $scope.feeLevel = feeService.feeOpts[feeLevel]; - if (cb) return cb(); + + function getSendMaxInfo(tx, cb) { + if (!tx.sendMax) return cb(); + + //ongoingProcess.set('retrievingInputs', true); + walletService.getSendMaxInfo(wallet, { + feePerKb: tx.feeRate, + excludeUnconfirmedUtxos: !tx.spendUnconfirmed, + returnInputs: true, + }, cb); + }; + + + function getTxp(tx, wallet, dryRun, cb) { + + var paypro = tx.paypro; + var toAddress = tx.toAddress; + var description = tx.description; + + // ToDo: use a credential's (or fc's) function for this + if (description && !wallet.credentials.sharedEncryptingKey) { + var msg = gettextCatalog.getString('Could not add message to imported wallet without shared encrypting key'); + $log.warn(msg); + return setSendError(msg); + } + + if (tx.toAmount > Number.MAX_SAFE_INTEGER) { + var msg = gettextCatalog.getString('Amount too big'); + $log.warn(msg); + return setSendError(msg); + } + + var txp = {}; + + txp.outputs = [{ + 'toAddress': tx.toAddress, + 'amount': tx.toAmount, + 'message': tx.description + }]; + + if (tx.sendMaxInfo) { + txp.inputs = tx.sendMaxInfo.inputs; + txp.fee = tx.sendMaxInfo.fee; + } else { + txp.feeLevel = tx.feeLevel; + } + + txp.message = description; + + if (tx.paypro) { + txp.payProUrl = tx.paypro.url; + } + txp.excludeUnconfirmedUtxos = !tx.spendUnconfirmed; + txp.dryRun = dryRun; + walletService.createTx(wallet, txp, function(err, ctxp) { + if (err) { + setSendError(err); + return cb(err); + } + return cb(null, ctxp); + }); + }; + + + + function updateTx(tx, wallet, cb) { + + // Amount + tx.amountStr = txFormatService.formatAmountStr(tx.amount); + tx.amountValueStr = $scope.amountStr.split(' ')[0]; + tx.amountUnitStr = $scope.amountStr.split(' ')[1]; + txFormatService.formatAlternativeStr(tx.amount, function(v) { + tx.alternativeAmountStr = v; + }); + + $scope.tx = tx; + + + feeService.getFeeRate(tx.network, tx.feeLevel, function(err, feeRate) { + if (err) return cb(err); + + tx.feeRate = feeRate; + tx.feeLevelName = feeService.feeOpts[tx.feeLevel]; + + getSendMaxInfo(lodash.clone(tx), function(err, sendMaxInfo) { + if (err) { + var msg = gettextCatalog.getString('Error getting SendMax information'); + return setSendError(msg); + } + + if (sendMaxInfo) { + if (tx.sendMax && tx.sendMaxInfo.amount == 0) { + $scope.insufficientFunds = true; + popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee')); + return cb('no_funds'); + } + + tx.sendMaxInfo = resp; + tx.toAmount = parseFloat((tx.sendMaxInfo.amount * unitToSatoshi).toFixed(0)); + } + + getTxp(lodash.clone(tx), wallet, true, function(err, txp) { + if (err) return cb(err); + + if (tx.sendMaxInfo) + showSendMaxWarning(sendMaxInfo, function(err) {}); + + tx.feeStr = txFormatService.formatAmountStr(txp.fee); + txFormatService.formatAlternativeStr(txp.fee, function(v) { + tx.alternativeFeeStr = v; + }); + tx.feeRateStr = (txp.fee / (txp.amount + txp.fee) * 100).toFixed(2) + '%'; + + tx.txp = tx.txp || []; + tx.txp[wallet.id] = txp; + + return cb(); + }); + }); }); } function useSelectedWallet() { - if (!$scope.useSendMax) displayValues(); + + if (!$scope.useSendMax) { + showAmount(tx.toAmount); + } + $scope.onWalletSelect($scope.wallet); } - function applyButtonText(multisig) { - $scope.buttonText = $scope.isCordova ? gettextCatalog.getString('Slide') + ' ' : gettextCatalog.getString('Click') + ' '; + function setButtonText(isMultisig, isPayPro) { + $scope.buttonText = gettextCatalog.getString(isCordova ? 'Slide' : 'Click') + ' '; - if ($scope.paypro) { + if (isPayPro) { $scope.buttonText += gettextCatalog.getString('to pay'); - } else if (multisig) { + } else if (isMultisig) { $scope.buttonText += gettextCatalog.getString('to accept'); } else $scope.buttonText += gettextCatalog.getString('to send'); }; - function setwallets() { - $scope.wallets = profileService.getWallets({ - onlyComplete: true, - network: $scope.network - }); - - if (!$scope.wallets || !$scope.wallets.length) { - $scope.noMatchingWallet = true; - displayValues(); - $log.warn('No ' + $scope.network + ' wallets to make the payment'); - $timeout(function() { - $scope.$apply(); - }); - return; - } - - var filteredWallets = []; - var index = 0; - var enoughFunds = false; - var walletsUpdated = 0; - - lodash.each($scope.wallets, function(w) { - walletService.getStatus(w, {}, function(err, status) { - if (err || !status) { - $log.error(err); - } else { - walletsUpdated++; - w.status = status; - if (!status.availableBalanceSat) $log.debug('No balance available in: ' + w.name); - if (status.availableBalanceSat > toAmount) { - filteredWallets.push(w); - enoughFunds = true; - } - } - - if (++index == $scope.wallets.length) { - if (!lodash.isEmpty(filteredWallets)) { - $scope.wallets = lodash.clone(filteredWallets); - if ($scope.useSendMax) { - if ($scope.wallets.length > 1) - $scope.showWalletSelector(); - else { - $scope.wallet = $scope.wallets[0]; - $scope.getSendMaxInfo(); - } - } else initConfirm(); - } else { - - // Were we able to update any wallet? - if (walletsUpdated) { - if (!enoughFunds) $scope.insufficientFunds = true; - displayValues(); - $log.warn('No wallet available to make the payment'); - } else { - popupService.showAlert(gettextCatalog.getString('Could not update wallets'), bwcError.msg(err), function() { - $ionicHistory.nextViewOptions({ - disableAnimate: true, - historyRoot: true - }); - $ionicHistory.clearHistory(); - $state.go('tabs.send'); - }); - } - - } - $timeout(function() { - $scope.$apply(); - }); - } - }); - }); - }; $scope.toggleAddress = function() { $scope.showAddress = !$scope.showAddress; }; - var initConfirm = function() { - if ($scope.paypro) _paymentTimeControl($scope.paypro.expires); - displayValues(); - if ($scope.wallets.length > 1) $scope.showWalletSelector(); - else setWallet($scope.wallets[0]); - $timeout(function() { - $scope.$apply(); - }); - }; - - function displayValues() { - toAmount = parseInt(toAmount); - $scope.amountStr = txFormatService.formatAmountStr(toAmount); - $scope.displayAmount = getDisplayAmount($scope.amountStr); - $scope.displayUnit = getDisplayUnit($scope.amountStr); - txFormatService.formatAlternativeStr(toAmount, function(v) { - $scope.alternativeAmountStr = v; - }); - }; - - function resetValues() { + function resetView() { $scope.displayAmount = $scope.displayUnit = $scope.fee = $scope.feeFiat = $scope.feeRateStr = $scope.alternativeAmountStr = $scope.insufficientFunds = $scope.noMatchingWallet = null; $scope.showAddress = false; + + console.log('[confirm.js.213] RESET'); //TODO }; - $scope.getSendMaxInfo = function() { - resetValues(); - var config = configService.getSync().wallet; - ongoingProcess.set('retrievingInputs', true); - walletService.getSendMaxInfo($scope.wallet, { - feePerKb: feePerKb, - excludeUnconfirmedUtxos: !config.spendUnconfirmed, - returnInputs: true, - }, function(err, resp) { - ongoingProcess.set('retrievingInputs', false); - if (err) { - popupService.showAlert(gettextCatalog.getString('Error'), err); - return; + + function showSendMaxWarning(sendMaxInfo) { + + function verifyExcludedUtxos() { + var warningMsg = []; + if (sendMaxInfo.utxosBelowFee > 0) { + warningMsg.push(gettextCatalog.getString("A total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", { + amountBelowFeeStr: txFormatService.formatAmountStr(sendMaxInfo.amountBelowFee) + })); } - if (resp.amount == 0) { - $scope.insufficientFunds = true; - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee')); - return; + if (sendMaxInfo.utxosAboveMaxSize > 0) { + warningMsg.push(gettextCatalog.getString("A total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded.", { + amountAboveMaxSizeStr: txFormatService.formatAmountStr(sendMaxInfo.amountAboveMaxSize) + })); } + return warningMsg.join('\n'); + }; - $scope.sendMaxInfo = { - sendMax: true, - amount: resp.amount, - inputs: resp.inputs, - fee: resp.fee, - feePerKb: feePerKb, - }; - - cachedSendMax[$scope.wallet.id] = $scope.sendMaxInfo; - - var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", { - fee: txFormatService.formatAmountStr(resp.fee) - }); - var warningMsg = verifyExcludedUtxos(); - - if (!lodash.isEmpty(warningMsg)) - msg += '\n' + warningMsg; - - popupService.showAlert(null, msg, function() { - setSendMaxValues(resp); - - createTx($scope.wallet, true, function(err, txp) { - if (err) return; - cachedTxp[$scope.wallet.id] = txp; - apply(txp); - }); - }); - - function verifyExcludedUtxos() { - var warningMsg = []; - if (resp.utxosBelowFee > 0) { - warningMsg.push(gettextCatalog.getString("A total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", { - amountBelowFeeStr: txFormatService.formatAmountStr(resp.amountBelowFee) - })); - } - - if (resp.utxosAboveMaxSize > 0) { - warningMsg.push(gettextCatalog.getString("A total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded.", { - amountAboveMaxSizeStr: txFormatService.formatAmountStr(resp.amountAboveMaxSize) - })); - } - return warningMsg.join('\n'); - }; + var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", { + fee: txFormatService.formatAmountStr(sendMaxInfo.fee) }); + var warningMsg = verifyExcludedUtxos(); + + if (!lodash.isEmpty(warningMsg)) + msg += '\n' + warningMsg; + + popupService.showAlert(null, msg, function() {}); }; function setSendMaxValues(data) { - resetValues(); - var config = configService.getSync().wallet; - var unitToSatoshi = config.settings.unitToSatoshi; - var satToUnit = 1 / unitToSatoshi; - var unitDecimals = config.settings.unitDecimals; - + resetView(); $scope.amountStr = txFormatService.formatAmountStr(data.amount, true); $scope.displayAmount = getDisplayAmount($scope.amountStr); $scope.displayUnit = getDisplayUnit($scope.amountStr); @@ -272,27 +358,11 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.approve(); }); - $scope.showWalletSelector = function() { - $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); - if (!$scope.useSendMax && ($scope.insufficientFunds || $scope.noMatchingWallet)) return; - $scope.showWallets = true; - }; - $scope.onWalletSelect = function(wallet) { - if ($scope.useSendMax) { - $scope.wallet = wallet; - if (cachedSendMax[wallet.id]) { - $log.debug('Send max cached for wallet:', wallet.id); - setSendMaxValues(cachedSendMax[wallet.id]); - return; - } - $scope.getSendMaxInfo(); - } else - setWallet(wallet); - - applyButtonText(wallet.credentials.m > 1); + setWallet(wallet, tx); }; + // TODO $scope.showDescriptionPopup = function() { var message = gettextCatalog.getString('Add description'); var opts = { @@ -307,14 +377,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( }); }; - function getDisplayAmount(amountStr) { - return $scope.amountStr.split(' ')[0]; - }; - - function getDisplayUnit(amountStr) { - return $scope.amountStr.split(' ')[1]; - }; - function _paymentTimeControl(expirationTime) { $scope.paymentExpired.value = false; setExpirationTime(); @@ -347,31 +409,28 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; }; - function setWallet(wallet, delayed) { - var stop; + /* sets a wallet on the UI, creates a TXPs for that wallet */ + + function setWallet(wallet, tx) { + $scope.wallet = wallet; - $scope.fee = $scope.txp = null; - if (stop) { - $timeout.cancel(stop); - stop = null; - } - if (cachedTxp[wallet.id]) { - apply(cachedTxp[wallet.id]); - } else { - stop = $timeout(function() { - createTx(wallet, true, function(err, txp) { - if (err) return; - cachedTxp[wallet.id] = txp; - apply(txp); - }); - }, delayed ? 2000 : 1); - } + setButtonText(wallet.credentials.m > 1, !!tx.paypro); + + //T TODO + if ($scope.paypro) + _paymentTimeControl($scope.paypro.expires); + + updateTx(tx, wallet, function(err) { + if (err) return; + + $timeout(function() { + $ionicScrollDelegate.resize(); + $scope.$apply(); + }, 10); + + }); - $timeout(function() { - $ionicScrollDelegate.resize(); - $scope.$apply(); - }, 10); }; var setSendError = function(msg) { @@ -382,75 +441,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( popupService.showAlert(gettextCatalog.getString('Error at confirm'), bwcError.msg(msg)); }; - function apply(txp) { - $scope.fee = txFormatService.formatAmountStr(txp.fee); - txFormatService.formatAlternativeStr(txp.fee, function(v) { - $scope.feeFiat = v; - }); - $scope.txp = txp; - $scope.feeRateStr = (txp.fee / (txp.amount + txp.fee) * 100).toFixed(2) + '%'; - $timeout(function() { - $scope.$apply(); - }); - }; - - var createTx = function(wallet, dryRun, cb) { - var config = configService.getSync().wallet; - var currentSpendUnconfirmed = config.spendUnconfirmed; - var paypro = $scope.paypro; - var toAddress = $scope.toAddress; - var description = $scope.description; - var unitToSatoshi = config.settings.unitToSatoshi; - var unitDecimals = config.settings.unitDecimals; - - // ToDo: use a credential's (or fc's) function for this - if (description && !wallet.credentials.sharedEncryptingKey) { - var msg = gettextCatalog.getString('Could not add message to imported wallet without shared encrypting key'); - $log.warn(msg); - return setSendError(msg); - } - - if (toAmount > Number.MAX_SAFE_INTEGER) { - var msg = gettextCatalog.getString('Amount too big'); - $log.warn(msg); - return setSendError(msg); - } - - var txp = {}; - var amount; - - if ($scope.useSendMax) amount = parseFloat((toAmount * unitToSatoshi).toFixed(0)); - else amount = toAmount; - - txp.outputs = [{ - 'toAddress': toAddress, - 'amount': amount, - 'message': description - }]; - - if ($scope.sendMaxInfo) { - txp.inputs = $scope.sendMaxInfo.inputs; - txp.fee = $scope.sendMaxInfo.fee; - } else - txp.feeLevel = feeLevel; - - txp.message = description; - - if (paypro) { - txp.payProUrl = paypro.url; - } - txp.excludeUnconfirmedUtxos = !currentSpendUnconfirmed; - txp.dryRun = dryRun; - - walletService.createTx(wallet, txp, function(err, ctxp) { - if (err) { - setSendError(err); - return cb(err); - } - return cb(null, ctxp); - }); - }; - $scope.openPPModal = function() { $ionicModal.fromTemplateUrl('views/modals/paypro.html', { scope: $scope @@ -481,14 +471,11 @@ angular.module('copayApp.controllers').controller('confirmController', function( } ongoingProcess.set('creatingTx', true, onSendStatusChange); - createTx(wallet, false, function(err, txp) { + getTxp(wallet, false, function(err, txp) { ongoingProcess.set('creatingTx', false, onSendStatusChange); if (err) return; - var config = configService.getSync(); var spendingPassEnabled = walletService.isEncrypted(wallet); - var touchIdEnabled = config.touchIdFor && config.touchIdFor[wallet.id]; - var isCordova = $scope.isCordova; var bigAmount = parseFloat(txFormatService.formatToUSD(txp.amount)) > 20; var message = gettextCatalog.getString('Sending {{amountStr}} from your {{name}} wallet', { amountStr: $scope.amountStr, @@ -595,13 +582,12 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; $scope.hideModal = function(customFeeLevel) { if (customFeeLevel) { - cachedTxp = {}; - cachedSendMax = {}; ongoingProcess.set('gettingFeeLevels', true); - setFee(customFeeLevel, function() { + setAndShowFee(customFeeLevel, function() { ongoingProcess.set('gettingFeeLevels', false); - resetValues(); - if ($scope.wallet) useSelectedWallet(); + resetView(); + if ($scope.wallet) + useSelectedWallet(); }) } $scope.chooseFeeLevelModal.hide(); diff --git a/src/js/controllers/paperWallet.js b/src/js/controllers/paperWallet.js index 542a3a97d..321bb665f 100644 --- a/src/js/controllers/paperWallet.js +++ b/src/js/controllers/paperWallet.js @@ -60,7 +60,7 @@ angular.module('copayApp.controllers').controller('paperWalletController', $scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, null, function(err, testTx) { if (err) return cb(err); var rawTxLength = testTx.serialize().length; - feeService.getCurrentFeeValue('livenet', null, function(err, feePerKB) { + feeService.getCurrentFeeRate('livenet', null, function(err, feePerKB) { var opts = {}; opts.fee = Math.round((feePerKB * rawTxLength) / 2000); $scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, opts, function(err, tx) { diff --git a/src/js/services/bwcError.js b/src/js/services/bwcError.js index 9740af88e..417350868 100644 --- a/src/js/services/bwcError.js +++ b/src/js/services/bwcError.js @@ -110,7 +110,7 @@ angular.module('copayApp.services') body = gettextCatalog.getString('Amount below minimum allowed'); break; case 'INCORRECT_ADDRESS_NETWORK': - body = gettextCatalog.getString('Incorrect address network'); + body = gettextCatalog.getString('Incorrect network address'); break; case 'COPAYER_REGISTERED': body = gettextCatalog.getString('Key already associated with an existing wallet'); diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index 889ffb83e..8cc2654a5 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -1,8 +1,10 @@ 'use strict'; -angular.module('copayApp.services').factory('feeService', function($log, $stateParams, bwcService, walletService, configService, gettext, lodash, txFormatService, gettextCatalog) { +angular.module('copayApp.services').factory('feeService', function($log, $timeout, $stateParams, bwcService, walletService, configService, gettext, lodash, txFormatService, gettextCatalog) { var root = {}; + var CACHE_TIME_TS = 60; // 1 min + // Constant fee options to translate root.feeOpts = { urgent: gettext('Urgent'), @@ -12,22 +14,26 @@ angular.module('copayApp.services').factory('feeService', function($log, $stateP superEconomy: gettext('Super Economy') }; + var cache = { + updateTs: 0, + }; + root.getCurrentFeeLevel = function() { return configService.getSync().wallet.settings.feeLevel || 'normal'; }; - root.getCurrentFeeValue = function(network, customFeeLevel, cb) { + + root.getFeeRate = function(network, feeLevel, cb) { network = network || 'livenet'; - var feeLevel = customFeeLevel || root.getCurrentFeeLevel(); root.getFeeLevels(function(err, levels) { if (err) return cb(err); - var feeLevelValue = lodash.find(levels[network], { + var feeLevelRate = lodash.find(levels[network], { level: feeLevel }); - if (!feeLevelValue || !feeLevelValue.feePerKB) { + if (!feeLevelRate || !feeLevelRate.feePerKB) { return cb({ message: gettextCatalog.getString("Could not get dynamic fee for level: {{feeLevel}}", { feeLevel: feeLevel @@ -35,14 +41,26 @@ angular.module('copayApp.services').factory('feeService', function($log, $stateP }); } - var fee = feeLevelValue.feePerKB; - $log.debug('Dynamic fee: ' + feeLevel + ' ' + fee + ' SAT'); + var feeRate = feeLevelRate.feePerKB; + $log.debug('Dynamic fee: ' + feeLevel + ' ' + feeRate + ' SAT'); - return cb(null, fee); + return cb(null, feeRate); }); }; + root.getCurrentFeeRate = function(network, cb) { + return root.getFeeRate(network, root.getCurrentFeeLevel(), cb); + }; + root.getFeeLevels = function(cb) { + + if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000 ) { + $log.debug('Fee cache hit'); + $timeout( function() { + return cb(null, cache.data); + }, 1); + } + var walletClient = bwcService.getClient(); var unitName = configService.getSync().wallet.settings.unitName; @@ -51,10 +69,14 @@ angular.module('copayApp.services').factory('feeService', function($log, $stateP if (errLivenet || errTestnet) { return cb(gettextCatalog.getString('Could not get dynamic fee')); } - return cb(null, { + + cache.updateTs =Date.now(); + cache.data = { 'livenet': levelsLivenet, 'testnet': levelsTestnet - }); + }; + + return cb(null, cache.data); }); }); }; diff --git a/src/js/services/sendMax.js b/src/js/services/sendMax.js index fa716e260..142679f2a 100644 --- a/src/js/services/sendMax.js +++ b/src/js/services/sendMax.js @@ -10,7 +10,7 @@ angular.module('copayApp.services').service('sendMaxService', function(feeServic * */ this.getInfo = function(wallet, cb) { - feeService.getCurrentFeeValue(wallet.credentials.network, null, function(err, feePerKb) { + feeService.getCurrentFeeRate(wallet.credentials.network, null, function(err, feePerKb) { if (err) return cb(err); var config = configService.getSync().wallet; diff --git a/www/views/confirm.html b/www/views/confirm.html index 9fe71b8d2..761cb44b5 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -12,16 +12,16 @@
- Sending - Sending maximum amount + Sending + Sending maximum amount
-
{{displayAmount || '...'}} {{displayUnit}}
-
{{alternativeAmountStr || '...'}}
+
{{tx.amountValueStr || '...'}} {{tx.amountUnitStr}}
+
{{tx.alternativeAmountStr || '...'}}
-
+
Payment Expires: {{remainingTimeStr.value}} Expired @@ -32,36 +32,36 @@ -
- - {{toName}} +
+ + {{tx.toName}}
-
- - - {{paypro.domain || paypro.toAddress}} - {{toName}} +
+ + + {{tx.paypro.domain || tx.paypro.toAddress}} + {{tx.toName}}
-
-
- - {{toName}} +
+ + {{tx.toName}}
- - {{toName}} - {{toAddress}} + + {{tx.toName}} + {{tx.toAddress}}
- + From
@@ -78,17 +78,17 @@
- {{'Fee:' | translate}} {{feeLevel | translate}} - {{fee || '...'}} + {{'Fee:' | translate}} {{tx.feeLevel | translate}} + {{tx.fee || '...'}} - {{feeFiat || '...'}} - {{feeRateStr}} of the transaction + {{tx.alternativeFeeStr || '...'}} - {{tx.feeRatePerStr}} of the transaction
Add Memo - {{description}} + {{tx.description}} @@ -132,7 +132,7 @@ wallet-selector-title="walletSelectorTitle" wallet-selector-wallets="wallets" wallet-selector-selected-wallet="wallet" - wallet-selector-show="showWallets" + wallet-selector-show="walletSelector" wallet-selector-on-select="onWalletSelect"> From a5b547505713107ff869f756c726c9c761514da9 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Wed, 21 Jun 2017 10:21:32 -0300 Subject: [PATCH 06/84] Set any ip address for ionic serve --- app-template/package-template.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-template/package-template.json b/app-template/package-template.json index 01194e600..2da610c8b 100644 --- a/app-template/package-template.json +++ b/app-template/package-template.json @@ -81,7 +81,7 @@ }, "scripts": { "postinstall": "bower install", - "start": "npm run build:www && ionic serve --nolivereload --nogulp -s", + "start": "npm run build:www && ionic serve --nolivereload --nogulp -s --address 0.0.0.0", "start:ios": "npm run build:www && npm run build:ios && npm run open:ios", "start:android": "npm run build:www && npm run build:android && npm run run:android", "start:windows": "npm run build:www && npm run build:windows", From 5ee310ec50421e47c0d76ac69c60156c8f495fa3 Mon Sep 17 00:00:00 2001 From: JDonadio Date: Wed, 21 Jun 2017 11:11:40 -0300 Subject: [PATCH 07/84] modified in tx details --- src/js/controllers/modals/txpDetails.js | 5 ++--- src/js/controllers/tx-details.js | 19 +++++++++++++------ www/views/tx-details.html | 10 +++++----- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index b59c11897..bfab29089 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('txpDetailsController', function($scope, $rootScope, $timeout, $interval, $log, ongoingProcess, platformInfo, $ionicScrollDelegate, txFormatService, bwcError, gettextCatalog, lodash, walletService, popupService, $ionicHistory) { +angular.module('copayApp.controllers').controller('txpDetailsController', function($scope, $rootScope, $timeout, $interval, $log, ongoingProcess, platformInfo, $ionicScrollDelegate, txFormatService, bwcError, gettextCatalog, lodash, walletService, popupService, $ionicHistory, feeService) { var isGlidera = $scope.isGlidera; var GLIDERA_LOCK_TIME = 6 * 60 * 60; var now = Math.floor(Date.now() / 1000); @@ -27,8 +27,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.tx.feeFiatStr = v; }); $scope.tx.feeRateStr = ($scope.tx.fee / ($scope.tx.amount + $scope.tx.fee) * 100).toFixed(2) + '%'; - if ($scope.tx.feeLevel == 'superEconomy') $scope.tx.feeLevelStr = gettextCatalog.getString('Super Economy'); - else $scope.tx.feeLevelStr = $scope.tx.feeLevelStr = $scope.tx.feeLevel.charAt(0).toUpperCase() + $scope.tx.feeLevel.slice(1); + $scope.tx.feeLevelStr = feeService.feeOpts[$scope.tx.feeLevel]; }; function applyButtonText() { diff --git a/src/js/controllers/tx-details.js b/src/js/controllers/tx-details.js index 9416bbaee..5af36a0e0 100644 --- a/src/js/controllers/tx-details.js +++ b/src/js/controllers/tx-details.js @@ -11,10 +11,12 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio $scope.wallet = profileService.getWallet(data.stateParams.walletId); $scope.color = $scope.wallet.color; $scope.copayerId = $scope.wallet.credentials.copayerId; - $scope.isShared = $scope.wallet.credentials.n > 1; + $scope.isShared = $scope.wallet.credentials.n > 1; txConfirmNotification.checkIfEnabled(txId, function(res) { - $scope.txNotification = { value: res }; + $scope.txNotification = { + value: res + }; }); }); @@ -24,7 +26,9 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio listeners = [ $rootScope.$on('bwsEvent', function(e, walletId, type, n) { if (type == 'NewBlock' && n && n.data && n.data.network == 'livenet') { - updateTxDebounced({hideLoading: true}); + updateTxDebounced({ + hideLoading: true + }); } }) ]; @@ -108,7 +112,8 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio $scope.btx = txFormatService.processTx(tx); txFormatService.formatAlternativeStr(tx.fees, function(v) { - $scope.feeFiatStr = v; + $scope.btx.feeFiatStr = v; + $scope.btx.feeRateStr = ($scope.btx.fees / ($scope.btx.amount + $scope.btx.fees) * 100).toFixed(2) + '%'; }); if ($scope.btx.action != 'invalid') { @@ -130,7 +135,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio }; var updateTxDebounced = lodash.debounce(updateTx, 5000); - + $scope.showCommentPopup = function() { var opts = {}; if ($scope.btx.message) { @@ -194,7 +199,9 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio $scope.txConfirmNotificationChange = function() { if ($scope.txNotification.value) { - txConfirmNotification.subscribe($scope.wallet, { txid: txId }); + txConfirmNotification.subscribe($scope.wallet, { + txid: txId + }); } else { txConfirmNotification.unsubscribe($scope.wallet, txId); } diff --git a/www/views/tx-details.html b/www/views/tx-details.html index 18163cb88..a9fff2256 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -77,11 +77,11 @@
-
+
Fee - - {{btx.feeStr}} - {{feeFiatStr}} + {{btx.feeStr || '...'}} + + {{btx.feeFiatStr || '...'}} - {{btx.feeRateStr}} of the transaction
@@ -104,7 +104,7 @@
Notify me if confirmed From 442e64c20c29d7eab5dc8144c9f243b0e60ea9ff Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 21 Jun 2017 13:03:48 -0300 Subject: [PATCH 08/84] send working. SendMax / PayPro: todo --- src/js/controllers/confirm.js | 192 ++++++++++++++++++---------------- src/js/services/feeService.js | 8 +- www/views/confirm.html | 12 +-- 3 files changed, 114 insertions(+), 98 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 4e3a2765a..8b05888ee 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -3,6 +3,7 @@ angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError) { var countDown = null; + var CONFIRM_LIMIT_USD = 20; var tx = {}; @@ -66,7 +67,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( if (!status.availableBalanceSat) $log.debug('No balance available in: ' + w.name); - console.log('[confirm.js.68]', status.availableBalanceSat, minAmount); //TODO if (status.availableBalanceSat > minAmount) { filteredWallets.push(w); } @@ -106,6 +106,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( toEmail: data.stateParams.toEmail, toColor: data.stateParams.toColor, network: (new bitcore.Address(data.stateParams.toAddress)).network.name, + txp: {}, }; @@ -212,20 +213,28 @@ angular.module('copayApp.controllers').controller('confirmController', function( }); }; + function updateTx(tx, wallet, opts, cb) { - - function updateTx(tx, wallet, cb) { - - // Amount - tx.amountStr = txFormatService.formatAmountStr(tx.amount); - tx.amountValueStr = $scope.amountStr.split(' ')[0]; - tx.amountUnitStr = $scope.amountStr.split(' ')[1]; - txFormatService.formatAlternativeStr(tx.amount, function(v) { - tx.alternativeAmountStr = v; - }); + if (opts.clearCache) { + tx.txp = {}; + } $scope.tx = tx; + // Amount + tx.amountStr = txFormatService.formatAmountStr(tx.toAmount); + console.log('[confirm.js.217:tx:]', tx); //TODO + tx.amountValueStr = tx.amountStr.split(' ')[0]; + tx.amountUnitStr = tx.amountStr.split(' ')[1]; + txFormatService.formatAlternativeStr(tx.toAmount, function(v) { + tx.alternativeAmountStr = v; + }); + + + // inmediate refresh of know values + $timeout(function() { + $scope.$apply(); + }, 1); feeService.getFeeRate(tx.network, tx.feeLevel, function(err, feeRate) { if (err) return cb(err); @@ -250,20 +259,28 @@ angular.module('copayApp.controllers').controller('confirmController', function( tx.toAmount = parseFloat((tx.sendMaxInfo.amount * unitToSatoshi).toFixed(0)); } - getTxp(lodash.clone(tx), wallet, true, function(err, txp) { + + + // txp already generated for this wallet? + if (tx.txp[wallet.id]) + return cb(); + + getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) { if (err) return cb(err); if (tx.sendMaxInfo) showSendMaxWarning(sendMaxInfo, function(err) {}); - tx.feeStr = txFormatService.formatAmountStr(txp.fee); - txFormatService.formatAlternativeStr(txp.fee, function(v) { - tx.alternativeFeeStr = v; - }); - tx.feeRateStr = (txp.fee / (txp.amount + txp.fee) * 100).toFixed(2) + '%'; - tx.txp = tx.txp || []; + txp.feeStr = txFormatService.formatAmountStr(txp.fee); + txFormatService.formatAlternativeStr(txp.fee, function(v) { + txp.alternativeFeeStr = v; + }); + txp.feeRatePerStr = (txp.fee / (txp.amount + txp.fee) * 100).toFixed(2) + '%'; + + tx.txp[wallet.id] = txp; + $log.debug('Confirm. TX Fully Updated for wallet:' + wallet.id, tx); return cb(); }); @@ -362,15 +379,14 @@ angular.module('copayApp.controllers').controller('confirmController', function( setWallet(wallet, tx); }; - // TODO - $scope.showDescriptionPopup = function() { + $scope.showDescriptionPopup = function(tx) { var message = gettextCatalog.getString('Add description'); var opts = { - defaultText: $scope.description + defaultText: tx.description }; popupService.showPrompt(null, message, opts, function(res) { - if (typeof res != 'undefined') $scope.description = res; + if (typeof res != 'undefined') tx.description = res; $timeout(function() { $scope.$apply(); }); @@ -421,7 +437,9 @@ angular.module('copayApp.controllers').controller('confirmController', function( if ($scope.paypro) _paymentTimeControl($scope.paypro.expires); - updateTx(tx, wallet, function(err) { + updateTx(tx, wallet, { + dryRun: true + }, function(err) { if (err) return; $timeout(function() { @@ -454,14 +472,12 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.payproModal.hide(); }; - $scope.approve = function(onSendStatusChange) { + $scope.approve = function(tx, wallet, onSendStatusChange) { - var wallet = $scope.wallet; - if (!wallet) { - return; - } + if (!tx || !wallet) return; - if ($scope.paypro && $scope.paymentExpired.value) { + // TODO + if (tx.paypro && $scope.paymentExpired.value) { popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.')); $scope.sendStatus = ''; $timeout(function() { @@ -471,43 +487,57 @@ angular.module('copayApp.controllers').controller('confirmController', function( } ongoingProcess.set('creatingTx', true, onSendStatusChange); - getTxp(wallet, false, function(err, txp) { + getTxp(lodash.clone(tx), wallet, false, function(err, txp) { +console.log('[confirm.js.490:txp:]',txp); //TODO ongoingProcess.set('creatingTx', false, onSendStatusChange); if (err) return; - var spendingPassEnabled = walletService.isEncrypted(wallet); - var bigAmount = parseFloat(txFormatService.formatToUSD(txp.amount)) > 20; - var message = gettextCatalog.getString('Sending {{amountStr}} from your {{name}} wallet', { - amountStr: $scope.amountStr, - name: wallet.name - }); - var okText = gettextCatalog.getString('Confirm'); - var cancelText = gettextCatalog.getString('Cancel'); + // confirm txs for more that 20usd, if not spending/touchid is enabled + function confirmTx(cb) { + if (walletService.isEncrypted(wallet)) + return cb(); - if (!spendingPassEnabled && !touchIdEnabled) { - if (isCordova) { - if (bigAmount) { - popupService.showConfirm(null, message, okText, cancelText, function(ok) { - if (!ok) { - $scope.sendStatus = ''; - $timeout(function() { - $scope.$apply(); - }); - return; - } - publishAndSign(wallet, txp, onSendStatusChange); - }); - } else publishAndSign(wallet, txp, onSendStatusChange); - } else { - popupService.showConfirm(null, message, okText, cancelText, function(ok) { - if (!ok) { - $scope.sendStatus = ''; - return; - } - publishAndSign(wallet, txp, onSendStatusChange); - }); + var amountUsd = parseFloat(txFormatService.formatToUSD(txp.amount)); + if (amountUsd <= CONFIRM_LIMIT_USD) + return cb(); + + var message = gettextCatalog.getString('Sending {{amountStr}} from your {{name}} wallet', { + amountStr: tx.amountStr, + name: wallet.name + }); + var okText = gettextCatalog.getString('Confirm'); + var cancelText = gettextCatalog.getString('Cancel'); + popupService.showConfirm(null, message, okText, cancelText, function(ok) { + return cb(!ok); + }); + }; + + function publishAndSign() { + if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { + $log.info('No signing proposal: No private key'); + + return walletService.onlyPublish(wallet, txp, function(err) { + if (err) setSendError(err); + }, onSendStatusChange); } - } else publishAndSign(wallet, txp, onSendStatusChange); + + walletService.publishAndSign(wallet, txp, function(err, txp) { + if (err) return setSendError(err); + }, onSendStatusChange); + }; + + confirmTx(function(nok) { + if (nok) { + $scope.sendStatus = ''; + $timeout(function() { + $scope.$apply(); + }); + return; + } + +console.log('[confirm.js.541]'); //TODO + publishAndSign(); + }); }); }; @@ -553,24 +583,9 @@ angular.module('copayApp.controllers').controller('confirmController', function( }); }; - function publishAndSign(wallet, txp, onSendStatusChange) { + $scope.chooseFeeLevel = function(tx, wallet) { - if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { - $log.info('No signing proposal: No private key'); - - return walletService.onlyPublish(wallet, txp, function(err) { - if (err) setSendError(err); - }, onSendStatusChange); - } - - walletService.publishAndSign(wallet, txp, function(err, txp) { - if (err) return setSendError(err); - }, onSendStatusChange); - }; - - $scope.chooseFeeLevel = function() { - - $scope.customFeeLevel = feeLevel; + $scope.customFeeLevel = tx.feeLevel; $ionicModal.fromTemplateUrl('views/modals/chooseFeeLevel.html', { scope: $scope, }).then(function(modal) { @@ -581,16 +596,17 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.chooseFeeLevelModal.show(); }; $scope.hideModal = function(customFeeLevel) { - if (customFeeLevel) { - ongoingProcess.set('gettingFeeLevels', true); - setAndShowFee(customFeeLevel, function() { - ongoingProcess.set('gettingFeeLevels', false); - resetView(); - if ($scope.wallet) - useSelectedWallet(); - }) - } - $scope.chooseFeeLevelModal.hide(); + $log.debug('Custom fee level choosen:' + customFeeLevel + ' was:' + tx.feeLevel); + if (tx.feeLevel == customFeeLevel) + $scope.chooseFeeLevelModal.hide(); + + tx.feeLevel = customFeeLevel; + updateTx(tx, wallet, { + clearCache: true, + dryRun: true, + }, function() { + $scope.chooseFeeLevelModal.hide(); + }); }; }; diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index 8cc2654a5..c88b867ca 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -26,7 +26,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou root.getFeeRate = function(network, feeLevel, cb) { network = network || 'livenet'; - root.getFeeLevels(function(err, levels) { + root.getFeeLevels(function(err, levels, fromCache) { if (err) return cb(err); var feeLevelRate = lodash.find(levels[network], { @@ -42,7 +42,8 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou } var feeRate = feeLevelRate.feePerKB; - $log.debug('Dynamic fee: ' + feeLevel + ' ' + feeRate + ' SAT'); + + if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network +' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B'); return cb(null, feeRate); }); @@ -55,9 +56,8 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou root.getFeeLevels = function(cb) { if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000 ) { - $log.debug('Fee cache hit'); $timeout( function() { - return cb(null, cache.data); + return cb(null, cache.data, true); }, 1); } diff --git a/www/views/confirm.html b/www/views/confirm.html index 761cb44b5..496e5a8e9 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -77,15 +77,15 @@
-
- {{'Fee:' | translate}} {{tx.feeLevel | translate}} - {{tx.fee || '...'}} +
+ {{'Fee:' | translate}} {{tx.feeLevelName | translate}} + {{tx.txp[wallet.id].feeStr || '...'}} - {{tx.alternativeFeeStr || '...'}} - {{tx.feeRatePerStr}} of the transaction + {{tx.txp[wallet.id].alternativeFeeStr || '...'}} - {{tx.txp[wallet.id].feeRatePerStr}} of the transaction
- + Add Memo {{tx.description}} @@ -102,7 +102,7 @@
Date: Wed, 21 Jun 2017 17:09:33 -0300 Subject: [PATCH 09/84] better fee service --- src/js/controllers/confirm.js | 88 +++++++++++++-------------- src/js/controllers/preferencesFee.js | 28 +++++---- src/js/directives/clickToAccept.js | 4 +- www/views/confirm.html | 27 +++----- www/views/includes/clickToAccept.html | 2 +- www/views/modals/chooseFeeLevel.html | 10 ++- 6 files changed, 77 insertions(+), 82 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 8b05888ee..6de5b749d 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -34,6 +34,28 @@ angular.module('copayApp.controllers').controller('confirmController', function( $ionicConfig.views.swipeBackEnabled(false); }); + + function exitWithError(err) { + $log.info('Error setting wallet selector:' + err); + popupService.showAlert(gettextCatalog.getString(), bwcError.msg(err), function() { + $ionicHistory.nextViewOptions({ + disableAnimate: true, + historyRoot: true + }); + $ionicHistory.clearHistory(); + $state.go('tabs.send'); + }); + }; + + function setNoWallet(msg) { + $scope.wallet = null; + $scope.noWalletMessage = gettextCatalog.getString(msg); + $log.warn('Not ready to make the payment:' + msg); + $timeout(function() { + $scope.$apply(); + }); + }; + $scope.$on("$ionicView.beforeEnter", function(event, data) { function setWalletSelector(minAmount, cb) { @@ -44,12 +66,8 @@ angular.module('copayApp.controllers').controller('confirmController', function( }); if (!$scope.wallets || !$scope.wallets.length) { - $scope.noMatchingWallet = true; - $log.warn('No ' + $scope.network + ' wallets to make the payment'); - $timeout(function() { - $scope.$apply(); - }); - return; + setNoWallet('No wallets available'); + return cb(); } var filteredWallets = []; @@ -77,8 +95,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( return cb('Could not update any wallet'); if (lodash.isEmpty(filteredWallets)) { - $scope.insufficientFunds = true; - $log.warn('No wallet available to make the payment'); + setNoWallet('Insufficent funds'); } $scope.wallets = lodash.clone(filteredWallets); return cb(); @@ -114,7 +131,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.isCordova = isCordova; $scope.showAddress = false; $scope.insufficientFunds = false; - $scope.noMatchingWallet = false; $scope.paymentExpired = { value: false }; @@ -122,29 +138,16 @@ angular.module('copayApp.controllers').controller('confirmController', function( value: null }; - $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); - console.log('[confirm.js.126:tx:]', tx); //TODO - setWalletSelector(tx.toAmount, function(err) { if (err) { - $log.debug('Error updating wallets:' + err); - popupService.showAlert(gettextCatalog.getString('Could not update wallets'), bwcError.msg(err), function() { - $ionicHistory.nextViewOptions({ - disableAnimate: true, - historyRoot: true - }); - $ionicHistory.clearHistory(); - $state.go('tabs.send'); - }); + return exitWithError('Could not update wallets'); } - $log.debug('Wallet selector is setup'); - if ($scope.wallets.length > 1) { $scope.showWalletSelector(); - } else { + } else if ($scope.wallets.length) { setWallet($scope.wallets[0], tx); } }); @@ -314,15 +317,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; - function resetView() { - $scope.displayAmount = $scope.displayUnit = $scope.fee = $scope.feeFiat = $scope.feeRateStr = $scope.alternativeAmountStr = $scope.insufficientFunds = $scope.noMatchingWallet = null; - $scope.showAddress = false; - - console.log('[confirm.js.213] RESET'); //TODO - }; - - - function showSendMaxWarning(sendMaxInfo) { function verifyExcludedUtxos() { @@ -353,7 +347,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; function setSendMaxValues(data) { - resetView(); $scope.amountStr = txFormatService.formatAmountStr(data.amount, true); $scope.displayAmount = getDisplayAmount($scope.amountStr); $scope.displayUnit = getDisplayUnit($scope.amountStr); @@ -488,7 +481,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( ongoingProcess.set('creatingTx', true, onSendStatusChange); getTxp(lodash.clone(tx), wallet, false, function(err, txp) { -console.log('[confirm.js.490:txp:]',txp); //TODO ongoingProcess.set('creatingTx', false, onSendStatusChange); if (err) return; @@ -534,8 +526,6 @@ console.log('[confirm.js.490:txp:]',txp); //TODO }); return; } - -console.log('[confirm.js.541]'); //TODO publishAndSign(); }); }); @@ -585,27 +575,33 @@ console.log('[confirm.js.541]'); //TODO $scope.chooseFeeLevel = function(tx, wallet) { - $scope.customFeeLevel = tx.feeLevel; + + var scope = $rootScope.$new(true); + scope.network = tx.network; + scope.feeLevel = tx.feeLevel; + scope.noSave = true; + $ionicModal.fromTemplateUrl('views/modals/chooseFeeLevel.html', { - scope: $scope, + scope: scope, }).then(function(modal) { - $scope.chooseFeeLevelModal = modal; - $scope.openModal(); + scope.chooseFeeLevelModal = modal; + scope.openModal(); }); - $scope.openModal = function() { - $scope.chooseFeeLevelModal.show(); + scope.openModal = function() { + scope.chooseFeeLevelModal.show(); }; - $scope.hideModal = function(customFeeLevel) { + + scope.hideModal = function(customFeeLevel) { $log.debug('Custom fee level choosen:' + customFeeLevel + ' was:' + tx.feeLevel); if (tx.feeLevel == customFeeLevel) - $scope.chooseFeeLevelModal.hide(); + scope.chooseFeeLevelModal.hide(); tx.feeLevel = customFeeLevel; updateTx(tx, wallet, { clearCache: true, dryRun: true, }, function() { - $scope.chooseFeeLevelModal.hide(); + scope.chooseFeeLevelModal.hide(); }); }; }; diff --git a/src/js/controllers/preferencesFee.js b/src/js/controllers/preferencesFee.js index 6ac32a1bf..c08932cd2 100644 --- a/src/js/controllers/preferencesFee.js +++ b/src/js/controllers/preferencesFee.js @@ -2,13 +2,14 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', function($scope, $timeout, $ionicHistory, lodash, gettextCatalog, configService, feeService, ongoingProcess, popupService) { - $scope.save = function(newFee) { + var network; - if ($scope.customFeeLevel) { - $scope.currentFeeLevel = newFee; - updateCurrentValues(); + $scope.save = function(newFee) { + $scope.currentFeeLevel = newFee; + updateCurrentValues(); + + if ($scope.noSave) return; - } var opts = { wallet: { @@ -20,8 +21,6 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu configService.set(opts, function(err) { if (err) $log.debug(err); - $scope.currentFeeLevel = newFee; - updateCurrentValues(); $timeout(function() { $scope.$apply(); }); @@ -33,8 +32,10 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu }); $scope.init = function() { + + $scope.network = $scope.network || 'livenet'; $scope.feeOpts = feeService.feeOpts; - $scope.currentFeeLevel = $scope.customFeeLevel ? $scope.customFeeLevel : feeService.getCurrentFeeLevel(); + $scope.currentFeeLevel = $scope.feeLevel || feeService.getCurrentFeeLevel(); $scope.loadingFee = true; feeService.getFeeLevels(function(err, levels) { $scope.loadingFee = false; @@ -51,16 +52,19 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu var updateCurrentValues = function() { if (lodash.isEmpty($scope.feeLevels) || lodash.isEmpty($scope.currentFeeLevel)) return; - var feeLevelValue = lodash.find($scope.feeLevels['livenet'], { + + var value = lodash.find($scope.feeLevels[$scope.network], { level: $scope.currentFeeLevel }); - if (lodash.isEmpty(feeLevelValue)) { + + if (lodash.isEmpty(value)) { $scope.feePerSatByte = null; $scope.avgConfirmationTime = null; return; } - $scope.feePerSatByte = (feeLevelValue.feePerKB / 1000).toFixed(); - $scope.avgConfirmationTime = feeLevelValue.nbBlocks * 10; + + $scope.feePerSatByte = (value.feePerKB / 1000).toFixed(); + $scope.avgConfirmationTime = value.nbBlocks * 10; }; $scope.chooseNewFee = function() { diff --git a/src/js/directives/clickToAccept.js b/src/js/directives/clickToAccept.js index 2127075dd..bb31b45b4 100644 --- a/src/js/directives/clickToAccept.js +++ b/src/js/directives/clickToAccept.js @@ -8,9 +8,7 @@ angular.module('copayApp.directives') transclude: true, scope: { sendStatus: '=clickSendStatus', - hasWalletChosen: '=hasWalletChosen', - insufficientFunds: '=insufficientFunds', - noMatchingWallet: '=noMatchingWallet' + isDisabled: '=isDisabled', }, link: function(scope, element, attrs) { scope.$watch('sendStatus', function() { diff --git a/www/views/confirm.html b/www/views/confirm.html index 496e5a8e9..ae8158ba9 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -7,7 +7,7 @@ - +
@@ -61,7 +61,7 @@ {{tx.toAddress}}
-
+ From
@@ -77,26 +77,23 @@
-
+
{{'Fee:' | translate}} {{tx.feeLevelName | translate}} {{tx.txp[wallet.id].feeStr || '...'}} - {{tx.txp[wallet.id].alternativeFeeStr || '...'}} - {{tx.txp[wallet.id].feeRatePerStr}} of the transaction + {{tx.txp[wallet.id].alternativeFeeStr || '...'}} - {{tx.txp[wallet.id].feeRatePerStr}} of the transaction
- + Add Memo {{tx.description}} -
- No wallets available -
-
- Insufficient funds +
+ {{noWalletMessage}}
@@ -105,18 +102,14 @@ ng-click="approve(tx, wallet, statusChangeHandler)" ng-if="!isCordova" click-send-status="sendStatus" - has-wallet-chosen="wallet" - insufficient-funds="insufficientFunds" - no-matching-wallet="noMatchingWallet"> + is-disabled="!wallet"> {{buttonText}} + is-disabled="!wallet"> {{buttonText}} +
- +
@@ -20,6 +20,7 @@ {{feePerSatByte}} satoshis/byte ...
+
[{{network}}]
@@ -28,7 +29,10 @@
- +
From 54b554d279612a9d810c57646867e66fe3708794 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 21 Jun 2017 18:29:03 -0300 Subject: [PATCH 10/84] send max working --- src/js/controllers/confirm.js | 64 ++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 6de5b749d..c8c297e88 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -58,11 +58,14 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.$on("$ionicView.beforeEnter", function(event, data) { - function setWalletSelector(minAmount, cb) { - console.log('[confirm.js.38:minAmount:]', minAmount); //TODO + function setWalletSelector(network, minAmount, cb) { + + // no min amount? (sendMax) => look for no empty wallets + minAmount = minAmount || 1; + $scope.wallets = profileService.getWallets({ onlyComplete: true, - network: $scope.network + network: network }); if (!$scope.wallets || !$scope.wallets.length) { @@ -130,7 +133,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( // Other Scope vars $scope.isCordova = isCordova; $scope.showAddress = false; - $scope.insufficientFunds = false; $scope.paymentExpired = { value: false }; @@ -140,7 +142,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); - setWalletSelector(tx.toAmount, function(err) { + setWalletSelector(tx.network, tx.toAmount, function(err) { if (err) { return exitWithError('Could not update wallets'); } @@ -154,7 +156,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( }); - function getSendMaxInfo(tx, cb) { + function getSendMaxInfo(tx, wallet, cb) { if (!tx.sendMax) return cb(); //ongoingProcess.set('retrievingInputs', true); @@ -224,20 +226,26 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.tx = tx; - // Amount - tx.amountStr = txFormatService.formatAmountStr(tx.toAmount); - console.log('[confirm.js.217:tx:]', tx); //TODO - tx.amountValueStr = tx.amountStr.split(' ')[0]; - tx.amountUnitStr = tx.amountStr.split(' ')[1]; - txFormatService.formatAlternativeStr(tx.toAmount, function(v) { - tx.alternativeAmountStr = v; - }); + function refresh() { + $timeout(function() { + $scope.$apply(); + }, 1); + } + function updateAmount() { + if (!tx.toAmount) return; - // inmediate refresh of know values - $timeout(function() { - $scope.$apply(); - }, 1); + // Amount + tx.amountStr = txFormatService.formatAmountStr(tx.toAmount); + tx.amountValueStr = tx.amountStr.split(' ')[0]; + tx.amountUnitStr = tx.amountStr.split(' ')[1]; + txFormatService.formatAlternativeStr(tx.toAmount, function(v) { + tx.alternativeAmountStr = v; + }); + } + + updateAmount(); + refresh(); feeService.getFeeRate(tx.network, tx.feeLevel, function(err, feeRate) { if (err) return cb(err); @@ -245,24 +253,27 @@ angular.module('copayApp.controllers').controller('confirmController', function( tx.feeRate = feeRate; tx.feeLevelName = feeService.feeOpts[tx.feeLevel]; - getSendMaxInfo(lodash.clone(tx), function(err, sendMaxInfo) { + getSendMaxInfo(lodash.clone(tx), wallet, function(err, sendMaxInfo) { if (err) { var msg = gettextCatalog.getString('Error getting SendMax information'); return setSendError(msg); } if (sendMaxInfo) { - if (tx.sendMax && tx.sendMaxInfo.amount == 0) { - $scope.insufficientFunds = true; + + $log.debug('Send max info', sendMaxInfo); + + if (tx.sendMax && sendMaxInfo.amount == 0) { + setNoWallet('Insufficent funds'); popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee')); return cb('no_funds'); } - tx.sendMaxInfo = resp; - tx.toAmount = parseFloat((tx.sendMaxInfo.amount * unitToSatoshi).toFixed(0)); + tx.sendMaxInfo = sendMaxInfo; + tx.toAmount =tx.sendMaxInfo.amount; + updateAmount(); } - - + refresh(); // txp already generated for this wallet? if (tx.txp[wallet.id]) @@ -274,7 +285,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( if (tx.sendMaxInfo) showSendMaxWarning(sendMaxInfo, function(err) {}); - txp.feeStr = txFormatService.formatAmountStr(txp.fee); txFormatService.formatAlternativeStr(txp.fee, function(v) { txp.alternativeFeeStr = v; @@ -433,8 +443,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( updateTx(tx, wallet, { dryRun: true }, function(err) { - if (err) return; - $timeout(function() { $ionicScrollDelegate.resize(); $scope.$apply(); From 13b8b81e1131a3a12ef76c95871eadc9ead8a835 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 00:46:35 -0300 Subject: [PATCH 11/84] fix paypro --- src/js/controllers/confirm.js | 68 ++++++++++++++++++----------------- www/views/confirm.html | 8 ++--- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index c8c297e88..780f30171 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -22,8 +22,16 @@ angular.module('copayApp.controllers').controller('confirmController', function( var isCordova = platformInfo.isCordova; + function refresh() { + $timeout(function() { + $scope.$apply(); + }, 1); + } + + $scope.showWalletSelector = function() { $scope.walletSelector = true; + refresh(); }; $scope.$on("$ionicView.beforeLeave", function(event, data) { @@ -61,7 +69,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( function setWalletSelector(network, minAmount, cb) { // no min amount? (sendMax) => look for no empty wallets - minAmount = minAmount || 1; + minAmount = minAmount || 1; $scope.wallets = profileService.getWallets({ onlyComplete: true, @@ -133,25 +141,23 @@ angular.module('copayApp.controllers').controller('confirmController', function( // Other Scope vars $scope.isCordova = isCordova; $scope.showAddress = false; - $scope.paymentExpired = { - value: false - }; - $scope.remainingTimeStr = { - value: null - }; - $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); + updateTx(tx, null, {}, function() { - setWalletSelector(tx.network, tx.toAmount, function(err) { - if (err) { - return exitWithError('Could not update wallets'); - } + $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); + + setWalletSelector(tx.network, tx.toAmount, function(err) { + if (err) { + return exitWithError('Could not update wallets'); + } + + if ($scope.wallets.length > 1) { + $scope.showWalletSelector(); + } else if ($scope.wallets.length) { + setWallet($scope.wallets[0], tx); + } + }); - if ($scope.wallets.length > 1) { - $scope.showWalletSelector(); - } else if ($scope.wallets.length) { - setWallet($scope.wallets[0], tx); - } }); }); @@ -226,12 +232,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.tx = tx; - function refresh() { - $timeout(function() { - $scope.$apply(); - }, 1); - } - function updateAmount() { if (!tx.toAmount) return; @@ -253,6 +253,10 @@ angular.module('copayApp.controllers').controller('confirmController', function( tx.feeRate = feeRate; tx.feeLevelName = feeService.feeOpts[tx.feeLevel]; + // End of quick refresh, before wallet is selected. + if (!wallet) + return cb(); + getSendMaxInfo(lodash.clone(tx), wallet, function(err, sendMaxInfo) { if (err) { var msg = gettextCatalog.getString('Error getting SendMax information'); @@ -270,7 +274,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( } tx.sendMaxInfo = sendMaxInfo; - tx.toAmount =tx.sendMaxInfo.amount; + tx.toAmount = tx.sendMaxInfo.amount; updateAmount(); } refresh(); @@ -397,7 +401,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; function _paymentTimeControl(expirationTime) { - $scope.paymentExpired.value = false; + $scope.paymentExpired = false; setExpirationTime(); countDown = $interval(function() { @@ -415,12 +419,12 @@ angular.module('copayApp.controllers').controller('confirmController', function( var totalSecs = expirationTime - now; var m = Math.floor(totalSecs / 60); var s = totalSecs % 60; - $scope.remainingTimeStr.value = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2); + $scope.remainingTimeStr = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2); }; function setExpiredValues() { - $scope.paymentExpired.value = true; - $scope.remainingTimeStr.value = gettextCatalog.getString('Expired'); + $scope.paymentExpired = true; + $scope.remainingTimeStr = gettextCatalog.getString('Expired'); if (countDown) $interval.cancel(countDown); $timeout(function() { $scope.$apply(); @@ -436,9 +440,8 @@ angular.module('copayApp.controllers').controller('confirmController', function( setButtonText(wallet.credentials.m > 1, !!tx.paypro); - //T TODO - if ($scope.paypro) - _paymentTimeControl($scope.paypro.expires); + if (tx.paypro) + _paymentTimeControl(tx.paypro.expires); updateTx(tx, wallet, { dryRun: true @@ -477,8 +480,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( if (!tx || !wallet) return; - // TODO - if (tx.paypro && $scope.paymentExpired.value) { + if ($scope.paymentExpired) { popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.')); $scope.sendStatus = ''; $timeout(function() { diff --git a/www/views/confirm.html b/www/views/confirm.html index ae8158ba9..c576c1320 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -23,8 +23,8 @@
Payment Expires: - {{remainingTimeStr.value}} - Expired + {{remainingTimeStr}} + Expired
@@ -61,7 +61,7 @@ {{tx.toAddress}}
- + From
@@ -92,7 +92,7 @@ -
+
{{noWalletMessage}}
From dadd89e32299a7242a2cf4fea0f9b678db38d586 Mon Sep 17 00:00:00 2001 From: JDonadio Date: Thu, 22 Jun 2017 10:39:09 -0300 Subject: [PATCH 12/84] only on sent txs --- www/views/tx-details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/views/tx-details.html b/www/views/tx-details.html index a9fff2256..5af45c3aa 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -77,7 +77,7 @@
-
+
Fee {{btx.feeStr || '...'}} From 748e8a4fbb375b735c16c2a1f8aa59bca8b7415a Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 22 Jun 2017 11:49:20 -0300 Subject: [PATCH 13/84] Ref confirm. Removes unused code. Fix noLowFee directive --- src/js/controllers/confirm.js | 42 ++++-------------------------- src/js/directives/noLowFee.js | 2 +- src/js/directives/slideToAccept.js | 2 +- www/views/buyAmazon.html | 10 ++----- www/views/buyCoinbase.html | 14 +++------- www/views/buyGlidera.html | 14 +++------- www/views/confirm.html | 2 +- www/views/modals/paypro.html | 32 +++++++++++------------ www/views/sellCoinbase.html | 24 +++++++---------- www/views/sellGlidera.html | 14 +++------- www/views/topup.html | 12 +++------ 11 files changed, 50 insertions(+), 118 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 780f30171..3bfb55581 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -176,12 +176,8 @@ angular.module('copayApp.controllers').controller('confirmController', function( function getTxp(tx, wallet, dryRun, cb) { - var paypro = tx.paypro; - var toAddress = tx.toAddress; - var description = tx.description; - // ToDo: use a credential's (or fc's) function for this - if (description && !wallet.credentials.sharedEncryptingKey) { + if (tx.description && !wallet.credentials.sharedEncryptingKey) { var msg = gettextCatalog.getString('Could not add message to imported wallet without shared encrypting key'); $log.warn(msg); return setSendError(msg); @@ -208,7 +204,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( txp.feeLevel = tx.feeLevel; } - txp.message = description; + txp.message = tx.description; if (tx.paypro) { txp.payProUrl = tx.paypro.url; @@ -254,7 +250,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( tx.feeLevelName = feeService.feeOpts[tx.feeLevel]; // End of quick refresh, before wallet is selected. - if (!wallet) + if (!wallet) return cb(); getSendMaxInfo(lodash.clone(tx), wallet, function(err, sendMaxInfo) { @@ -276,6 +272,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( tx.sendMaxInfo = sendMaxInfo; tx.toAmount = tx.sendMaxInfo.amount; updateAmount(); + showSendMaxWarning(sendMaxInfo); } refresh(); @@ -286,9 +283,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) { if (err) return cb(err); - if (tx.sendMaxInfo) - showSendMaxWarning(sendMaxInfo, function(err) {}); - txp.feeStr = txFormatService.formatAmountStr(txp.fee); txFormatService.formatAlternativeStr(txp.fee, function(v) { txp.alternativeFeeStr = v; @@ -360,24 +354,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( popupService.showAlert(null, msg, function() {}); }; - function setSendMaxValues(data) { - $scope.amountStr = txFormatService.formatAmountStr(data.amount, true); - $scope.displayAmount = getDisplayAmount($scope.amountStr); - $scope.displayUnit = getDisplayUnit($scope.amountStr); - $scope.fee = txFormatService.formatAmountStr(data.fee); - txFormatService.formatAlternativeStr(data.fee, function(v) { - $scope.feeFiat = v; - }); - toAmount = parseFloat((data.amount * satToUnit).toFixed(unitDecimals)); - txFormatService.formatAlternativeStr(data.amount, function(v) { - $scope.alternativeAmountStr = v; - }); - $scope.feeRateStr = (data.fee / (data.amount + data.fee) * 100).toFixed(2) + '%'; - $timeout(function() { - $scope.$apply(); - }); - }; - $scope.$on('accepted', function(event) { $scope.approve(); }); @@ -565,27 +541,19 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; $scope.onSuccessConfirm = function() { - var previousView = $ionicHistory.viewHistory().backView && $ionicHistory.viewHistory().backView.stateName; - - $ionicHistory.nextViewOptions({ - disableAnimate: true - }); - $ionicHistory.removeBackView(); $scope.sendStatus = ''; - $ionicHistory.nextViewOptions({ disableAnimate: true, historyRoot: true }); - $ionicHistory.clearHistory(); $state.go('tabs.send').then(function() { + $ionicHistory.clearHistory(); $state.transitionTo('tabs.home'); }); }; $scope.chooseFeeLevel = function(tx, wallet) { - var scope = $rootScope.$new(true); scope.network = tx.network; scope.feeLevel = tx.feeLevel; diff --git a/src/js/directives/noLowFee.js b/src/js/directives/noLowFee.js index b332272e5..68046056b 100644 --- a/src/js/directives/noLowFee.js +++ b/src/js/directives/noLowFee.js @@ -12,7 +12,7 @@ angular.module('copayApp.directives') elem.bind('click', function() { configService.whenAvailable(function(config) { - if (config.wallet.settings.feeLevel.match(/conomy/)) { + if (config.wallet.settings.feeLevel && config.wallet.settings.feeLevel.match(/conomy/)) { $log.debug('Economy Fee setting... disabling link:' + elem.text()); popupService.showAlert('Low Fee Error', 'Please change your Bitcoin Network Fee Policy setting to Normal or higher to use this service', function() { $ionicHistory.goBack(); diff --git a/src/js/directives/slideToAccept.js b/src/js/directives/slideToAccept.js index e57aaecff..3f4db0ef9 100644 --- a/src/js/directives/slideToAccept.js +++ b/src/js/directives/slideToAccept.js @@ -9,7 +9,7 @@ angular.module('copayApp.directives') scope: { sendStatus: '=slideSendStatus', onConfirm: '&slideOnConfirm', - wallet: '=hasWalletChosen' + isDisabled: '=isDisabled' }, link: function(scope, element, attrs) { diff --git a/www/views/buyAmazon.html b/www/views/buyAmazon.html index 03e2e4063..04440fa9e 100644 --- a/www/views/buyAmazon.html +++ b/www/views/buyAmazon.html @@ -53,23 +53,17 @@ + is-disabled="!wallet"> Confirm purchase + is-disabled="!wallet"> Slide to buy
{{amountUnitStr}}
- {{buyRequestInfo.amount.amount}} {{buyRequestInfo.amount.currency}} + {{buyRequestInfo.amount.amount}} {{buyRequestInfo.amount.currency}} @ ${{buyPrice.amount}} per BTC
@@ -59,7 +59,7 @@ {{fee.type}} fee - {{fee.amount.amount}} {{fee.amount.currency}} + {{fee.amount.amount}} {{fee.amount.currency}}
@@ -74,23 +74,17 @@ + is-disabled="!selectedPaymentMethodId.value || !buyRequestInfo || !wallet"> Confirm purchase + is-disabled="!selectedPaymentMethodId.value || !buyRequestInfo || !wallet"> Slide to buy
{{amountUnitStr}}
- {{buyInfo.subtotal}} {{buyInfo.currency}} - {{buyInfo.qty}} BTC + {{buyInfo.subtotal}} {{buyInfo.currency}} + {{buyInfo.qty}} BTC @ ${{buyInfo.price}} per BTC
@@ -64,23 +64,17 @@ + is-disabled="!buyInfo || !wallet"> Confirm purchase + is-disabled="!buyInfo || !wallet"> Slide to buy - +
diff --git a/www/views/modals/paypro.html b/www/views/modals/paypro.html index 78dd4380a..18e3ae670 100644 --- a/www/views/modals/paypro.html +++ b/www/views/modals/paypro.html @@ -9,51 +9,51 @@
-
{{displayAmount || '...'}} {{displayUnit}}
-
{{alternativeAmountStr || '...'}}
+
{{tx.amountValueStr || '...'}} {{tx.amountUnitStr}}
+
{{tx.alternativeAmountStr || '...'}}
-
+
{{'Pay To'|translate}} - {{paypro.domain}} + {{tx.paypro.domain}}
-
+
{{'Address'|translate}} - {{paypro.toAddress}} + {{tx.paypro.toAddress}}
{{'Certified by'|translate}} - + - {{paypro.caName}} {{'(Trusted)' | translate}} + {{tx.paypro.caName}} {{'(Trusted)' | translate}} - - + + Self-signed Certificate - - {{paypro.caName}}
+ + {{tx.paypro.caName}}
WARNING: UNTRUSTED CERTIFICATE
-
+
{{'Memo'|translate}} - {{paypro.memo}} + {{tx.paypro.memo}}
-
+
{{'Expires'|translate}} - {{paypro.expires * 1000 | amTimeAgo }} + {{tx.paypro.expires * 1000 | amTimeAgo }}
diff --git a/www/views/sellCoinbase.html b/www/views/sellCoinbase.html index dffd935fe..5827efda6 100644 --- a/www/views/sellCoinbase.html +++ b/www/views/sellCoinbase.html @@ -17,11 +17,11 @@
{{amountUnitStr}}
- {{sellRequestInfo.amount.amount}} {{sellRequestInfo.amount.currency}} + {{sellRequestInfo.amount.amount}} {{sellRequestInfo.amount.currency}} @ ${{sellPrice.amount}} per BTC
-
+
@@ -62,16 +62,16 @@ will be sent to your Coinbase account, and sold when Coinbase accepts the transaction (usually one hour).
-
Estimated sale value: +
Estimated sale value: - {{sellRequestInfo.total.amount | currency : '' : 2}} + {{sellRequestInfo.total.amount | currency : '' : 2}} {{sellRequestInfo.total.currency}}
-
Still sell if price fall until: +
Still sell if price fall until: - {{(sellRequestInfo.total.amount - - (selectedPriceSensitivity.data.value / 100) * sellRequestInfo.total.amount) | currency : '' : 2}} + {{(sellRequestInfo.total.amount - + (selectedPriceSensitivity.data.value / 100) * sellRequestInfo.total.amount) | currency : '' : 2}} {{sellRequestInfo.total.currency}}
@@ -107,23 +107,17 @@ + is-disabled="!selectedPaymentMethodId.value || !sellRequestInfo || !wallet"> Confirm sale + is-disabled="!selectedPaymentMethodId.value || !sellRequestInfo || !wallet"> Slide to sell
{{amountUnitStr}}
- {{sellInfo.subtotal}} {{sellInfo.currency}} + {{sellInfo.subtotal}} {{sellInfo.currency}} {{sellInfo.qty}} BTC @ ${{sellInfo.price}} per BTC
-
+
@@ -64,23 +64,17 @@ + is-disabled="!sellInfo || !wallet"> Confirm sale + is-disabled="!sellInfo || !wallet"> Slide to sell
{{amountUnitStr}}
- @ + @ {{rate | currency:cardInfo.currencySymbol:2}} per BTC ...
@@ -60,23 +60,17 @@ + is-disabled="!cardInfo || !wallet"> Add funds + is-disabled="!cardInfo || !wallet"> Slide to confirm Date: Thu, 22 Jun 2017 12:28:39 -0300 Subject: [PATCH 14/84] ref msj --- www/views/bitpayCard.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/views/bitpayCard.html b/www/views/bitpayCard.html index 91c85b482..c08297225 100644 --- a/www/views/bitpayCard.html +++ b/www/views/bitpayCard.html @@ -48,7 +48,7 @@

Get started

- Your BitPay Card is ready. Add funds to your card to start using your card at stores and ATMs worldwide. + Your BitPay Card is ready. Add funds to your card to start using it at stores and ATMs worldwide.
From 4484856687b2a39c064067df09f066d86fa05b53 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 22 Jun 2017 12:41:50 -0300 Subject: [PATCH 15/84] Removes unused variable --- src/js/controllers/confirm.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 3bfb55581..e12c82cf7 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -13,7 +13,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( var unitToSatoshi = walletConfig.settings.unitToSatoshi; var unitDecimals = walletConfig.settings.unitDecimals; var satToUnit = 1 / unitToSatoshi; - var touchIdEnabled = config.touchIdFor && config.touchIdFor[wallet.id]; var configFeeLevel = walletConfig.settings.feeLevel ? walletConfig.settings.feeLevel : 'normal'; From ba138059ce75a592d271aa3db8b286f6a01780d8 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 22 Jun 2017 13:32:19 -0300 Subject: [PATCH 16/84] Fix slide to pay --- src/js/controllers/confirm.js | 8 -------- www/views/confirm.html | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index e12c82cf7..c9ce5943a 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -353,10 +353,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( popupService.showAlert(null, msg, function() {}); }; - $scope.$on('accepted', function(event) { - $scope.approve(); - }); - $scope.onWalletSelect = function(wallet) { setWallet(wallet, tx); }; @@ -535,10 +531,6 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.statusChangeHandler = statusChangeHandler; - $scope.onConfirm = function() { - $scope.approve(statusChangeHandler); - }; - $scope.onSuccessConfirm = function() { $scope.sendStatus = ''; $ionicHistory.nextViewOptions({ diff --git a/www/views/confirm.html b/www/views/confirm.html index c7f801539..cff04ebf3 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -107,7 +107,7 @@ {{buttonText}} From 8627e6010397a4a0c9986180fc6d61d4f4448044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Wed, 7 Jun 2017 12:23:07 -0300 Subject: [PATCH 17/84] add old scanner for windows platform --- app-template/config-template.xml | 1 + src/js/controllers/join.js | 1 + src/js/controllers/tabsController.js | 21 ++++- src/js/directives/qrScanner.js | 35 ++++++-- src/js/services/scannerService.js | 122 +++++++++++++++------------ www/views/tab-home.html | 1 + www/views/tabs.html | 2 +- 7 files changed, 121 insertions(+), 62 deletions(-) diff --git a/app-template/config-template.xml b/app-template/config-template.xml index b8019530a..d0dec21e9 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -60,6 +60,7 @@ + diff --git a/src/js/controllers/join.js b/src/js/controllers/join.js index 0acc5556b..b17236d5b 100644 --- a/src/js/controllers/join.js +++ b/src/js/controllers/join.js @@ -50,6 +50,7 @@ angular.module('copayApp.controllers').controller('joinController', $scope.onQrCodeScannedJoin = function(data) { $scope.formData.secret = data; + $scope.$apply(); }; if ($stateParams.url) { diff --git a/src/js/controllers/tabsController.js b/src/js/controllers/tabsController.js index 42899e13e..ef4dd8299 100644 --- a/src/js/controllers/tabsController.js +++ b/src/js/controllers/tabsController.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, incomingData, lodash, popupService, gettextCatalog) { +angular.module('copayApp.controllers').controller('tabsController', function($rootScope, $log, $scope, $state, $stateParams, $timeout, platformInfo, incomingData, lodash, popupService, gettextCatalog, scannerService) { $scope.onScan = function(data) { if (!incomingData.redir(data)) { @@ -22,6 +22,25 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro }, 1); }; + $scope.chooseScanner = function() { + + var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + + if (!isWindowsPhoneApp) { + $state.go('tabs.scan'); + return; + } + + scannerService.useOldScanner(function(err, contents) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; + } + incomingData.redir(contents); + }); + + }; + $scope.$on("$ionicView.beforeEnter", function(event, data) { $rootScope.hideTabs = ''; }); diff --git a/src/js/directives/qrScanner.js b/src/js/directives/qrScanner.js index 8a144bc2b..cd1759e56 100644 --- a/src/js/directives/qrScanner.js +++ b/src/js/directives/qrScanner.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.directives') - .directive('qrScanner', function($state, $rootScope, $log, $ionicHistory) { + .directive('qrScanner', function($state, $rootScope, $log, $ionicHistory, platformInfo, scannerService) { return { restrict: 'E', @@ -9,26 +9,49 @@ angular.module('copayApp.directives') onScan: "&" }, replace: true, - template: '', + template: '', link: function(scope, el, attrs) { + scope.chooseScanner = function() { + var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + + if (!isWindowsPhoneApp) { + scope.openScanner(); + return; + } + + scannerService.useOldScanner(function(err, contents) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; + } + scope.onScan({ + data: contents + }); + }); + }; + scope.openScanner = function() { $log.debug('Opening scanner by directive...'); $ionicHistory.nextViewOptions({ disableAnimate: true }); - $state.go('scanner', { passthroughMode: 1 }); + $state.go('scanner', { + passthroughMode: 1 + }); }; var afterEnter = $rootScope.$on('$ionicView.afterEnter', function() { - if($rootScope.scanResult) { - scope.onScan({ data: $rootScope.scanResult }); + if ($rootScope.scanResult) { + scope.onScan({ + data: $rootScope.scanResult + }); $rootScope.scanResult = null; } }); // Destroy event - scope.$on('$destroy', function(){ + scope.$on('$destroy', function() { afterEnter(); }); } diff --git a/src/js/services/scannerService.js b/src/js/services/scannerService.js index 0c3f28916..ddf62895d 100644 --- a/src/js/services/scannerService.js +++ b/src/js/services/scannerService.js @@ -17,27 +17,27 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti var canChangeCamera = false; var canOpenSettings = false; - function _checkCapabilities(status){ + function _checkCapabilities(status) { $log.debug('scannerService is reviewing platform capabilities...'); // Permission can be assumed on the desktop builds - hasPermission = (isDesktop || status.authorized)? true: false; - isDenied = status.denied? true : false; - isRestricted = status.restricted? true : false; - canEnableLight = status.canEnableLight? true : false; - canChangeCamera = status.canChangeCamera? true : false; - canOpenSettings = status.canOpenSettings? true : false; + hasPermission = (isDesktop || status.authorized) ? true : false; + isDenied = status.denied ? true : false; + isRestricted = status.restricted ? true : false; + canEnableLight = status.canEnableLight ? true : false; + canChangeCamera = status.canChangeCamera ? true : false; + canOpenSettings = status.canOpenSettings ? true : false; _logCapabilities(); } - function _logCapabilities(){ - function _orIsNot(bool){ - return bool? '' : 'not '; + function _logCapabilities() { + function _orIsNot(bool) { + return bool ? '' : 'not '; } $log.debug('A camera is ' + _orIsNot(isAvailable) + 'available to this app.'); var access = 'not authorized'; - if(hasPermission) access = 'authorized'; - if(isDenied) access = 'denied'; - if(isRestricted) access = 'restricted'; + if (hasPermission) access = 'authorized'; + if (isDenied) access = 'denied'; + if (isRestricted) access = 'restricted'; $log.debug('Camera access is ' + access + '.'); $log.debug('Support for opening device settings is ' + _orIsNot(canOpenSettings) + 'available on this platform.'); $log.debug('A light is ' + _orIsNot(canEnableLight) + 'available on this platform.'); @@ -47,7 +47,7 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti /** * Immediately return known capabilities of the current platform. */ - this.getCapabilities = function(){ + this.getCapabilities = function() { return { isAvailable: isAvailable, hasPermission: hasPermission, @@ -68,18 +68,18 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti * The `status` of QRScanner is returned to the callback. */ this.gentleInitialize = function(callback) { - if(initializeStarted && !isDesktop){ - QRScanner.getStatus(function(status){ + if (initializeStarted && !isDesktop) { + QRScanner.getStatus(function(status) { _completeInitialization(status, callback); }); return; } initializeStarted = true; $log.debug('Trying to pre-initialize QRScanner.'); - if(!isDesktop){ - QRScanner.getStatus(function(status){ + if (!isDesktop) { + QRScanner.getStatus(function(status) { _checkCapabilities(status); - if(status.authorized){ + if (status.authorized) { $log.debug('Camera permission already granted.'); initialize(callback); } else { @@ -92,14 +92,14 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti } }; - function initialize(callback){ + function initialize(callback) { $log.debug('Initializing scanner...'); - QRScanner.prepare(function(err, status){ - if(err){ + QRScanner.prepare(function(err, status) { + if (err) { isAvailable = false; $log.error(err); // does not return `status` if there is an error - QRScanner.getStatus(function(status){ + QRScanner.getStatus(function(status) { _completeInitialization(status, callback); }); } else { @@ -112,18 +112,19 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti // This could be much cleaner with a Promise API // (needs a polyfill for some platforms) var initializeCompleted = false; - function _completeInitialization(status, callback){ + + function _completeInitialization(status, callback) { _checkCapabilities(status); initializeCompleted = true; $rootScope.$emit('scannerServiceInitialized'); - if(typeof callback === "function"){ + if (typeof callback === "function") { callback(status); } } - this.isInitialized = function(){ + this.isInitialized = function() { return initializeCompleted; }; - this.initializeStarted = function(){ + this.initializeStarted = function() { return initializeStarted; }; @@ -140,21 +141,21 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti */ this.activate = function(callback) { $log.debug('Activating scanner...'); - QRScanner.show(function(status){ - initializeCompleted = true; - _checkCapabilities(status); - if(typeof callback === "function"){ - callback(status); - } - }); - if(nextHide !== null){ - $timeout.cancel(nextHide); - nextHide = null; - } - if(nextDestroy !== null){ - $timeout.cancel(nextDestroy); - nextDestroy = null; + QRScanner.show(function(status) { + initializeCompleted = true; + _checkCapabilities(status); + if (typeof callback === "function") { + callback(status); } + }); + if (nextHide !== null) { + $timeout.cancel(nextHide); + nextHide = null; + } + if (nextDestroy !== null) { + $timeout.cancel(nextDestroy); + nextDestroy = null; + } }; /** @@ -193,18 +194,18 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti // Natively hide the QRScanner's preview // On mobile platforms, this can reduce GPU/power usage // On desktop, this fully turns off the camera (and any associated privacy lights) - function _hide(){ + function _hide() { $log.debug('Scanner not in use for ' + hideAfterSeconds + ' seconds, hiding...'); QRScanner.hide(); } // Reduce QRScanner power/processing consumption by the maximum amount - function _destroy(){ + function _destroy() { $log.debug('Scanner not in use for ' + destroyAfterSeconds + ' seconds, destroying...'); QRScanner.destroy(); } - this.reinitialize = function(callback){ + this.reinitialize = function(callback) { initializeCompleted = false; QRScanner.destroy(); initialize(callback); @@ -217,17 +218,18 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti */ this.toggleLight = function(callback) { $log.debug('Toggling light...'); - if(lightEnabled){ + if (lightEnabled) { QRScanner.disableLight(_handleResponse); } else { QRScanner.enableLight(_handleResponse); } - function _handleResponse(err, status){ - if(err){ + + function _handleResponse(err, status) { + if (err) { $log.error(err); } else { lightEnabled = status.lightEnabled; - var state = lightEnabled? 'enabled' : 'disabled'; + var state = lightEnabled ? 'enabled' : 'disabled'; $log.debug('Light ' + state + '.'); } callback(lightEnabled); @@ -241,16 +243,17 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti * is complete. */ this.toggleCamera = function(callback) { - var nextCamera = backCamera? 1 : 0; - function cameraToString(index){ - return index === 1? 'front' : 'back'; // front = 1, back = 0 + var nextCamera = backCamera ? 1 : 0; + + function cameraToString(index) { + return index === 1 ? 'front' : 'back'; // front = 1, back = 0 } $log.debug('Toggling to the ' + cameraToString(nextCamera) + ' camera...'); - QRScanner.useCamera(nextCamera, function(err, status){ - if(err){ + QRScanner.useCamera(nextCamera, function(err, status) { + if (err) { $log.error(err); } - backCamera = status.currentCamera === 1? false : true; + backCamera = status.currentCamera === 1 ? false : true; $log.debug('Camera toggled. Now using the ' + cameraToString(backCamera) + ' camera.'); callback(status); }); @@ -260,4 +263,15 @@ angular.module('copayApp.services').service('scannerService', function($log, $ti $log.debug('Attempting to open device settings...'); QRScanner.openSettings(); }; + + this.useOldScanner = function(callback) { + cordova.plugins.barcodeScanner.scan( + function(result) { + callback(null, result.text); + }, + function(error) { + callback(error); + } + ); + } }); diff --git a/www/views/tab-home.html b/www/views/tab-home.html index 6d2ec9247..c27fa4f1b 100644 --- a/www/views/tab-home.html +++ b/www/views/tab-home.html @@ -10,6 +10,7 @@ spinner="ios-small" on-refresh="onRefresh()"> +
diff --git a/www/views/tabs.html b/www/views/tabs.html index 6673b416a..69cf93309 100644 --- a/www/views/tabs.html +++ b/www/views/tabs.html @@ -8,7 +8,7 @@ - + From c932e0d23c2ba95cac7a3c270ef8e336aa7ffc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Wed, 7 Jun 2017 13:15:15 -0300 Subject: [PATCH 18/84] fixes --- app-template/config-template.xml | 2 +- src/js/directives/qrScanner.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app-template/config-template.xml b/app-template/config-template.xml index d0dec21e9..3c2a9bd84 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -72,7 +72,7 @@ - + diff --git a/src/js/directives/qrScanner.js b/src/js/directives/qrScanner.js index cd1759e56..323093203 100644 --- a/src/js/directives/qrScanner.js +++ b/src/js/directives/qrScanner.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.directives') - .directive('qrScanner', function($state, $rootScope, $log, $ionicHistory, platformInfo, scannerService) { + .directive('qrScanner', function($state, $rootScope, $log, $ionicHistory, platformInfo, scannerService, popupService) { return { restrict: 'E', From b17e38dea2e580493df6bd33dd7824b722cae0a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Wed, 7 Jun 2017 14:45:40 -0300 Subject: [PATCH 19/84] add old scanner to tab send --- src/js/controllers/tab-send.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/js/controllers/tab-send.js b/src/js/controllers/tab-send.js index ba6577938..8d176d071 100644 --- a/src/js/controllers/tab-send.js +++ b/src/js/controllers/tab-send.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog) { +angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService) { var originalList; var CONTACTS_SHOW_LIMIT; @@ -120,7 +120,20 @@ angular.module('copayApp.controllers').controller('tabSendController', function( }; $scope.openScanner = function() { - $state.go('tabs.scan'); + var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + + if (!isWindowsPhoneApp) { + $state.go('tabs.scan'); + return; + } + + scannerService.useOldScanner(function(err, contents) { + if (err) { + popupService.showAlert(gettextCatalog.getString('Error'), err); + return; + } + incomingData.redir(contents); + }); }; $scope.showMore = function() { From 34fa643ff87cef797256d7d54e1746ef780bdf01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Wed, 7 Jun 2017 15:23:45 -0300 Subject: [PATCH 20/84] remove lock app for windows phone --- src/js/controllers/tab-settings.js | 1 + www/views/tab-settings.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/controllers/tab-settings.js b/src/js/controllers/tab-settings.js index a245418c7..01ffacd42 100644 --- a/src/js/controllers/tab-settings.js +++ b/src/js/controllers/tab-settings.js @@ -51,6 +51,7 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct $scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.isCordova = platformInfo.isCordova; + $scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; $scope.isDevel = platformInfo.isDevel; $scope.appName = appConfigService.nameCase; configService.whenAvailable(function(config) { diff --git a/www/views/tab-settings.html b/www/views/tab-settings.html index cfc054614..3d7318b0b 100644 --- a/www/views/tab-settings.html +++ b/www/views/tab-settings.html @@ -89,7 +89,7 @@ - + {{'Lock App' | translate}} From 9cbd2ebb0806a44852c64cd9f5c0b8d5990eaa17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 11:41:30 -0300 Subject: [PATCH 21/84] fix success modal for wp --- src/js/directives/slideToAcceptSuccess.js | 9 ++++++--- src/sass/views/includes/slideToAcceptSuccess.scss | 6 ++++++ www/views/includes/slideToAcceptSuccess.html | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/js/directives/slideToAcceptSuccess.js b/src/js/directives/slideToAcceptSuccess.js index b5e9b20bc..fbd588bfe 100644 --- a/src/js/directives/slideToAcceptSuccess.js +++ b/src/js/directives/slideToAcceptSuccess.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.directives') - .directive('slideToAcceptSuccess', function($timeout) { + .directive('slideToAcceptSuccess', function($timeout, platformInfo) { return { restrict: 'E', templateUrl: 'views/includes/slideToAcceptSuccess.html', @@ -12,10 +12,13 @@ angular.module('copayApp.directives') hideOnConfirm: '=slideSuccessHideOnConfirm' }, link: function(scope, element, attrs) { + + scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; + var elm = element[0]; elm.style.display = 'none'; scope.$watch('isShown', function() { - if(scope.isShown) { + if (scope.isShown) { elm.style.display = 'flex'; $timeout(function() { scope.fillScreen = true; @@ -24,7 +27,7 @@ angular.module('copayApp.directives') }); scope.onConfirmButtonClick = function() { scope.onConfirm(); - if(scope.hideOnConfirm) { + if (scope.hideOnConfirm) { scope.fillScreen = false; elm.style.display = 'none'; } diff --git a/src/sass/views/includes/slideToAcceptSuccess.scss b/src/sass/views/includes/slideToAcceptSuccess.scss index faeefc7c9..bf6c5e269 100644 --- a/src/sass/views/includes/slideToAcceptSuccess.scss +++ b/src/sass/views/includes/slideToAcceptSuccess.scss @@ -12,6 +12,12 @@ slide-to-accept-success { .slide-success { $duration: 400ms; + &__windows-background { + background: $v-success-bg-color; + height: 100%; + width: 100%; + position: fixed; + } &__background { $start-radius: 5; $scale-factor: 20; diff --git a/www/views/includes/slideToAcceptSuccess.html b/www/views/includes/slideToAcceptSuccess.html index 37f0381f1..a37a8cb3c 100644 --- a/www/views/includes/slideToAcceptSuccess.html +++ b/www/views/includes/slideToAcceptSuccess.html @@ -1,6 +1,6 @@
+ class="slide-success__background slide-success__windows-background" + ng-class="{'fill-screen': fillScreen, 'slide-success__windows-background': isWindowsPhoneApp}">
From 138a4ef02fe9e27165cf359eb7c79f4547c365e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 11:47:06 -0300 Subject: [PATCH 22/84] hide share app for wp --- www/views/tab-settings.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/views/tab-settings.html b/www/views/tab-settings.html index 3d7318b0b..7650aa62f 100644 --- a/www/views/tab-settings.html +++ b/www/views/tab-settings.html @@ -29,7 +29,7 @@ {{'Send Feedback' | translate}} - + From 364b6923e743191ceab842103ed5495073c0cc7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 12:29:00 -0300 Subject: [PATCH 23/84] hide color change from preferences for wp --- www/views/preferences.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/views/preferences.html b/www/views/preferences.html index 5c8d6f7aa..b7bf2e304 100644 --- a/www/views/preferences.html +++ b/www/views/preferences.html @@ -18,7 +18,7 @@ - + Color Date: Thu, 8 Jun 2017 12:46:56 -0300 Subject: [PATCH 24/84] add copy and paste support for windows universal app --- app-template/config-template.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-template/config-template.xml b/app-template/config-template.xml index 3c2a9bd84..83671485e 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -43,7 +43,7 @@ - + From 162fe742f6d5fdabe210edb0274e89eff922759b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 13:47:03 -0300 Subject: [PATCH 25/84] fixes --- src/js/controllers/preferences.js | 4 ++-- www/views/includes/slideToAcceptSuccess.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/controllers/preferences.js b/src/js/controllers/preferences.js index 1057d5c69..d30413695 100644 --- a/src/js/controllers/preferences.js +++ b/src/js/controllers/preferences.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('preferencesController', - function($scope, $rootScope, $timeout, $log, $ionicHistory, configService, profileService, fingerprintService, walletService) { + function($scope, $rootScope, $timeout, $log, $ionicHistory, configService, profileService, fingerprintService, walletService, platformInfo) { var wallet; var walletId; @@ -76,7 +76,7 @@ angular.module('copayApp.controllers').controller('preferencesController', wallet = profileService.getWallet(data.stateParams.walletId); walletId = wallet.credentials.walletId; $scope.wallet = wallet; - + $scope.isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; $scope.externalSource = null; if (!wallet) diff --git a/www/views/includes/slideToAcceptSuccess.html b/www/views/includes/slideToAcceptSuccess.html index a37a8cb3c..923eab25c 100644 --- a/www/views/includes/slideToAcceptSuccess.html +++ b/www/views/includes/slideToAcceptSuccess.html @@ -1,5 +1,5 @@
From 14e0cc2e0f1b385e3b2e1f75e5a07320cd0415a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 14:36:55 -0300 Subject: [PATCH 26/84] use ionic modals for prompts --- src/js/services/popupService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/services/popupService.js b/src/js/services/popupService.js index 83ea3180b..1f03cd976 100644 --- a/src/js/services/popupService.js +++ b/src/js/services/popupService.js @@ -3,6 +3,7 @@ angular.module('copayApp.services').service('popupService', function($log, $ionicPopup, platformInfo, gettextCatalog) { var isCordova = platformInfo.isCordova; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; /*************** Ionic ****************/ @@ -121,7 +122,7 @@ angular.module('copayApp.services').service('popupService', function($log, $ioni opts = opts ||  {}; - if (isCordova && !opts.forceHTMLPrompt) + if (isCordova && !isWindowsPhoneApp && !opts.forceHTMLPrompt) _cordovaPrompt(title, message, opts, cb); else _ionicPrompt(title, message, opts, cb); From 95f3ddf01aa5a318da33fc39e18e223588f864f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 15:09:39 -0300 Subject: [PATCH 27/84] remove external services for this first release and general refactors --- src/js/controllers/advancedSettings.js | 3 ++- src/js/controllers/feedback/rateApp.js | 5 +++-- src/js/controllers/tab-send.js | 2 +- src/js/controllers/tabsController.js | 2 +- src/js/directives/qrScanner.js | 2 +- src/js/services/coinbaseService.js | 22 +++++++++++----------- src/js/services/configService.js | 6 ++++-- src/js/services/glideraService.js | 2 +- src/js/services/onGoingProcess.js | 10 +++++----- src/js/services/profileService.js | 10 +++++----- www/views/advancedSettings.html | 4 ++-- 11 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/js/controllers/advancedSettings.js b/src/js/controllers/advancedSettings.js index 5b213b053..89500af52 100644 --- a/src/js/controllers/advancedSettings.js +++ b/src/js/controllers/advancedSettings.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $log, configService) { +angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $log, configService, platformInfo) { var updateConfig = function() { var config = configService.getSync(); @@ -50,6 +50,7 @@ angular.module('copayApp.controllers').controller('advancedSettingsController', }; $scope.$on("$ionicView.beforeEnter", function(event, data) { + $scope.isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; updateConfig(); }); diff --git a/src/js/controllers/feedback/rateApp.js b/src/js/controllers/feedback/rateApp.js index ff3ad5e53..76f4e864b 100644 --- a/src/js/controllers/feedback/rateApp.js +++ b/src/js/controllers/feedback/rateApp.js @@ -5,7 +5,8 @@ angular.module('copayApp.controllers').controller('rateAppController', function( $scope.appName = appConfigService.nameCase; var isAndroid = platformInfo.isAndroid; var isIOS = platformInfo.isIOS; - var isWP = platformInfo.isWP; + var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + var config = configService.getSync(); $scope.skip = function() { @@ -42,7 +43,7 @@ angular.module('copayApp.controllers').controller('rateAppController', function( url = $scope.appName == 'Copay' ? defaults.rateApp.copay.android : defaults.rateApp.bitpay.android; if (isIOS) url = $scope.appName == 'Copay' ? defaults.rateApp.copay.ios : defaults.rateApp.bitpay.ios; - // if (isWP) + // if (isWindowsPhoneApp) // url = $scope.appName == 'Copay' ? defaults.rateApp.copay.windows : defaults.rateApp.bitpay.windows; externalLinkService.open(url); diff --git a/src/js/controllers/tab-send.js b/src/js/controllers/tab-send.js index 8d176d071..830cc167b 100644 --- a/src/js/controllers/tab-send.js +++ b/src/js/controllers/tab-send.js @@ -120,7 +120,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function( }; $scope.openScanner = function() { - var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; if (!isWindowsPhoneApp) { $state.go('tabs.scan'); diff --git a/src/js/controllers/tabsController.js b/src/js/controllers/tabsController.js index ef4dd8299..fcebd4ddd 100644 --- a/src/js/controllers/tabsController.js +++ b/src/js/controllers/tabsController.js @@ -24,7 +24,7 @@ angular.module('copayApp.controllers').controller('tabsController', function($ro $scope.chooseScanner = function() { - var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; if (!isWindowsPhoneApp) { $state.go('tabs.scan'); diff --git a/src/js/directives/qrScanner.js b/src/js/directives/qrScanner.js index 323093203..158f71c7e 100644 --- a/src/js/directives/qrScanner.js +++ b/src/js/directives/qrScanner.js @@ -13,7 +13,7 @@ angular.module('copayApp.directives') link: function(scope, el, attrs) { scope.chooseScanner = function() { - var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; if (!isWindowsPhoneApp) { scope.openScanner(); diff --git a/src/js/services/coinbaseService.js b/src/js/services/coinbaseService.js index cce8544de..65adaa31c 100644 --- a/src/js/services/coinbaseService.js +++ b/src/js/services/coinbaseService.js @@ -5,7 +5,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ var credentials = {}; var isCordova = platformInfo.isCordova; var isNW = platformInfo.isNW; - var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; root.priceSensitivity = [{ value: 0.5, @@ -303,14 +303,14 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; root.getBuyOrder = function(token, accountId, buyId, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/accounts/' + accountId + '/buys/' + buyId, token)).then(function(data) { - $log.info('Coinbase Buy Info: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Buy Info: ERROR ' + data.statusText); - return cb(data.data); - }); + if (!token) return cb('Invalid Token'); + $http(_get('/accounts/' + accountId + '/buys/' + buyId, token)).then(function(data) { + $log.info('Coinbase Buy Info: SUCCESS'); + return cb(null, data.data); + }, function(data) { + $log.error('Coinbase Buy Info: ERROR ' + data.statusText); + return cb(data.data); + }); }; root.getTransaction = function(token, accountId, transactionId, cb) { @@ -723,7 +723,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ var register = function() { - root.isActive(function(err, isActive){ + root.isActive(function(err, isActive) { if (err) return; buyAndSellService.register({ @@ -742,7 +742,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ $rootScope.$on('bwsEvent', function(e, walletId, type, n) { if (type == 'NewBlock' && n && n.data && n.data.network == 'livenet') { - root.isActive(function(err,isActive){ + root.isActive(function(err, isActive) { // Update Coinbase if (isActive) root.updatePendingTransactions(); diff --git a/src/js/services/configService.js b/src/js/services/configService.js index 4a8021b55..e4521296a 100644 --- a/src/js/services/configService.js +++ b/src/js/services/configService.js @@ -1,8 +1,10 @@ 'use strict'; -angular.module('copayApp.services').factory('configService', function(storageService, lodash, $log, $timeout, $rootScope) { +angular.module('copayApp.services').factory('configService', function(storageService, lodash, $log, $timeout, $rootScope, platformInfo) { var root = {}; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; + var defaultConfig = { // wallet limits limits: { @@ -65,7 +67,7 @@ angular.module('copayApp.services').factory('configService', function(storageSer }, hideNextSteps: { - enabled: false, + enabled: isWindowsPhoneApp ? true : false, }, rates: { diff --git a/src/js/services/glideraService.js b/src/js/services/glideraService.js index ad62d3ef4..1685ad9c7 100644 --- a/src/js/services/glideraService.js +++ b/src/js/services/glideraService.js @@ -4,7 +4,7 @@ angular.module('copayApp.services').factory('glideraService', function($http, $l var root = {}; var credentials = {}; var isCordova = platformInfo.isCordova; - var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; var setCredentials = function() { if (!$window.externalServices || !$window.externalServices.glidera) { diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js index 19e492e47..454d566f8 100644 --- a/src/js/services/onGoingProcess.js +++ b/src/js/services/onGoingProcess.js @@ -3,7 +3,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $timeout, $filter, lodash, $ionicLoading, gettext, platformInfo) { var root = {}; var isCordova = platformInfo.isCordova; - var isWP = platformInfo.isWP; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; var ongoingProcess = {}; @@ -51,7 +51,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti root.clear = function() { ongoingProcess = {}; - if (isCordova && !isWP) { + if (isCordova && !isWindowsPhoneApp) { window.plugins.spinnerDialog.hide(); } else { $ionicLoading.hide(); @@ -81,19 +81,19 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti if (customHandler) { customHandler(processName, showName, isOn); } else if (root.onGoingProcessName) { - if (isCordova && !isWP) { + if (isCordova && !isWindowsPhoneApp) { window.plugins.spinnerDialog.show(null, showName, root.clear); } else { var tmpl; - if (isWP) tmpl = '
' + showName + '
'; + if (isWindowsPhoneApp) tmpl = '
' + showName + '
'; else tmpl = '
' + showName + '
'; $ionicLoading.show({ template: tmpl }); } } else { - if (isCordova && !isWP) { + if (isCordova && !isWindowsPhoneApp) { window.plugins.spinnerDialog.hide(); } else { $ionicLoading.hide(); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 8c5a93662..ae44c7b26 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -5,12 +5,12 @@ angular.module('copayApp.services') var isChromeApp = platformInfo.isChromeApp; var isCordova = platformInfo.isCordova; - var isWP = platformInfo.isWP; + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; var isIOS = platformInfo.isIOS; var root = {}; var errors = bwcService.getErrors(); - var usePushNotifications = isCordova && !isWP; + var usePushNotifications = isCordova && !isWindowsPhoneApp; var UPDATE_PERIOD = 15; @@ -208,9 +208,9 @@ angular.module('copayApp.services') }; var shouldSkipValidation = function(walletId) { - return root.profile.isChecked(platformInfo.ua, walletId) || isIOS || isWP; - } - // Used when reading wallets from the profile + return root.profile.isChecked(platformInfo.ua, walletId) || isIOS || isWindowsPhoneApp; + } + // Used when reading wallets from the profile root.bindWallet = function(credentials, cb) { if (!credentials.walletId || !credentials.m) return cb('bindWallet should receive credentials JSON'); diff --git a/www/views/advancedSettings.html b/www/views/advancedSettings.html index 7181505f8..2d39653a0 100644 --- a/www/views/advancedSettings.html +++ b/www/views/advancedSettings.html @@ -16,7 +16,7 @@
- + Recent Transaction Card
@@ -25,7 +25,7 @@
- + Hide Next Steps Card
From d3b1ea07cdc7177367292ecf1a5fa75e51c4b89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 15:21:38 -0300 Subject: [PATCH 28/84] remove next steps card and app rate from tab-home --- src/js/controllers/feedback/rateApp.js | 3 --- src/js/controllers/tab-home.js | 6 ++++++ www/views/tab-home.html | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/js/controllers/feedback/rateApp.js b/src/js/controllers/feedback/rateApp.js index 76f4e864b..7e2bc8e41 100644 --- a/src/js/controllers/feedback/rateApp.js +++ b/src/js/controllers/feedback/rateApp.js @@ -5,7 +5,6 @@ angular.module('copayApp.controllers').controller('rateAppController', function( $scope.appName = appConfigService.nameCase; var isAndroid = platformInfo.isAndroid; var isIOS = platformInfo.isIOS; - var isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; var config = configService.getSync(); @@ -43,8 +42,6 @@ angular.module('copayApp.controllers').controller('rateAppController', function( url = $scope.appName == 'Copay' ? defaults.rateApp.copay.android : defaults.rateApp.bitpay.android; if (isIOS) url = $scope.appName == 'Copay' ? defaults.rateApp.copay.ios : defaults.rateApp.bitpay.ios; - // if (isWindowsPhoneApp) - // url = $scope.appName == 'Copay' ? defaults.rateApp.copay.windows : defaults.rateApp.bitpay.windows; externalLinkService.open(url); $state.go('tabs.rate.complete', { diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.js index b2667b2b7..79be14391 100644 --- a/src/js/controllers/tab-home.js +++ b/src/js/controllers/tab-home.js @@ -12,6 +12,7 @@ angular.module('copayApp.controllers').controller('tabHomeController', $scope.homeTip = $stateParams.fromOnboarding; $scope.isCordova = platformInfo.isCordova; $scope.isAndroid = platformInfo.isAndroid; + $scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; $scope.isNW = platformInfo.isNW; $scope.showRateCard = {}; @@ -42,6 +43,11 @@ angular.module('copayApp.controllers').controller('tabHomeController', } storageService.getFeedbackInfo(function(error, info) { + + if ($scope.isWindowsPhoneApp) { + $scope.showRateCard.value = false; + return; + } if (!info) { initFeedBackInfo(); } else { diff --git a/www/views/tab-home.html b/www/views/tab-home.html index c27fa4f1b..300bb78ea 100644 --- a/www/views/tab-home.html +++ b/www/views/tab-home.html @@ -109,7 +109,7 @@
-
+
From 5c9902e5c7d4c8ec0ed509a33142b9e9778808c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 8 Jun 2017 17:01:40 -0300 Subject: [PATCH 29/84] fix exit button for wp --- src/js/routes.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/js/routes.js b/src/js/routes.js index 52a9ade41..17267fa93 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -1123,7 +1123,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }); }) - .run(function($rootScope, $state, $location, $log, $timeout, startupService, fingerprintService, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, configService, emailService, /* plugins START HERE => */ coinbaseService, glideraService, amazonService, bitpayCardService, applicationService) { + .run(function($rootScope, $state, $location, $log, $timeout, startupService, ionicToast, fingerprintService, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, configService, emailService, /* plugins START HERE => */ coinbaseService, glideraService, amazonService, bitpayCardService, applicationService) { uxLanguage.init(); @@ -1170,10 +1170,12 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr $ionicHistory.goBack(); } else if ($rootScope.backButtonPressedOnceToExit) { - ionic.Platform.exitApp(); + navigator.app.exitApp(); } else { $rootScope.backButtonPressedOnceToExit = true; - window.plugins.toast.showShortBottom(gettextCatalog.getString('Press again to exit')); + $rootScope.$apply(function() { + ionicToast.show(gettextCatalog.getString('Press again to exit'), 'bottom', false, 1000); + }); $timeout(function() { $rootScope.backButtonPressedOnceToExit = false; }, 3000); From 4772faf758773b951f7fa45e95ee8e7be4294ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Fri, 9 Jun 2017 11:04:20 -0300 Subject: [PATCH 30/84] comment phonegap-plugin-barcodescanner plugin to avoid build crashs on android and ios --- app-template/config-template.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app-template/config-template.xml b/app-template/config-template.xml index 83671485e..ae3db5723 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -60,7 +60,6 @@ - @@ -69,6 +68,9 @@ + + + From b388ddb98a83ff93a949466f186553469e8b8614 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Thu, 15 Jun 2017 12:00:49 -0300 Subject: [PATCH 31/84] fix appxmanifest values --- app-template/bitpay/appConfig.json | 4 ++-- app-template/config-template.xml | 6 ++++-- app-template/copay/appConfig.json | 4 ++-- app-template/package-template.json | 4 ++-- build.json | 11 +++++++++++ 5 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 build.json diff --git a/app-template/bitpay/appConfig.json b/app-template/bitpay/appConfig.json index 1e1b40255..b5d5445f4 100644 --- a/app-template/bitpay/appConfig.json +++ b/app-template/bitpay/appConfig.json @@ -17,8 +17,8 @@ "url": "https://bitpay.com", "appDescription": "Secure Bitcoin Wallet", "winAppName": "BitPayWallet", - "wpPublisherId": "{}", - "wpProductId": "{}", + "WindowsStoreIdentityName": "18C7659D.BitPaySecureBitcoinWallet", + "WindowsStoreDisplayName": "BitPay - Secure Bitcoin Wallet", "windowsAppId": "2d1002d7-ee34-4f60-bd29-0c871ba0c195", "pushSenderId": "1036948132229", "description": "Secure Bitcoin Wallet", diff --git a/app-template/config-template.xml b/app-template/config-template.xml index ae3db5723..1abc0fb7a 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -17,6 +17,9 @@ + + + @@ -59,7 +62,6 @@ - @@ -69,7 +71,7 @@ - + diff --git a/app-template/copay/appConfig.json b/app-template/copay/appConfig.json index deab492ac..72cb5c54d 100644 --- a/app-template/copay/appConfig.json +++ b/app-template/copay/appConfig.json @@ -17,8 +17,8 @@ "url": "https://copay.io", "appDescription": "Copay Bitcoin Wallet", "winAppName": "CopayWallet", - "wpPublisherId": "{31cdd08b-457c-413d-b440-f6665eec847d}", - "wpProductId": "{5381aa50-9069-11e4-84cc-293caf9cbdc8}", + "WindowsStoreIdentityName": "18C7659D.CopayWallet", + "WindowsStoreDisplayName": "Copay Bitcoin Wallet", "windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c", "pushSenderId": "1036948132229", "description": "A Secure Bitcoin Wallet", diff --git a/app-template/package-template.json b/app-template/package-template.json index 2da610c8b..d9ebdd18a 100644 --- a/app-template/package-template.json +++ b/app-template/package-template.json @@ -91,10 +91,10 @@ "build:www-release": "grunt prod", "build:ios": "cordova prepare ios && cordova build ios --debug", "build:android": "cordova prepare android && cordova build android --debug", - "build:windows": "cordova prepare windows && cordova build windows -- --arch=\"x86\"", + "build:windows": "cordova prepare windows && cordova build windows -- --arch=\"ARM\"", "build:ios-release": "cordova prepare ios && cordova build ios --release", "build:android-release": "cordova prepare android && cordova build android --release", - "build:windows-release": "cordova prepare windows && cordova build windows --release --arch=\"x86\"", + "build:windows-release": "cordova prepare windows && cordova build windows --release --arch=\"ARM\"", "build:desktop": "grunt desktop", "build:osx": "grunt osx", "open:ios": "open platforms/ios/*.xcodeproj", diff --git a/build.json b/build.json new file mode 100644 index 000000000..921006b10 --- /dev/null +++ b/build.json @@ -0,0 +1,11 @@ +{ + "windows": { + "debug": { + "packageCertificateKeyFile": "platforms\\windows\\CordovaApp_TemporaryKey.pfx" + }, + "release": { + "packageThumbprint": "ABCABCABCABC123123123123", + "publisherId": "CN=F89609D1-EB3E-45FD-A58A-C2E3895FCE7B" + } + } +} \ No newline at end of file From 03f8b473d32221d2267d21c1b04b26aead5add1c Mon Sep 17 00:00:00 2001 From: Gabriel Date: Thu, 15 Jun 2017 12:02:24 -0300 Subject: [PATCH 32/84] fixes --- app-template/config-template.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app-template/config-template.xml b/app-template/config-template.xml index 1abc0fb7a..062977610 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -62,6 +62,7 @@ + @@ -71,7 +72,7 @@ - + From 04db3f91598152514d8eb4a2144333ceefd49e63 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Sun, 18 Jun 2017 23:36:25 -0300 Subject: [PATCH 33/84] Testing coinbase --- src/js/controllers/buyCoinbase.js | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/js/controllers/buyCoinbase.js b/src/js/controllers/buyCoinbase.js index fb6a625a5..a525fbc2b 100644 --- a/src/js/controllers/buyCoinbase.js +++ b/src/js/controllers/buyCoinbase.js @@ -1,9 +1,10 @@ 'use strict'; -angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, txFormatService) { +angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, txFormatService, feeService) { var amount; var currency; + var feeBTC; var showErrorAndBack = function(err) { $scope.sendStatus = ''; @@ -44,13 +45,33 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct $scope.$on("$ionicView.beforeEnter", function(event, data) { $scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false; var parsedAmount = txFormatService.parseAmount( - data.stateParams.amount, + data.stateParams.amount, data.stateParams.currency); +console.log('[buyCoinbase.js:46]',parsedAmount); //TODO/ + + // Buy always in BTC + amount = (parsedAmount.amountSat / 100000000).toFixed(8); +console.log('[buyCoinbase.js:52]',amount); //TODO/ + currency = 'BTC'; +console.log('[buyCoinbase.js:54]',currency); //TODO/ - amount = parsedAmount.amount; - currency = parsedAmount.currency; $scope.amountUnitStr = parsedAmount.amountUnitStr; +console.log('[buyCoinbase.js:57]',$scope.amountUnitStr); //TODO/ + // Fee Normal for a single transaction + var txNormalFeeKB = 450 / 1024; +console.log('[buyCoinbase.js:60]',txNormalFeeKB); //TODO/ + feeService.getCurrentFeeValue(null, 'normal', function(err, feePerKB) { + feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8); +console.log('[buyCoinbase.js:60]',feePerKB, feeBTC, amount - feeBTC); //TODO/ + // Check if transaction has enough funds to transfer bitcoin from Coinbase to Copay + if (amount - feeBTC < 0) { + showErrorAndBack('Not enough funds for fee'); + return; + } + }); + + return; // TODO $scope.network = coinbaseService.getNetwork(); $scope.wallets = profileService.getWallets({ onlyComplete: true, @@ -144,7 +165,7 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct var cancelText = 'Cancel'; popupService.showConfirm(null, message, okText, cancelText, function(ok) { if (!ok) return; - + ongoingProcess.set('buyingBitcoin', true, statusChangeHandler); coinbaseService.init(function(err, res) { if (err) { From dfd3eeec540a7e322d3857472acbe3477681b72f Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Wed, 21 Jun 2017 15:59:43 -0300 Subject: [PATCH 34/84] Adds fee to transaction --- src/js/controllers/buyCoinbase.js | 108 +++++++++++++---------------- src/js/services/coinbaseService.js | 76 +++++++++++++++----- 2 files changed, 106 insertions(+), 78 deletions(-) diff --git a/src/js/controllers/buyCoinbase.js b/src/js/controllers/buyCoinbase.js index a525fbc2b..6066207ba 100644 --- a/src/js/controllers/buyCoinbase.js +++ b/src/js/controllers/buyCoinbase.js @@ -1,10 +1,9 @@ 'use strict'; -angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, txFormatService, feeService) { +angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, txFormatService) { var amount; var currency; - var feeBTC; var showErrorAndBack = function(err) { $scope.sendStatus = ''; @@ -47,84 +46,75 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct var parsedAmount = txFormatService.parseAmount( data.stateParams.amount, data.stateParams.currency); -console.log('[buyCoinbase.js:46]',parsedAmount); //TODO/ // Buy always in BTC amount = (parsedAmount.amountSat / 100000000).toFixed(8); -console.log('[buyCoinbase.js:52]',amount); //TODO/ currency = 'BTC'; -console.log('[buyCoinbase.js:54]',currency); //TODO/ $scope.amountUnitStr = parsedAmount.amountUnitStr; -console.log('[buyCoinbase.js:57]',$scope.amountUnitStr); //TODO/ - // Fee Normal for a single transaction - var txNormalFeeKB = 450 / 1024; -console.log('[buyCoinbase.js:60]',txNormalFeeKB); //TODO/ - feeService.getCurrentFeeValue(null, 'normal', function(err, feePerKB) { - feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8); -console.log('[buyCoinbase.js:60]',feePerKB, feeBTC, amount - feeBTC); //TODO/ - // Check if transaction has enough funds to transfer bitcoin from Coinbase to Copay - if (amount - feeBTC < 0) { - showErrorAndBack('Not enough funds for fee'); - return; - } - }); - - return; // TODO - $scope.network = coinbaseService.getNetwork(); - $scope.wallets = profileService.getWallets({ - onlyComplete: true, - network: $scope.network - }); - - if (lodash.isEmpty($scope.wallets)) { - showErrorAndBack('No wallets available'); - return; - } - $scope.wallet = $scope.wallets[0]; // Default first wallet - - ongoingProcess.set('connectingCoinbase', true); - coinbaseService.init(function(err, res) { + ongoingProcess.set('calculatingFee', true); + coinbaseService.checkEnoughFundsForFee(amount, function(err) { + ongoingProcess.set('calculatingFee', false); if (err) { - ongoingProcess.set('connectingCoinbase', false); showErrorAndBack(err); return; } - var accessToken = res.accessToken; - coinbaseService.buyPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, b) { - $scope.buyPrice = b.data || null; + $scope.network = coinbaseService.getNetwork(); + $scope.wallets = profileService.getWallets({ + onlyComplete: true, + network: $scope.network }); - $scope.paymentMethods = []; - $scope.selectedPaymentMethodId = { value : null }; - coinbaseService.getPaymentMethods(accessToken, function(err, p) { + if (lodash.isEmpty($scope.wallets)) { + showErrorAndBack('No wallets available'); + return; + } + $scope.wallet = $scope.wallets[0]; // Default first wallet + + ongoingProcess.set('connectingCoinbase', true); + coinbaseService.init(function(err, res) { if (err) { ongoingProcess.set('connectingCoinbase', false); showErrorAndBack(err); return; } + var accessToken = res.accessToken; - var hasPrimary; - var pm; - for(var i = 0; i < p.data.length; i++) { - pm = p.data[i]; - if (pm.allow_buy) { - $scope.paymentMethods.push(pm); + coinbaseService.buyPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, b) { + $scope.buyPrice = b.data || null; + }); + + $scope.paymentMethods = []; + $scope.selectedPaymentMethodId = { value : null }; + coinbaseService.getPaymentMethods(accessToken, function(err, p) { + if (err) { + ongoingProcess.set('connectingCoinbase', false); + showErrorAndBack(err); + return; } - if (pm.allow_buy && pm.primary_buy) { - hasPrimary = true; - $scope.selectedPaymentMethodId.value = pm.id; + + var hasPrimary; + var pm; + for(var i = 0; i < p.data.length; i++) { + pm = p.data[i]; + if (pm.allow_buy) { + $scope.paymentMethods.push(pm); + } + if (pm.allow_buy && pm.primary_buy) { + hasPrimary = true; + $scope.selectedPaymentMethodId.value = pm.id; + } } - } - if (lodash.isEmpty($scope.paymentMethods)) { - ongoingProcess.set('connectingCoinbase', false); - showErrorAndBack('No payment method available to buy'); - return; - } - if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id; - $scope.buyRequest(); + if (lodash.isEmpty($scope.paymentMethods)) { + ongoingProcess.set('connectingCoinbase', false); + showErrorAndBack('No payment method available to buy'); + return; + } + if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id; + $scope.buyRequest(); + }); }); }); }); @@ -160,7 +150,7 @@ console.log('[buyCoinbase.js:60]',feePerKB, feeBTC, amount - feeBTC); //TODO/ }; $scope.buyConfirm = function() { - var message = 'Buy bitcoin for ' + amount + ' ' + currency; + var message = 'Buy bitcoin for ' + $scope.amountUnitStr; var okText = 'Confirm'; var cancelText = 'Cancel'; popupService.showConfirm(null, message, okText, cancelText, function(ok) { diff --git a/src/js/services/coinbaseService.js b/src/js/services/coinbaseService.js index cce8544de..eea9f5f3a 100644 --- a/src/js/services/coinbaseService.js +++ b/src/js/services/coinbaseService.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.services').factory('coinbaseService', function($http, $log, $window, $filter, platformInfo, lodash, storageService, configService, appConfigService, txFormatService, buyAndSellService, $rootScope) { +angular.module('copayApp.services').factory('coinbaseService', function($http, $log, $window, $filter, platformInfo, lodash, storageService, configService, appConfigService, txFormatService, buyAndSellService, $rootScope, feeService) { var root = {}; var credentials = {}; var isCordova = platformInfo.isCordova; @@ -107,6 +107,30 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; }; + root.getReductedAmountByFee = function(amount, cb) { + // Fee Normal for a single transaction (450 bytes) + var txNormalFeeKB = 450 / 1000; + feeService.getCurrentFeeValue(null, 'normal', function(err, feePerKB) { + if (err) return cb(err); + var feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8); + + return cb(null, amount - feeBTC, feeBTC); + }); + }; + + root.checkEnoughFundsForFee = function(amount, cb) { + root.getReductedAmountByFee(amount, function(err, reductedAmount) { + if (err) return cb(err); + + // Check if transaction has enough funds to transfer bitcoin from Coinbase to Copay + if (reductedAmount < 0) { + return cb('Not enough funds for fee'); + } + + return cb(); + }); + }; + root.getSignupUrl = function() { return credentials.HOST + '/signup'; } @@ -657,13 +681,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ var _sendToWallet = function(tx, accessToken, accountId, coinbasePendingTransactions) { if (!tx) return; var desc = appConfigService.nameCase + ' Wallet'; - var data = { - to: tx.toAddr, - amount: tx.amount.amount, - currency: tx.amount.currency, - description: desc - }; - root.sendTo(accessToken, accountId, data, function(err, res) { + root.getReductedAmountByFee(tx.amount.amount, function(err, amountBTC, feeBTC) { if (err) { _savePendingTransaction(tx, { status: 'error', @@ -672,8 +690,18 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ if (err) $log.debug(err); _updateTxs(coinbasePendingTransactions); }); - } else { - if (res.data && !res.data.id) { + return; + } + + var data = { + to: tx.toAddr, + amount: amountBTC, + currency: tx.amount.currency, + description: desc, + fee: feeBTC + }; + root.sendTo(accessToken, accountId, data, function(err, res) { + if (err) { _savePendingTransaction(tx, { status: 'error', error: err @@ -681,19 +709,29 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ if (err) $log.debug(err); _updateTxs(coinbasePendingTransactions); }); - return; - } - root.getTransaction(accessToken, accountId, res.data.id, function(err, sendTx) { - _savePendingTransaction(tx, { - remove: true - }, function(err) { - _savePendingTransaction(sendTx.data, {}, function(err) { + } else { + if (res.data && !res.data.id) { + _savePendingTransaction(tx, { + status: 'error', + error: err + }, function(err) { if (err) $log.debug(err); _updateTxs(coinbasePendingTransactions); }); + return; + } + root.getTransaction(accessToken, accountId, res.data.id, function(err, sendTx) { + _savePendingTransaction(tx, { + remove: true + }, function(err) { + _savePendingTransaction(sendTx.data, {}, function(err) { + if (err) $log.debug(err); + _updateTxs(coinbasePendingTransactions); + }); + }); }); - }); - } + } + }); }); }; From b799ed43b193dadebc134d5181ffd6d838ea48d7 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 22 Jun 2017 16:49:24 -0300 Subject: [PATCH 35/84] Fix function name --- src/js/services/coinbaseService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/services/coinbaseService.js b/src/js/services/coinbaseService.js index eea9f5f3a..9161f5301 100644 --- a/src/js/services/coinbaseService.js +++ b/src/js/services/coinbaseService.js @@ -110,7 +110,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ root.getReductedAmountByFee = function(amount, cb) { // Fee Normal for a single transaction (450 bytes) var txNormalFeeKB = 450 / 1000; - feeService.getCurrentFeeValue(null, 'normal', function(err, feePerKB) { + feeService.getFeeRate(null, 'normal', function(err, feePerKB) { if (err) return cb(err); var feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8); From c54b38a9a954c84d9abd80c121e18e39774c29d5 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 11:38:13 -0300 Subject: [PATCH 36/84] add to low amount to incoming TXs --- src/js/controllers/confirm.js | 6 ++- src/js/controllers/modals/txpDetails.js | 10 ----- src/js/controllers/tx-details.js | 18 +++----- src/js/controllers/walletDetails.js | 5 ++- src/js/services/feeService.js | 56 ++++++++++++++++++++++-- src/js/services/profileService.js | 2 + src/js/services/txFormatService.js | 5 +++ src/js/services/walletService.js | 16 +++++-- src/sass/views/confirm.scss | 4 ++ src/sass/views/includes/txp-details.scss | 2 +- www/views/confirm.html | 9 +++- www/views/includes/walletHistory.html | 5 +++ www/views/modals/txp-details.html | 2 +- www/views/tx-details.html | 7 ++- 14 files changed, 110 insertions(+), 37 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index c9ce5943a..9623206f2 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -4,6 +4,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( var countDown = null; var CONFIRM_LIMIT_USD = 20; + var FEE_TOO_HIGH_LIMIT_PER = 15; var tx = {}; @@ -286,7 +287,10 @@ angular.module('copayApp.controllers').controller('confirmController', function( txFormatService.formatAlternativeStr(txp.fee, function(v) { txp.alternativeFeeStr = v; }); - txp.feeRatePerStr = (txp.fee / (txp.amount + txp.fee) * 100).toFixed(2) + '%'; + + var per = (txp.fee / (txp.amount + txp.fee) * 100); + txp.feeRatePerStr = per.toFixed(2) + '%'; + txp.feeToHigh = per > FEE_TOO_HIGH_LIMIT_PER; tx.txp[wallet.id] = txp; diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index bfab29089..3767b6e93 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -14,8 +14,6 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.canSign = $scope.wallet.canSign() || $scope.wallet.isPrivKeyExternal(); $scope.color = $scope.wallet.color; $scope.data = {}; - $scope.displayAmount = getDisplayAmount($scope.tx.amountStr); - $scope.displayUnit = getDisplayUnit($scope.tx.amountStr); displayFeeValues(); initActionList(); checkPaypro(); @@ -43,14 +41,6 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.buttonText += gettextCatalog.getString('to accept'); }; - function getDisplayAmount(amountStr) { - return amountStr.split(' ')[0]; - }; - - function getDisplayUnit(amountStr) { - return amountStr.split(' ')[1]; - }; - function initActionList() { $scope.actionList = []; diff --git a/src/js/controllers/tx-details.js b/src/js/controllers/tx-details.js index 5af36a0e0..6d76fe84c 100644 --- a/src/js/controllers/tx-details.js +++ b/src/js/controllers/tx-details.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $ionicHistory, $scope, $timeout, walletService, lodash, gettextCatalog, profileService, externalLinkService, popupService, ongoingProcess, txFormatService, txConfirmNotification) { +angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $ionicHistory, $scope, $timeout, walletService, lodash, gettextCatalog, profileService, externalLinkService, popupService, ongoingProcess, txFormatService, txConfirmNotification, feeService) { var txId; var listeners = []; @@ -40,14 +40,6 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio }); }); - function getDisplayAmount(amountStr) { - return amountStr.split(' ')[0]; - } - - function getDisplayUnit(amountStr) { - return amountStr.split(' ')[1]; - } - function updateMemo() { walletService.getTxNote($scope.wallet, $scope.btx.txid, function(err, note) { if (err) { @@ -122,12 +114,14 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio if ($scope.btx.action == 'moved') $scope.title = gettextCatalog.getString('Moved Funds'); } - $scope.displayAmount = getDisplayAmount($scope.btx.amountStr); - $scope.displayUnit = getDisplayUnit($scope.btx.amountStr); - updateMemo(); initActionList(); getFiatRate(); + + feeService.getLowAmount($scope.wallet, function(err, amount) { + $scope.btx.lowAmount = tx.amount< amount; + }); + $timeout(function() { $scope.$apply(); }); diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 24cf0afbc..259ca2ff3 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService) { +angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService, feeService) { var HISTORY_SHOW_LIMIT = 10; var currentTxHistoryPage = 0; @@ -154,9 +154,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun }); }; - $timeout(function() { + feeService.getLowAmount($scope.wallet, function(err, lowAmount){ walletService.getTxHistory($scope.wallet, { progressFn: progressFn, + lowAmount: lowAmount, }, function(err, txHistory) { $scope.updatingTxHistory = false; if (err) { diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index c88b867ca..a3e554f38 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -4,6 +4,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var root = {}; var CACHE_TIME_TS = 60; // 1 min + var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) // Constant fee options to translate root.feeOpts = { @@ -43,7 +44,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var feeRate = feeLevelRate.feePerKB; - if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network +' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B'); + if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B'); return cb(null, feeRate); }); @@ -55,8 +56,8 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou root.getFeeLevels = function(cb) { - if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000 ) { - $timeout( function() { + if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) { + $timeout(function() { return cb(null, cache.data, true); }, 1); } @@ -70,7 +71,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou return cb(gettextCatalog.getString('Could not get dynamic fee')); } - cache.updateTs =Date.now(); + cache.updateTs = Date.now(); cache.data = { 'livenet': levelsLivenet, 'testnet': levelsTestnet @@ -81,5 +82,52 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou }); }; + + // These 2 functions were taken from + // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 + + function getEstimatedSizeForSingleInput(wallet) { + switch (wallet.credentials.addressType) { + case 'P2PKH': + return 147; + default: + case 'P2SH': + return wallet.m * 72 + wallet.n * 36 + 44; + } + }; + + + function getEstimatedSize(wallet) { + // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. + var safetyMargin = 0.02; + + var overhead = 4 + 4 + 9 + 9; + var inputSize = getEstimatedSizeForSingleInput(wallet); + var outputSize = 34; + var nbInputs = 1; //Assume 1 input + var nbOutputs = 2; // Assume 2 outputs + + var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; + return parseInt((size * (1 + safetyMargin)).toFixed(0)); + }; + + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, cb) { + root.getFeeLevels(function(err, levels) { + if (err) return cb(err); + + var lowLevelRate = (lodash.find(levels[wallet.network], { + level: 'economy', + }).feePerKB / 1000).toFixed(0); + + var size = getEstimatedSize(wallet); + + var minFee = size * lowLevelRate; + + return cb(null, parseInt(minFee / (LOW_AMOUNT_RATIO))); + }); + }; + return root; }); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 8c5a93662..5f1118a1d 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -90,6 +90,8 @@ angular.module('copayApp.services') wallet.m = wallet.credentials.m; wallet.n = wallet.credentials.n; + wallet.lowAmount = + root.updateWalletSettings(wallet); root.wallet[walletId] = wallet; diff --git a/src/js/services/txFormatService.js b/src/js/services/txFormatService.js index 7524bb548..fee503a18 100644 --- a/src/js/services/txFormatService.js +++ b/src/js/services/txFormatService.js @@ -93,6 +93,11 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount); tx.feeStr = root.formatAmountStr(tx.fee || tx.fees); + if (tx.amountStr) { + tx.amountValueStr = tx.amountStr.split(' ')[0]; + tx.amountUnitStr = tx.amountStr.split(' ')[1]; + } + return tx; }; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index a9d45f3ff..7f53f1ce8 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -413,7 +413,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim $log.debug('Fixing Tx Cache Unit to:' + name) lodash.each(txs, function(tx) { - tx.amountStr = txFormatService.formatAmount(tx.amount) + name; tx.feeStr = txFormatService.formatAmount(tx.fees) + name; }); @@ -511,6 +510,15 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); } + function updateLowAmount(txs) { + if (!opts.lowAmount) return; + lodash.each(txs, function(tx) { + tx.lowAmount = tx.amount < opts.lowAmount; + }); + }; + + updateLowAmount(txs); + updateNotes(function() { // @@ -567,9 +575,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim root.getTx = function(wallet, txid, cb) { - function finish(list){ + function finish(list) { var tx = lodash.find(list, { - txid: txid + txid: txid }); if (!tx) return cb('Could not get transaction'); @@ -602,7 +610,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; - + root.getTxHistory = function(wallet, opts, cb) { opts = opts || {}; diff --git a/src/sass/views/confirm.scss b/src/sass/views/confirm.scss index 8adc61672..9ceee92c4 100644 --- a/src/sass/views/confirm.scss +++ b/src/sass/views/confirm.scss @@ -5,6 +5,10 @@ float: none; .fee-rate { display: inline-block; + .warn { + color: red; + } + } } .icon-amazon { diff --git a/src/sass/views/includes/txp-details.scss b/src/sass/views/includes/txp-details.scss index c68841a4c..7303c1f82 100644 --- a/src/sass/views/includes/txp-details.scss +++ b/src/sass/views/includes/txp-details.scss @@ -98,7 +98,7 @@ &.low-fees { display: flex; font-size: 14px; - color: #aaa; + color: #777; align-items: center; i { padding-right: 20px; diff --git a/www/views/confirm.html b/www/views/confirm.html index cff04ebf3..0048cb951 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -81,8 +81,15 @@ {{'Fee:' | translate}} {{tx.feeLevelName | translate}} {{tx.txp[wallet.id].feeStr || '...'}} - {{tx.txp[wallet.id].alternativeFeeStr || '...'}} - {{tx.txp[wallet.id].feeRatePerStr}} of the transaction + {{tx.txp[wallet.id].alternativeFeeStr || '...'}}  + · +   + {{tx.txp[wallet.id].feeRatePerStr}} of the sending amount + + + +
diff --git a/www/views/includes/walletHistory.html b/www/views/includes/walletHistory.html index bdd372e2f..81124ab7d 100644 --- a/www/views/includes/walletHistory.html +++ b/www/views/includes/walletHistory.html @@ -26,6 +26,11 @@ Low fees
+
+ + Amount too low to spend +
+
diff --git a/www/views/modals/txp-details.html b/www/views/modals/txp-details.html index a093ba441..c5649201a 100644 --- a/www/views/modals/txp-details.html +++ b/www/views/modals/txp-details.html @@ -19,7 +19,7 @@ Sending
-
{{displayAmount}} {{displayUnit}}
+
{{tx.amountValueStr}} {{tx.amountUnitStr}}
{{tx.alternativeAmountStr}}
diff --git a/www/views/tx-details.html b/www/views/tx-details.html index 5af45c3aa..cd13d7535 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -24,7 +24,7 @@ Receiving
-
{{displayAmount}} {{displayUnit}}
+
{{btx.amountValueStr}} {{btx.amountUnitStr}}
{{btx.alternativeAmountStr}} @@ -88,6 +88,11 @@ This transaction could take a long time to confirm or could be dropped due to the low fees set by the sender
+
+ + This transaction amount is too small given current Bitcoin network fees. Spending these funds will incur in fees comparable to the amount itself. +
+
Confirmations From e4799d639a2b6abeb934422b9853e841433292c7 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 13:44:49 -0300 Subject: [PATCH 37/84] add low amount in txhistory/details and balance --- src/js/controllers/walletDetails.js | 19 ++++++- src/js/services/feeService.js | 47 ----------------- src/js/services/profileService.js | 2 - src/js/services/walletService.js | 79 +++++++++++++++++++++++++++++ www/views/tx-details.html | 3 +- www/views/walletDetails.html | 6 +++ 6 files changed, 104 insertions(+), 52 deletions(-) diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 259ca2ff3..59799293a 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -47,6 +47,19 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun $scope.txps = lodash.sortBy(txps, 'createdOn').reverse(); }; + var analyzeUtxosDone; + + var analyzeUtxos = function() { + if (analyzeUtxosDone) return; + + feeService.getFeeLevels(function(err, levels){ + walletService.getLowUtxos($scope.wallet, levels, function(err, resp){ + analyzeUtxosDone = true; + $scope.lowUtxosWarning = resp.warning; + }); + }); + }; + var updateStatus = function(force) { $scope.updatingStatus = true; $scope.updateStatusError = null; @@ -72,6 +85,8 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun $scope.$apply(); }); + analyzeUtxos(); + }); }; @@ -154,10 +169,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun }); }; - feeService.getLowAmount($scope.wallet, function(err, lowAmount){ + feeService.getFeeLevels(function(err, levels){ walletService.getTxHistory($scope.wallet, { progressFn: progressFn, - lowAmount: lowAmount, + feeLevels: levels, }, function(err, txHistory) { $scope.updatingTxHistory = false; if (err) { diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index a3e554f38..1f51b046b 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -4,7 +4,6 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var root = {}; var CACHE_TIME_TS = 60; // 1 min - var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) // Constant fee options to translate root.feeOpts = { @@ -83,51 +82,5 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou }; - // These 2 functions were taken from - // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 - - function getEstimatedSizeForSingleInput(wallet) { - switch (wallet.credentials.addressType) { - case 'P2PKH': - return 147; - default: - case 'P2SH': - return wallet.m * 72 + wallet.n * 36 + 44; - } - }; - - - function getEstimatedSize(wallet) { - // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. - var safetyMargin = 0.02; - - var overhead = 4 + 4 + 9 + 9; - var inputSize = getEstimatedSizeForSingleInput(wallet); - var outputSize = 34; - var nbInputs = 1; //Assume 1 input - var nbOutputs = 2; // Assume 2 outputs - - var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; - return parseInt((size * (1 + safetyMargin)).toFixed(0)); - }; - - - // Approx utxo amount, from which the uxto is economically redeemable - root.getLowAmount = function(wallet, cb) { - root.getFeeLevels(function(err, levels) { - if (err) return cb(err); - - var lowLevelRate = (lodash.find(levels[wallet.network], { - level: 'economy', - }).feePerKB / 1000).toFixed(0); - - var size = getEstimatedSize(wallet); - - var minFee = size * lowLevelRate; - - return cb(null, parseInt(minFee / (LOW_AMOUNT_RATIO))); - }); - }; - return root; }); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 5f1118a1d..8c5a93662 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -90,8 +90,6 @@ angular.module('copayApp.services') wallet.m = wallet.credentials.m; wallet.n = wallet.credentials.n; - wallet.lowAmount = - root.updateWalletSettings(wallet); root.wallet[walletId] = wallet; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 7f53f1ce8..5e8930c82 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -3,6 +3,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) { // `wallet` is a decorated version of client. + var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) + var TOTAL_LOW_WARNING_RATIO = .15; + var root = {}; root.externalSource = { @@ -401,6 +404,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim var progressFn = opts.progressFn || function() {}; var foundLimitTx = false; + + if (opts.feeLevels) { + opts.lowAmount = root.getLowAmount(wallet, opts.feeLevels); + } + var fixTxsUnit = function(txs) { if (!txs || !txs[0] || !txs[0].amountStr) return; @@ -512,6 +520,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim function updateLowAmount(txs) { if (!opts.lowAmount) return; + lodash.each(txs, function(tx) { tx.lowAmount = tx.amount < opts.lowAmount; }); @@ -881,6 +890,76 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; + + // These 2 functions were taken from + // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 + + function getEstimatedSizeForSingleInput(wallet) { + switch (wallet.credentials.addressType) { + case 'P2PKH': + return 147; + default: + case 'P2SH': + return wallet.m * 72 + wallet.n * 36 + 44; + } + }; + + + root.getEstimatedTxSize = function(wallet, nbOutputs) { + // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. + var safetyMargin = 0.02; + + var overhead = 4 + 4 + 9 + 9; + var inputSize = getEstimatedSizeForSingleInput(wallet); + var outputSize = 34; + var nbInputs = 1; //Assume 1 input + var nbOutputs = nbOutputs || 2; // Assume 2 outputs + + var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; + return parseInt((size * (1 + safetyMargin)).toFixed(0)); + }; + + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + var lowLevelRate = (lodash.find(feeLevels[wallet.network], { + level: 'normal', + }).feePerKB / 1000).toFixed(0); + + var size = root.getEstimatedTxSize(wallet, nbOutputs); + var minFee = size * lowLevelRate; + + return parseInt(minFee / (LOW_AMOUNT_RATIO)); + }; + + + + root.getLowUtxos = function(wallet, levels, cb) { + + wallet.getUtxos({}, function(err, resp) { + if (err || !resp || !resp.length) return cb(); + + + var lowAmountN = root.getLowAmount(wallet, levels, resp.length + 1); +console.log('[walletService.js.946:lowAmountN:]',lowAmountN); //TODO + var total = lodash.sum(resp, 'satoshis'); +console.log('[walletService.js.948:total:]',total); //TODO + + var lowAmount1 = root.getLowAmount(wallet, levels); +console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO + var lowUtxos = lodash.filter(resp, function(x) { + return x.satoshis < lowAmount1; + }); + + var totalLow = lodash.sum(lowUtxos, 'satoshis'); + + return cb(err, { + lowUtxos: lowUtxos, + warning: lowAmountN / total > TOTAL_LOW_WARNING_RATIO, + }); + }); + }; + root.getAddress = function(wallet, forceNew, cb) { storageService.getLastAddress(wallet.id, function(err, addr) { if (err) return cb(err); diff --git a/www/views/tx-details.html b/www/views/tx-details.html index cd13d7535..6ef243116 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -90,7 +90,8 @@
- This transaction amount is too small given current Bitcoin network fees. Spending these funds will incur in fees comparable to the amount itself. + +This transaction amount is too small compared to current Bitcoin network fees. Spending these funds will need a Bitcoin network fee cost comparable to the funds itself.
diff --git a/www/views/walletDetails.html b/www/views/walletDetails.html index 93fe90f68..7b075a50c 100644 --- a/www/views/walletDetails.html +++ b/www/views/walletDetails.html @@ -158,6 +158,12 @@ Wallet not backed up + + + Spending this balance will need significant Bitcoin network fees + + +
From 58d79dd702ccf466f37d86ca5be1898ad6ff4a69 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 17:00:20 -0300 Subject: [PATCH 38/84] add balance warning --- src/js/controllers/addresses.js | 29 +++++++++++++++++++++++++++-- src/js/services/walletService.js | 27 ++++++++++++++++----------- www/views/addresses.html | 30 +++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/js/controllers/addresses.js b/src/js/controllers/addresses.js index cfc324521..19db9ad11 100644 --- a/src/js/controllers/addresses.js +++ b/src/js/controllers/addresses.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService) { +angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService, txFormatService, feeService) { var UNUSED_ADDRESS_LIMIT = 5; var BALANCE_ADDRESS_LIMIT = 5; var config = configService.getSync().wallet.settings; @@ -55,7 +55,7 @@ angular.module('copayApp.controllers').controller('addressesController', functio $scope.latestWithBalance = lodash.slice(withBalance, 0, BALANCE_ADDRESS_LIMIT); lodash.each(withBalance, function(a) { - a.balanceStr = (a.amount * satToUnit).toFixed(unitDecimals) + ' ' + unitName; + a.balanceStr = txFormatService.formatAmount(a.amount); }); $scope.viewAll = { @@ -72,6 +72,31 @@ angular.module('copayApp.controllers').controller('addressesController', functio }); }); }); + + + + feeService.getFeeLevels(function(err, levels){ + walletService.getLowUtxos($scope.wallet, levels, function(err, resp) { + if (err) return; + + if (resp.allUtxos && resp.allUtxos.length) { + + + var allSum = lodash.sum(resp.allUtxos || 0, 'satoshis'); + var per = (resp.minFee / allSum) * 100; + + $scope.lowWarning = resp.warning; + $scope.lowUtxosNb = resp.lowUtxos.length; + $scope.allUtxosNb = resp.allUtxos.length; + $scope.lowUtxosSum = txFormatService.formatAmountStr(lodash.sum(resp.lowUtxos || 0, 'satoshis')); + $scope.allUtxosSum = txFormatService.formatAmountStr(allSum); + $scope.minFee = txFormatService.formatAmountStr(resp.minFee || 0); + $scope.minFeePer = per.toFixed(2) + '%'; + + + } + }); + }); }; function processPaths(list) { diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 5e8930c82..2a33cf091 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -1,10 +1,12 @@ 'use strict'; angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) { - // `wallet` is a decorated version of client. - var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) - var TOTAL_LOW_WARNING_RATIO = .15; + // Ratio low amount warning (fee/amount) in incoming TX + var LOW_AMOUNT_RATIO = 0.15; + + // Ratio of "many utxos" warning in total balance (fee/amount) + var TOTAL_LOW_WARNING_RATIO = .3; var root = {}; @@ -921,15 +923,20 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim // Approx utxo amount, from which the uxto is economically redeemable - root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + root.getMinFee = function(wallet, feeLevels, nbOutputs) { var lowLevelRate = (lodash.find(feeLevels[wallet.network], { level: 'normal', }).feePerKB / 1000).toFixed(0); var size = root.getEstimatedTxSize(wallet, nbOutputs); - var minFee = size * lowLevelRate; + return size * lowLevelRate; + }; - return parseInt(minFee / (LOW_AMOUNT_RATIO)); + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + var minFee = root.getMinFee(wallet,feeLevels, nbOutputs); + return parseInt( minFee / LOW_AMOUNT_RATIO); }; @@ -939,14 +946,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim wallet.getUtxos({}, function(err, resp) { if (err || !resp || !resp.length) return cb(); - var lowAmountN = root.getLowAmount(wallet, levels, resp.length + 1); -console.log('[walletService.js.946:lowAmountN:]',lowAmountN); //TODO var total = lodash.sum(resp, 'satoshis'); -console.log('[walletService.js.948:total:]',total); //TODO var lowAmount1 = root.getLowAmount(wallet, levels); -console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO var lowUtxos = lodash.filter(resp, function(x) { return x.satoshis < lowAmount1; }); @@ -954,8 +957,10 @@ console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO var totalLow = lodash.sum(lowUtxos, 'satoshis'); return cb(err, { - lowUtxos: lowUtxos, + allUtxos: resp || [], + lowUtxos: lowUtxos || [], warning: lowAmountN / total > TOTAL_LOW_WARNING_RATIO, + minFee: root.getMinFee(wallet, levels, resp.length), }); }); }; diff --git a/www/views/addresses.html b/www/views/addresses.html index 5e8ef5b32..2698aa55f 100644 --- a/www/views/addresses.html +++ b/www/views/addresses.html @@ -35,7 +35,7 @@
-
+
Unused Addresses
@@ -70,6 +70,34 @@
{{w.balanceStr}}
+ + +
+
+ Wallet Inputs +
+ +
+ Total wallet inputs +
+ {{allUtxosNb}} [{{allUtxosSum}}] +
+
+
+ Low amount inputs +
+ {{lowUtxosNb}} [{{ lowUtxosSum }}] +
+
+ +
+ Approximate fee to move all wallet's balance (with normal priority) +
+ {{minFeePer}} [{{minFee}}] +
+
+ +
From 4d23ae62c545c43f268926d90089d7564a67ceae Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 22 Jun 2017 17:20:55 -0300 Subject: [PATCH 39/84] Fix wording and function name --- src/js/services/coinbaseService.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/js/services/coinbaseService.js b/src/js/services/coinbaseService.js index 9161f5301..81566fa2b 100644 --- a/src/js/services/coinbaseService.js +++ b/src/js/services/coinbaseService.js @@ -107,23 +107,12 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; }; - root.getReductedAmountByFee = function(amount, cb) { - // Fee Normal for a single transaction (450 bytes) - var txNormalFeeKB = 450 / 1000; - feeService.getFeeRate(null, 'normal', function(err, feePerKB) { - if (err) return cb(err); - var feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8); - - return cb(null, amount - feeBTC, feeBTC); - }); - }; - root.checkEnoughFundsForFee = function(amount, cb) { - root.getReductedAmountByFee(amount, function(err, reductedAmount) { + _getNetAmount(amount, function(err, reducedAmount) { if (err) return cb(err); // Check if transaction has enough funds to transfer bitcoin from Coinbase to Copay - if (reductedAmount < 0) { + if (reducedAmount < 0) { return cb('Not enough funds for fee'); } @@ -177,6 +166,17 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }); }; + var _getNetAmount = function(amount, cb) { + // Fee Normal for a single transaction (450 bytes) + var txNormalFeeKB = 450 / 1000; + feeService.getFeeRate(null, 'normal', function(err, feePerKB) { + if (err) return cb(err); + var feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8); + + return cb(null, amount - feeBTC, feeBTC); + }); + }; + var _refreshToken = function(refreshToken, cb) { var req = { method: 'POST', @@ -681,7 +681,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ var _sendToWallet = function(tx, accessToken, accountId, coinbasePendingTransactions) { if (!tx) return; var desc = appConfigService.nameCase + ' Wallet'; - root.getReductedAmountByFee(tx.amount.amount, function(err, amountBTC, feeBTC) { + _getNetAmount(tx.amount.amount, function(err, amountBTC, feeBTC) { if (err) { _savePendingTransaction(tx, { status: 'error', From 52bf9c139dc419ac49862130a86708647daed888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Baz=C3=A1n?= Date: Thu, 22 Jun 2017 15:12:42 -0300 Subject: [PATCH 40/84] change copay app name and remove slider to accept for wp --- app-template/copay/appConfig.json | 4 ++-- src/js/controllers/advancedSettings.js | 2 +- src/js/controllers/confirm.js | 5 +++-- src/js/controllers/modals/txpDetails.js | 3 ++- src/js/controllers/preferences.js | 2 +- www/views/confirm.html | 4 ++-- www/views/modals/txp-details.html | 4 ++-- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app-template/copay/appConfig.json b/app-template/copay/appConfig.json index 72cb5c54d..557b9a472 100644 --- a/app-template/copay/appConfig.json +++ b/app-template/copay/appConfig.json @@ -17,8 +17,8 @@ "url": "https://copay.io", "appDescription": "Copay Bitcoin Wallet", "winAppName": "CopayWallet", - "WindowsStoreIdentityName": "18C7659D.CopayWallet", - "WindowsStoreDisplayName": "Copay Bitcoin Wallet", + "WindowsStoreIdentityName": "18C7659D.Copay-SecureBitcoinWallet", + "WindowsStoreDisplayName": "Copay - Secure Bitcoin Wallet", "windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c", "pushSenderId": "1036948132229", "description": "A Secure Bitcoin Wallet", diff --git a/src/js/controllers/advancedSettings.js b/src/js/controllers/advancedSettings.js index 89500af52..cd065200c 100644 --- a/src/js/controllers/advancedSettings.js +++ b/src/js/controllers/advancedSettings.js @@ -50,7 +50,7 @@ angular.module('copayApp.controllers').controller('advancedSettingsController', }; $scope.$on("$ionicView.beforeEnter", function(event, data) { - $scope.isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + $scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; updateConfig(); }); diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index c9ce5943a..da728f7a0 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -19,7 +19,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( // Platform info var isChromeApp = platformInfo.isChromeApp; var isCordova = platformInfo.isCordova; - + var isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; function refresh() { $timeout(function() { @@ -139,6 +139,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( // Other Scope vars $scope.isCordova = isCordova; + $scope.isWindowsPhoneApp = isWindowsPhoneApp; $scope.showAddress = false; updateTx(tx, null, {}, function() { @@ -308,7 +309,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( } function setButtonText(isMultisig, isPayPro) { - $scope.buttonText = gettextCatalog.getString(isCordova ? 'Slide' : 'Click') + ' '; + $scope.buttonText = gettextCatalog.getString(isCordova && !isWindowsPhoneApp ? 'Slide' : 'Click') + ' '; if (isPayPro) { $scope.buttonText += gettextCatalog.getString('to pay'); diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index bfab29089..0c4afc247 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -9,6 +9,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.init = function() { $scope.loading = null; $scope.isCordova = platformInfo.isCordova; + $scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; $scope.copayerId = $scope.wallet.credentials.copayerId; $scope.isShared = $scope.wallet.credentials.n > 1; $scope.canSign = $scope.wallet.canSign() || $scope.wallet.isPrivKeyExternal(); @@ -31,7 +32,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi }; function applyButtonText() { - $scope.buttonText = $scope.isCordova ? gettextCatalog.getString('Slide') + ' ' : gettextCatalog.getString('Click') + ' '; + $scope.buttonText = $scope.isCordova && !$scope.isWindowsPhoneApp ? gettextCatalog.getString('Slide') + ' ' : gettextCatalog.getString('Click') + ' '; var lastSigner = lodash.filter($scope.tx.actions, { type: 'accept' diff --git a/src/js/controllers/preferences.js b/src/js/controllers/preferences.js index d30413695..ef95c00db 100644 --- a/src/js/controllers/preferences.js +++ b/src/js/controllers/preferences.js @@ -76,7 +76,7 @@ angular.module('copayApp.controllers').controller('preferencesController', wallet = profileService.getWallet(data.stateParams.walletId); walletId = wallet.credentials.walletId; $scope.wallet = wallet; - $scope.isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; + $scope.isWindowsPhoneApp = platformInfo.isCordova && platformInfo.isWP; $scope.externalSource = null; if (!wallet) diff --git a/www/views/confirm.html b/www/views/confirm.html index cff04ebf3..afd2ef0eb 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -100,13 +100,13 @@ {{buttonText}} diff --git a/www/views/modals/txp-details.html b/www/views/modals/txp-details.html index a093ba441..8cc13f9b2 100644 --- a/www/views/modals/txp-details.html +++ b/www/views/modals/txp-details.html @@ -170,13 +170,13 @@ {{buttonText}} From bb528ff4ab07ae65ea63b96f2a0f9239e6fc379f Mon Sep 17 00:00:00 2001 From: Tang Bo Hao Date: Fri, 23 Jun 2017 18:29:36 +0800 Subject: [PATCH 41/84] fix 'account invalid number' error when join by using ledger source --- src/js/controllers/join.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/controllers/join.js b/src/js/controllers/join.js index 0acc5556b..c037d5b12 100644 --- a/src/js/controllers/join.js +++ b/src/js/controllers/join.js @@ -136,7 +136,7 @@ angular.module('copayApp.controllers').controller('joinController', } if ($scope.formData.seedSource.id == walletService.externalSource.ledger.id || $scope.formData.seedSource.id == walletService.externalSource.trezor.id || $scope.formData.seedSource.id == walletService.externalSource.intelTEE.id) { - var account = $scope.account; + var account = $scope.formData.account; if (!account || account < 1) { popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number')); return; From fdf73fa838d08fc8283810fdbd0d92d1e5873174 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 11:38:13 -0300 Subject: [PATCH 42/84] add to low amount to incoming TXs --- src/js/controllers/confirm.js | 6 ++- src/js/controllers/modals/txpDetails.js | 10 ----- src/js/controllers/tx-details.js | 18 +++----- src/js/controllers/walletDetails.js | 5 ++- src/js/services/feeService.js | 56 ++++++++++++++++++++++-- src/js/services/profileService.js | 2 + src/js/services/txFormatService.js | 5 +++ src/js/services/walletService.js | 16 +++++-- src/sass/views/confirm.scss | 4 ++ src/sass/views/includes/txp-details.scss | 2 +- www/views/confirm.html | 9 +++- www/views/includes/walletHistory.html | 5 +++ www/views/modals/txp-details.html | 2 +- www/views/tx-details.html | 7 ++- 14 files changed, 110 insertions(+), 37 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index c9ce5943a..9623206f2 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -4,6 +4,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( var countDown = null; var CONFIRM_LIMIT_USD = 20; + var FEE_TOO_HIGH_LIMIT_PER = 15; var tx = {}; @@ -286,7 +287,10 @@ angular.module('copayApp.controllers').controller('confirmController', function( txFormatService.formatAlternativeStr(txp.fee, function(v) { txp.alternativeFeeStr = v; }); - txp.feeRatePerStr = (txp.fee / (txp.amount + txp.fee) * 100).toFixed(2) + '%'; + + var per = (txp.fee / (txp.amount + txp.fee) * 100); + txp.feeRatePerStr = per.toFixed(2) + '%'; + txp.feeToHigh = per > FEE_TOO_HIGH_LIMIT_PER; tx.txp[wallet.id] = txp; diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index bfab29089..3767b6e93 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -14,8 +14,6 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.canSign = $scope.wallet.canSign() || $scope.wallet.isPrivKeyExternal(); $scope.color = $scope.wallet.color; $scope.data = {}; - $scope.displayAmount = getDisplayAmount($scope.tx.amountStr); - $scope.displayUnit = getDisplayUnit($scope.tx.amountStr); displayFeeValues(); initActionList(); checkPaypro(); @@ -43,14 +41,6 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi $scope.buttonText += gettextCatalog.getString('to accept'); }; - function getDisplayAmount(amountStr) { - return amountStr.split(' ')[0]; - }; - - function getDisplayUnit(amountStr) { - return amountStr.split(' ')[1]; - }; - function initActionList() { $scope.actionList = []; diff --git a/src/js/controllers/tx-details.js b/src/js/controllers/tx-details.js index 5af36a0e0..6d76fe84c 100644 --- a/src/js/controllers/tx-details.js +++ b/src/js/controllers/tx-details.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $ionicHistory, $scope, $timeout, walletService, lodash, gettextCatalog, profileService, externalLinkService, popupService, ongoingProcess, txFormatService, txConfirmNotification) { +angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $ionicHistory, $scope, $timeout, walletService, lodash, gettextCatalog, profileService, externalLinkService, popupService, ongoingProcess, txFormatService, txConfirmNotification, feeService) { var txId; var listeners = []; @@ -40,14 +40,6 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio }); }); - function getDisplayAmount(amountStr) { - return amountStr.split(' ')[0]; - } - - function getDisplayUnit(amountStr) { - return amountStr.split(' ')[1]; - } - function updateMemo() { walletService.getTxNote($scope.wallet, $scope.btx.txid, function(err, note) { if (err) { @@ -122,12 +114,14 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio if ($scope.btx.action == 'moved') $scope.title = gettextCatalog.getString('Moved Funds'); } - $scope.displayAmount = getDisplayAmount($scope.btx.amountStr); - $scope.displayUnit = getDisplayUnit($scope.btx.amountStr); - updateMemo(); initActionList(); getFiatRate(); + + feeService.getLowAmount($scope.wallet, function(err, amount) { + $scope.btx.lowAmount = tx.amount< amount; + }); + $timeout(function() { $scope.$apply(); }); diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 24cf0afbc..259ca2ff3 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService) { +angular.module('copayApp.controllers').controller('walletDetailsController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, $ionicPopover, $state, $stateParams, $ionicHistory, profileService, lodash, configService, platformInfo, walletService, txpModalService, externalLinkService, popupService, addressbookService, storageService, $ionicScrollDelegate, $window, bwcError, gettextCatalog, timeService, feeService) { var HISTORY_SHOW_LIMIT = 10; var currentTxHistoryPage = 0; @@ -154,9 +154,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun }); }; - $timeout(function() { + feeService.getLowAmount($scope.wallet, function(err, lowAmount){ walletService.getTxHistory($scope.wallet, { progressFn: progressFn, + lowAmount: lowAmount, }, function(err, txHistory) { $scope.updatingTxHistory = false; if (err) { diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index c88b867ca..a3e554f38 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -4,6 +4,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var root = {}; var CACHE_TIME_TS = 60; // 1 min + var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) // Constant fee options to translate root.feeOpts = { @@ -43,7 +44,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var feeRate = feeLevelRate.feePerKB; - if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network +' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B'); + if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B'); return cb(null, feeRate); }); @@ -55,8 +56,8 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou root.getFeeLevels = function(cb) { - if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000 ) { - $timeout( function() { + if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) { + $timeout(function() { return cb(null, cache.data, true); }, 1); } @@ -70,7 +71,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou return cb(gettextCatalog.getString('Could not get dynamic fee')); } - cache.updateTs =Date.now(); + cache.updateTs = Date.now(); cache.data = { 'livenet': levelsLivenet, 'testnet': levelsTestnet @@ -81,5 +82,52 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou }); }; + + // These 2 functions were taken from + // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 + + function getEstimatedSizeForSingleInput(wallet) { + switch (wallet.credentials.addressType) { + case 'P2PKH': + return 147; + default: + case 'P2SH': + return wallet.m * 72 + wallet.n * 36 + 44; + } + }; + + + function getEstimatedSize(wallet) { + // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. + var safetyMargin = 0.02; + + var overhead = 4 + 4 + 9 + 9; + var inputSize = getEstimatedSizeForSingleInput(wallet); + var outputSize = 34; + var nbInputs = 1; //Assume 1 input + var nbOutputs = 2; // Assume 2 outputs + + var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; + return parseInt((size * (1 + safetyMargin)).toFixed(0)); + }; + + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, cb) { + root.getFeeLevels(function(err, levels) { + if (err) return cb(err); + + var lowLevelRate = (lodash.find(levels[wallet.network], { + level: 'economy', + }).feePerKB / 1000).toFixed(0); + + var size = getEstimatedSize(wallet); + + var minFee = size * lowLevelRate; + + return cb(null, parseInt(minFee / (LOW_AMOUNT_RATIO))); + }); + }; + return root; }); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 8c5a93662..5f1118a1d 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -90,6 +90,8 @@ angular.module('copayApp.services') wallet.m = wallet.credentials.m; wallet.n = wallet.credentials.n; + wallet.lowAmount = + root.updateWalletSettings(wallet); root.wallet[walletId] = wallet; diff --git a/src/js/services/txFormatService.js b/src/js/services/txFormatService.js index 7524bb548..fee503a18 100644 --- a/src/js/services/txFormatService.js +++ b/src/js/services/txFormatService.js @@ -93,6 +93,11 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount); tx.feeStr = root.formatAmountStr(tx.fee || tx.fees); + if (tx.amountStr) { + tx.amountValueStr = tx.amountStr.split(' ')[0]; + tx.amountUnitStr = tx.amountStr.split(' ')[1]; + } + return tx; }; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index a9d45f3ff..7f53f1ce8 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -413,7 +413,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim $log.debug('Fixing Tx Cache Unit to:' + name) lodash.each(txs, function(tx) { - tx.amountStr = txFormatService.formatAmount(tx.amount) + name; tx.feeStr = txFormatService.formatAmount(tx.fees) + name; }); @@ -511,6 +510,15 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); } + function updateLowAmount(txs) { + if (!opts.lowAmount) return; + lodash.each(txs, function(tx) { + tx.lowAmount = tx.amount < opts.lowAmount; + }); + }; + + updateLowAmount(txs); + updateNotes(function() { // @@ -567,9 +575,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim root.getTx = function(wallet, txid, cb) { - function finish(list){ + function finish(list) { var tx = lodash.find(list, { - txid: txid + txid: txid }); if (!tx) return cb('Could not get transaction'); @@ -602,7 +610,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; - + root.getTxHistory = function(wallet, opts, cb) { opts = opts || {}; diff --git a/src/sass/views/confirm.scss b/src/sass/views/confirm.scss index 8adc61672..9ceee92c4 100644 --- a/src/sass/views/confirm.scss +++ b/src/sass/views/confirm.scss @@ -5,6 +5,10 @@ float: none; .fee-rate { display: inline-block; + .warn { + color: red; + } + } } .icon-amazon { diff --git a/src/sass/views/includes/txp-details.scss b/src/sass/views/includes/txp-details.scss index c68841a4c..7303c1f82 100644 --- a/src/sass/views/includes/txp-details.scss +++ b/src/sass/views/includes/txp-details.scss @@ -98,7 +98,7 @@ &.low-fees { display: flex; font-size: 14px; - color: #aaa; + color: #777; align-items: center; i { padding-right: 20px; diff --git a/www/views/confirm.html b/www/views/confirm.html index cff04ebf3..0048cb951 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -81,8 +81,15 @@ {{'Fee:' | translate}} {{tx.feeLevelName | translate}} {{tx.txp[wallet.id].feeStr || '...'}} - {{tx.txp[wallet.id].alternativeFeeStr || '...'}} - {{tx.txp[wallet.id].feeRatePerStr}} of the transaction + {{tx.txp[wallet.id].alternativeFeeStr || '...'}}  + · +   + {{tx.txp[wallet.id].feeRatePerStr}} of the sending amount + + + +
diff --git a/www/views/includes/walletHistory.html b/www/views/includes/walletHistory.html index bdd372e2f..81124ab7d 100644 --- a/www/views/includes/walletHistory.html +++ b/www/views/includes/walletHistory.html @@ -26,6 +26,11 @@ Low fees
+
+ + Amount too low to spend +
+
diff --git a/www/views/modals/txp-details.html b/www/views/modals/txp-details.html index a093ba441..c5649201a 100644 --- a/www/views/modals/txp-details.html +++ b/www/views/modals/txp-details.html @@ -19,7 +19,7 @@ Sending
-
{{displayAmount}} {{displayUnit}}
+
{{tx.amountValueStr}} {{tx.amountUnitStr}}
{{tx.alternativeAmountStr}}
diff --git a/www/views/tx-details.html b/www/views/tx-details.html index 5af45c3aa..cd13d7535 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -24,7 +24,7 @@ Receiving
-
{{displayAmount}} {{displayUnit}}
+
{{btx.amountValueStr}} {{btx.amountUnitStr}}
{{btx.alternativeAmountStr}} @@ -88,6 +88,11 @@ This transaction could take a long time to confirm or could be dropped due to the low fees set by the sender
+
+ + This transaction amount is too small given current Bitcoin network fees. Spending these funds will incur in fees comparable to the amount itself. +
+
Confirmations From b83c0590dcc53c1678521d858fc3aef3c1314ec2 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 13:44:49 -0300 Subject: [PATCH 43/84] add low amount in txhistory/details and balance --- src/js/controllers/walletDetails.js | 19 ++++++- src/js/services/feeService.js | 47 ----------------- src/js/services/profileService.js | 2 - src/js/services/walletService.js | 79 +++++++++++++++++++++++++++++ www/views/tx-details.html | 3 +- www/views/walletDetails.html | 6 +++ 6 files changed, 104 insertions(+), 52 deletions(-) diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 259ca2ff3..59799293a 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -47,6 +47,19 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun $scope.txps = lodash.sortBy(txps, 'createdOn').reverse(); }; + var analyzeUtxosDone; + + var analyzeUtxos = function() { + if (analyzeUtxosDone) return; + + feeService.getFeeLevels(function(err, levels){ + walletService.getLowUtxos($scope.wallet, levels, function(err, resp){ + analyzeUtxosDone = true; + $scope.lowUtxosWarning = resp.warning; + }); + }); + }; + var updateStatus = function(force) { $scope.updatingStatus = true; $scope.updateStatusError = null; @@ -72,6 +85,8 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun $scope.$apply(); }); + analyzeUtxos(); + }); }; @@ -154,10 +169,10 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun }); }; - feeService.getLowAmount($scope.wallet, function(err, lowAmount){ + feeService.getFeeLevels(function(err, levels){ walletService.getTxHistory($scope.wallet, { progressFn: progressFn, - lowAmount: lowAmount, + feeLevels: levels, }, function(err, txHistory) { $scope.updatingTxHistory = false; if (err) { diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index a3e554f38..1f51b046b 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -4,7 +4,6 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou var root = {}; var CACHE_TIME_TS = 60; // 1 min - var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) // Constant fee options to translate root.feeOpts = { @@ -83,51 +82,5 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou }; - // These 2 functions were taken from - // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 - - function getEstimatedSizeForSingleInput(wallet) { - switch (wallet.credentials.addressType) { - case 'P2PKH': - return 147; - default: - case 'P2SH': - return wallet.m * 72 + wallet.n * 36 + 44; - } - }; - - - function getEstimatedSize(wallet) { - // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. - var safetyMargin = 0.02; - - var overhead = 4 + 4 + 9 + 9; - var inputSize = getEstimatedSizeForSingleInput(wallet); - var outputSize = 34; - var nbInputs = 1; //Assume 1 input - var nbOutputs = 2; // Assume 2 outputs - - var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; - return parseInt((size * (1 + safetyMargin)).toFixed(0)); - }; - - - // Approx utxo amount, from which the uxto is economically redeemable - root.getLowAmount = function(wallet, cb) { - root.getFeeLevels(function(err, levels) { - if (err) return cb(err); - - var lowLevelRate = (lodash.find(levels[wallet.network], { - level: 'economy', - }).feePerKB / 1000).toFixed(0); - - var size = getEstimatedSize(wallet); - - var minFee = size * lowLevelRate; - - return cb(null, parseInt(minFee / (LOW_AMOUNT_RATIO))); - }); - }; - return root; }); diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 5f1118a1d..8c5a93662 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -90,8 +90,6 @@ angular.module('copayApp.services') wallet.m = wallet.credentials.m; wallet.n = wallet.credentials.n; - wallet.lowAmount = - root.updateWalletSettings(wallet); root.wallet[walletId] = wallet; diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 7f53f1ce8..5e8930c82 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -3,6 +3,9 @@ angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) { // `wallet` is a decorated version of client. + var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) + var TOTAL_LOW_WARNING_RATIO = .15; + var root = {}; root.externalSource = { @@ -401,6 +404,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim var progressFn = opts.progressFn || function() {}; var foundLimitTx = false; + + if (opts.feeLevels) { + opts.lowAmount = root.getLowAmount(wallet, opts.feeLevels); + } + var fixTxsUnit = function(txs) { if (!txs || !txs[0] || !txs[0].amountStr) return; @@ -512,6 +520,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim function updateLowAmount(txs) { if (!opts.lowAmount) return; + lodash.each(txs, function(tx) { tx.lowAmount = tx.amount < opts.lowAmount; }); @@ -881,6 +890,76 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }); }; + + // These 2 functions were taken from + // https://github.com/bitpay/bitcore-wallet-service/blob/master/lib/model/txproposal.js#L243 + + function getEstimatedSizeForSingleInput(wallet) { + switch (wallet.credentials.addressType) { + case 'P2PKH': + return 147; + default: + case 'P2SH': + return wallet.m * 72 + wallet.n * 36 + 44; + } + }; + + + root.getEstimatedTxSize = function(wallet, nbOutputs) { + // Note: found empirically based on all multisig P2SH inputs and within m & n allowed limits. + var safetyMargin = 0.02; + + var overhead = 4 + 4 + 9 + 9; + var inputSize = getEstimatedSizeForSingleInput(wallet); + var outputSize = 34; + var nbInputs = 1; //Assume 1 input + var nbOutputs = nbOutputs || 2; // Assume 2 outputs + + var size = overhead + inputSize * nbInputs + outputSize * nbOutputs; + return parseInt((size * (1 + safetyMargin)).toFixed(0)); + }; + + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + var lowLevelRate = (lodash.find(feeLevels[wallet.network], { + level: 'normal', + }).feePerKB / 1000).toFixed(0); + + var size = root.getEstimatedTxSize(wallet, nbOutputs); + var minFee = size * lowLevelRate; + + return parseInt(minFee / (LOW_AMOUNT_RATIO)); + }; + + + + root.getLowUtxos = function(wallet, levels, cb) { + + wallet.getUtxos({}, function(err, resp) { + if (err || !resp || !resp.length) return cb(); + + + var lowAmountN = root.getLowAmount(wallet, levels, resp.length + 1); +console.log('[walletService.js.946:lowAmountN:]',lowAmountN); //TODO + var total = lodash.sum(resp, 'satoshis'); +console.log('[walletService.js.948:total:]',total); //TODO + + var lowAmount1 = root.getLowAmount(wallet, levels); +console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO + var lowUtxos = lodash.filter(resp, function(x) { + return x.satoshis < lowAmount1; + }); + + var totalLow = lodash.sum(lowUtxos, 'satoshis'); + + return cb(err, { + lowUtxos: lowUtxos, + warning: lowAmountN / total > TOTAL_LOW_WARNING_RATIO, + }); + }); + }; + root.getAddress = function(wallet, forceNew, cb) { storageService.getLastAddress(wallet.id, function(err, addr) { if (err) return cb(err); diff --git a/www/views/tx-details.html b/www/views/tx-details.html index cd13d7535..6ef243116 100644 --- a/www/views/tx-details.html +++ b/www/views/tx-details.html @@ -90,7 +90,8 @@
- This transaction amount is too small given current Bitcoin network fees. Spending these funds will incur in fees comparable to the amount itself. + +This transaction amount is too small compared to current Bitcoin network fees. Spending these funds will need a Bitcoin network fee cost comparable to the funds itself.
diff --git a/www/views/walletDetails.html b/www/views/walletDetails.html index 93fe90f68..7b075a50c 100644 --- a/www/views/walletDetails.html +++ b/www/views/walletDetails.html @@ -158,6 +158,12 @@ Wallet not backed up + + + Spending this balance will need significant Bitcoin network fees + + +
From 44cd3cd4953f9996ec83206e167906692dd26148 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 22 Jun 2017 17:00:20 -0300 Subject: [PATCH 44/84] add balance warning --- src/js/controllers/addresses.js | 29 +++++++++++++++++++++++++++-- src/js/services/walletService.js | 27 ++++++++++++++++----------- www/views/addresses.html | 30 +++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/js/controllers/addresses.js b/src/js/controllers/addresses.js index cfc324521..19db9ad11 100644 --- a/src/js/controllers/addresses.js +++ b/src/js/controllers/addresses.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService) { +angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService, txFormatService, feeService) { var UNUSED_ADDRESS_LIMIT = 5; var BALANCE_ADDRESS_LIMIT = 5; var config = configService.getSync().wallet.settings; @@ -55,7 +55,7 @@ angular.module('copayApp.controllers').controller('addressesController', functio $scope.latestWithBalance = lodash.slice(withBalance, 0, BALANCE_ADDRESS_LIMIT); lodash.each(withBalance, function(a) { - a.balanceStr = (a.amount * satToUnit).toFixed(unitDecimals) + ' ' + unitName; + a.balanceStr = txFormatService.formatAmount(a.amount); }); $scope.viewAll = { @@ -72,6 +72,31 @@ angular.module('copayApp.controllers').controller('addressesController', functio }); }); }); + + + + feeService.getFeeLevels(function(err, levels){ + walletService.getLowUtxos($scope.wallet, levels, function(err, resp) { + if (err) return; + + if (resp.allUtxos && resp.allUtxos.length) { + + + var allSum = lodash.sum(resp.allUtxos || 0, 'satoshis'); + var per = (resp.minFee / allSum) * 100; + + $scope.lowWarning = resp.warning; + $scope.lowUtxosNb = resp.lowUtxos.length; + $scope.allUtxosNb = resp.allUtxos.length; + $scope.lowUtxosSum = txFormatService.formatAmountStr(lodash.sum(resp.lowUtxos || 0, 'satoshis')); + $scope.allUtxosSum = txFormatService.formatAmountStr(allSum); + $scope.minFee = txFormatService.formatAmountStr(resp.minFee || 0); + $scope.minFeePer = per.toFixed(2) + '%'; + + + } + }); + }); }; function processPaths(list) { diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 5e8930c82..2a33cf091 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -1,10 +1,12 @@ 'use strict'; angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) { - // `wallet` is a decorated version of client. - var LOW_AMOUNT_RATIO = 0.15; //Ratio low amount warning (econ fee/amount) - var TOTAL_LOW_WARNING_RATIO = .15; + // Ratio low amount warning (fee/amount) in incoming TX + var LOW_AMOUNT_RATIO = 0.15; + + // Ratio of "many utxos" warning in total balance (fee/amount) + var TOTAL_LOW_WARNING_RATIO = .3; var root = {}; @@ -921,15 +923,20 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim // Approx utxo amount, from which the uxto is economically redeemable - root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + root.getMinFee = function(wallet, feeLevels, nbOutputs) { var lowLevelRate = (lodash.find(feeLevels[wallet.network], { level: 'normal', }).feePerKB / 1000).toFixed(0); var size = root.getEstimatedTxSize(wallet, nbOutputs); - var minFee = size * lowLevelRate; + return size * lowLevelRate; + }; - return parseInt(minFee / (LOW_AMOUNT_RATIO)); + + // Approx utxo amount, from which the uxto is economically redeemable + root.getLowAmount = function(wallet, feeLevels, nbOutputs) { + var minFee = root.getMinFee(wallet,feeLevels, nbOutputs); + return parseInt( minFee / LOW_AMOUNT_RATIO); }; @@ -939,14 +946,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim wallet.getUtxos({}, function(err, resp) { if (err || !resp || !resp.length) return cb(); - var lowAmountN = root.getLowAmount(wallet, levels, resp.length + 1); -console.log('[walletService.js.946:lowAmountN:]',lowAmountN); //TODO var total = lodash.sum(resp, 'satoshis'); -console.log('[walletService.js.948:total:]',total); //TODO var lowAmount1 = root.getLowAmount(wallet, levels); -console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO var lowUtxos = lodash.filter(resp, function(x) { return x.satoshis < lowAmount1; }); @@ -954,8 +957,10 @@ console.log('[walletService.js.950:lowAmount1:]',lowAmount1); //TODO var totalLow = lodash.sum(lowUtxos, 'satoshis'); return cb(err, { - lowUtxos: lowUtxos, + allUtxos: resp || [], + lowUtxos: lowUtxos || [], warning: lowAmountN / total > TOTAL_LOW_WARNING_RATIO, + minFee: root.getMinFee(wallet, levels, resp.length), }); }); }; diff --git a/www/views/addresses.html b/www/views/addresses.html index 5e8ef5b32..2698aa55f 100644 --- a/www/views/addresses.html +++ b/www/views/addresses.html @@ -35,7 +35,7 @@
-
+
Unused Addresses
@@ -70,6 +70,34 @@
{{w.balanceStr}}
+ + +
+
+ Wallet Inputs +
+ +
+ Total wallet inputs +
+ {{allUtxosNb}} [{{allUtxosSum}}] +
+
+
+ Low amount inputs +
+ {{lowUtxosNb}} [{{ lowUtxosSum }}] +
+
+ +
+ Approximate fee to move all wallet's balance (with normal priority) +
+ {{minFeePer}} [{{minFee}}] +
+
+ +
From bdf0f594273487aad6963ab5a64cddb01e97b8b5 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 23 Jun 2017 08:52:45 -0300 Subject: [PATCH 45/84] fix sendmax --- src/js/controllers/confirm.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 9623206f2..1d455c4b9 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -243,13 +243,15 @@ angular.module('copayApp.controllers').controller('confirmController', function( updateAmount(); refresh(); + // End of quick refresh, before wallet is selected. + if (!wallet)return cb(); + feeService.getFeeRate(tx.network, tx.feeLevel, function(err, feeRate) { if (err) return cb(err); tx.feeRate = feeRate; tx.feeLevelName = feeService.feeOpts[tx.feeLevel]; - // End of quick refresh, before wallet is selected. if (!wallet) return cb(); From bb2111f9a9bddafb4dd61fa87fce6a9308e6b925 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Fri, 23 Jun 2017 09:22:17 -0300 Subject: [PATCH 46/84] Fix label separator by month or status in bp card --- src/sass/views/bitpayCard.scss | 2 +- src/sass/views/walletDetails.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sass/views/bitpayCard.scss b/src/sass/views/bitpayCard.scss index 294d60475..3d84f32a5 100644 --- a/src/sass/views/bitpayCard.scss +++ b/src/sass/views/bitpayCard.scss @@ -11,7 +11,7 @@ font-size: 14px; font-weight: 300; color: #727272; - padding: 2px 1rem; + padding: 1rem; background: #f8f8f9; i { position: absolute; diff --git a/src/sass/views/walletDetails.scss b/src/sass/views/walletDetails.scss index 3ee4846f4..8de214a4d 100644 --- a/src/sass/views/walletDetails.scss +++ b/src/sass/views/walletDetails.scss @@ -85,7 +85,7 @@ font-size: 14px; font-weight: 300; color: #727272; - padding: 2px 1rem; + padding: 1rem; background: #f8f8f9; } } From 250c65fdf8d9f9a2db6cd23b3f7427d06f3980b8 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Fri, 23 Jun 2017 09:56:59 -0300 Subject: [PATCH 47/84] Fix label padding --- www/views/walletDetails.html | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/www/views/walletDetails.html b/www/views/walletDetails.html index 7b075a50c..0041b352a 100644 --- a/www/views/walletDetails.html +++ b/www/views/walletDetails.html @@ -164,7 +164,7 @@ -
+
@@ -173,12 +173,8 @@
-
- -
+
+
Proposals Unsent transactions
From 5bcc0b072dc9634e57fe035754d42455ef70bb92 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 23 Jun 2017 10:24:14 -0300 Subject: [PATCH 48/84] fix refresh/fee --- src/js/controllers/confirm.js | 4 ++-- src/js/controllers/preferencesFee.js | 4 +++- src/js/services/feeService.js | 4 +--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 1d455c4b9..b2c37e692 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -567,16 +567,16 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; scope.hideModal = function(customFeeLevel) { + scope.chooseFeeLevelModal.hide(); $log.debug('Custom fee level choosen:' + customFeeLevel + ' was:' + tx.feeLevel); if (tx.feeLevel == customFeeLevel) - scope.chooseFeeLevelModal.hide(); + return; tx.feeLevel = customFeeLevel; updateTx(tx, wallet, { clearCache: true, dryRun: true, }, function() { - scope.chooseFeeLevelModal.hide(); }); }; }; diff --git a/src/js/controllers/preferencesFee.js b/src/js/controllers/preferencesFee.js index c08932cd2..3c3c6ce78 100644 --- a/src/js/controllers/preferencesFee.js +++ b/src/js/controllers/preferencesFee.js @@ -46,7 +46,9 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu } $scope.feeLevels = levels; updateCurrentValues(); - $scope.$apply(); + $timeout(function() { + $scope.$apply(); + }); }); }; diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index 1f51b046b..cdab6a7a5 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -56,9 +56,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou root.getFeeLevels = function(cb) { if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) { - $timeout(function() { - return cb(null, cache.data, true); - }, 1); + return cb(null, cache.data, true); } var walletClient = bwcService.getClient(); From 2c51b48961ac963fdbe5a81358f5ca8ffb492dbe Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 23 Jun 2017 10:38:05 -0300 Subject: [PATCH 49/84] fix refresh 2 --- src/js/controllers/confirm.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index b2c37e692..60222631e 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -276,11 +276,12 @@ angular.module('copayApp.controllers').controller('confirmController', function( updateAmount(); showSendMaxWarning(sendMaxInfo); } - refresh(); // txp already generated for this wallet? - if (tx.txp[wallet.id]) + if (tx.txp[wallet.id]) { + refresh(); return cb(); + } getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) { if (err) return cb(err); @@ -297,6 +298,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( tx.txp[wallet.id] = txp; $log.debug('Confirm. TX Fully Updated for wallet:' + wallet.id, tx); + refresh(); return cb(); }); From 4fa6db293e4288ee48a91bfed593a5981b3e09bf Mon Sep 17 00:00:00 2001 From: JDonadio Date: Fri, 23 Jun 2017 12:06:20 -0300 Subject: [PATCH 50/84] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e85f9a032..a713c6835 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,11 @@ cd copay Ensure you have [Node](https://nodejs.org/) installed, then install and start Copay: ```sh -npm install +npm run apply:copay npm start ``` -Visit [`localhost:3000`](http://localhost:3000/) to view the app. +Visit [`localhost:8100`](http://localhost:8100/) to view the app. A watch task is also available to rebuild components of the app as changes are made. This task can be run in a separate process – while the server started by `npm start` is running – to quickly test changes. From d6e4a70cdc524080c0dbff80aa7aeb9fa31d4de9 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 23 Jun 2017 12:11:54 -0300 Subject: [PATCH 51/84] handle err --- src/js/controllers/walletDetails.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js/controllers/walletDetails.js b/src/js/controllers/walletDetails.js index 59799293a..a41c32c2c 100644 --- a/src/js/controllers/walletDetails.js +++ b/src/js/controllers/walletDetails.js @@ -53,7 +53,9 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun if (analyzeUtxosDone) return; feeService.getFeeLevels(function(err, levels){ + if (err) return; walletService.getLowUtxos($scope.wallet, levels, function(err, resp){ + if (err || !resp) return; analyzeUtxosDone = true; $scope.lowUtxosWarning = resp.warning; }); From 0890f9e5e51c9c8d54d2cc131f25c89e7a00c7b3 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 23 Jun 2017 12:20:51 -0300 Subject: [PATCH 52/84] fix tx-details --- src/js/controllers/tx-details.js | 15 ++++++++++----- www/views/addresses.html | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/js/controllers/tx-details.js b/src/js/controllers/tx-details.js index 6d76fe84c..e65845af5 100644 --- a/src/js/controllers/tx-details.js +++ b/src/js/controllers/tx-details.js @@ -118,12 +118,17 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio initActionList(); getFiatRate(); - feeService.getLowAmount($scope.wallet, function(err, amount) { - $scope.btx.lowAmount = tx.amount< amount; - }); + feeService.getFeeLevels(function(err, levels) { + if (err) return; + walletService.getLowAmount($scope.wallet, levels, function(err, amount) { + if (err) return; + $scope.btx.lowAmount = tx.amount < amount; - $timeout(function() { - $scope.$apply(); + $timeout(function() { + $scope.$apply(); + }); + + }); }); }); }; diff --git a/www/views/addresses.html b/www/views/addresses.html index 2698aa55f..4831e7c81 100644 --- a/www/views/addresses.html +++ b/www/views/addresses.html @@ -91,7 +91,7 @@
- Approximate fee to move all wallet's balance (with normal priority) + Approximate Bitcoin network fee to transfer wallet's balance (with normal priority)
{{minFeePer}} [{{minFee}}]
From 4599ed16f64be653c0c6b21a81150e9435fb0323 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 23 Jun 2017 13:06:41 -0300 Subject: [PATCH 53/84] fix low --- src/js/services/walletService.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 2a33cf091..5414da09c 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -946,12 +946,14 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim wallet.getUtxos({}, function(err, resp) { if (err || !resp || !resp.length) return cb(); - var lowAmountN = root.getLowAmount(wallet, levels, resp.length + 1); - var total = lodash.sum(resp, 'satoshis'); + var minFee = root.getMinFee(wallet, levels, resp.length); - var lowAmount1 = root.getLowAmount(wallet, levels); + var balance = lodash.sum(resp, 'satoshis'); + + // for 2 outputs + var lowAmount = root.getLowAmount(wallet, levels); var lowUtxos = lodash.filter(resp, function(x) { - return x.satoshis < lowAmount1; + return x.satoshis < lowAmount; }); var totalLow = lodash.sum(lowUtxos, 'satoshis'); @@ -959,8 +961,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim return cb(err, { allUtxos: resp || [], lowUtxos: lowUtxos || [], - warning: lowAmountN / total > TOTAL_LOW_WARNING_RATIO, - minFee: root.getMinFee(wallet, levels, resp.length), + warning: minFee / balance > TOTAL_LOW_WARNING_RATIO, + minFee: minFee, }); }); }; From fd1bc9a823863479f7f4ee7e992207fa594577d8 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Fri, 23 Jun 2017 14:51:27 -0300 Subject: [PATCH 54/84] Fix translations bp card --- src/js/services/bitpayAccountService.js | 30 +++++++++++++++---------- www/views/bitpayCard.html | 10 ++++----- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/js/services/bitpayAccountService.js b/src/js/services/bitpayAccountService.js index 7ab5a1bf7..8204da246 100644 --- a/src/js/services/bitpayAccountService.js +++ b/src/js/services/bitpayAccountService.js @@ -14,18 +14,18 @@ angular.module('copayApp.services').factory('bitpayAccountService', function($lo * email: email address associated with bitpay account * otp: two-factor one-time use password * } - * + * * pairingReason - text string to be embedded into popup message. If `null` then the reason * message is not shown to the UI. * "To {{reason}} you must pair this app with your BitPay account ({{email}})." - * + * * cb - callback after completion * callback(err, paired, apiContext) * * err - something unexpected happened which prevented the pairing - * + * * paired - boolean indicating whether the pairing was compledted by the user - * + * * apiContext - the context needed for making future api calls * { * token: api token for use in future calls @@ -33,6 +33,7 @@ angular.module('copayApp.services').factory('bitpayAccountService', function($lo * appIdentity: the identity of this app * } */ + root.pair = function(pairData, pairingReason, cb) { checkOtp(pairData, function(otp) { pairData.otp = otp; @@ -66,14 +67,19 @@ angular.module('copayApp.services').factory('bitpayAccountService', function($lo fetchBasicInfo(apiContext, function(err, basicInfo) { if (err) return cb(err); var title = gettextCatalog.getString('Add BitPay Account?'); - var msgDetail = 'Add this BitPay account ({{email}})?'; + var msg; + if (pairingReason) { - msgDetail = 'To {{reason}} you must first add your BitPay account - {{email}}'; - } - var msg = gettextCatalog.getString(msgDetail, { - reason: pairingReason, - email: pairData.email - }); + msg = gettextCatalog.getString('To {{reason}} you must first add your BitPay account - {{email}}', { + reason: pairingReason, + email: pairData.email + }); + } else { + msg = gettextCatalog.getString('Add this BitPay account ({{email}})?', { + email: pairData.email + }); + } + var ok = gettextCatalog.getString('Add Account'); var cancel = gettextCatalog.getString('Go back'); popupService.showConfirm(title, msg, ok, cancel, function(res) { @@ -182,5 +188,5 @@ angular.module('copayApp.services').factory('bitpayAccountService', function($lo }; return root; - + }); diff --git a/www/views/bitpayCard.html b/www/views/bitpayCard.html index c08297225..b787ca4a9 100644 --- a/www/views/bitpayCard.html +++ b/www/views/bitpayCard.html @@ -64,8 +64,8 @@