From 36b64bdfa746dda16da6d8f9680322a3af241df2 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Tue, 27 Jun 2017 19:10:54 -0300 Subject: [PATCH 1/6] WIP: Ref topup. Fix sendmax --- src/js/controllers/topup.js | 364 ++++++++++++++++------------- src/js/services/onGoingProcess.js | 3 +- src/js/services/sendMax.js | 2 +- src/js/services/txFormatService.js | 24 +- www/views/topup.html | 52 ++--- 5 files changed, 248 insertions(+), 197 deletions(-) diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index c177a11d5..67bb35da7 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -2,9 +2,13 @@ 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 dataSrc = {}; + $scope.isCordova = platformInfo.isCordova; var cardId; - var sendMax; + var useSendMax; + var amount; + var currency; + var createdTx; + var message; var configWallet = configService.getSync().wallet; var showErrorAndBack = function(title, msg) { @@ -25,6 +29,12 @@ angular.module('copayApp.controllers').controller('topUpController', function($s popupService.showAlert(title, msg); }; + var satToAlternative = function(sat, cb) { + txFormatService.formatToCode(sat, $scope.currencyIsoCode, function(value) { + return cb(value); + }); + }; + var publishAndSign = function (wallet, txp, onSendStatusChange, cb) { if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { var err = gettextCatalog.getString('No signing proposal: No private key'); @@ -40,7 +50,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s var statusChangeHandler = function (processName, showName, isOn) { $log.debug('statusChangeHandler: ', processName, showName, isOn); - if ( processName == 'sendingTx' && !isOn) { + if (processName == 'topup' && !isOn && !hasError) { $scope.sendStatus = 'success'; $timeout(function() { $scope.$digest(); @@ -50,31 +60,152 @@ 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) { + var setTotalAmount = function(amountSat, invoiceFeeSat, networkFeeSat) { + satToAlternative(amountSat, function(a) { + $scope.amount = Number(a); + + satToAlternative(invoiceFeeSat, function(i) { + $scope.invoiceFee = Number(i); + + satToAlternative(networkFeeSat, function(n) { + $scope.networkFee = Number(n); + $scope.totalAmount = $scope.amount + $scope.invoiceFee + $scope.networkFee; + $timeout(function() { + $scope.$digest(); + }); + }); + }); + }); + }; + + var createInvoice = function(data, cb) { + bitpayCardService.topUp(cardId, data, function(err, invoiceId) { if (err) { - ongoingProcess.set('creatingInvoice', false); - showErrorAndBack(gettextCatalog.getString('Could not create the invoice'), err); - return; + return cb({ + title: gettextCatalog.getString('Could not create the invoice'), + message: err + }); } bitpayCardService.getInvoice(invoiceId, function(err, inv) { - ongoingProcess.set('creatingInvoice', false); if (err) { - showError(gettextCatalog.getString('Could not get the invoice'), err); - return; + return cb({ + title: gettextCatalog.getString('Could not get the invoice'), + message: err + }); } - $scope.invoice = inv; - $scope.expirationTime = ($scope.invoice.expirationTime - $scope.invoice.invoiceTime) / 1000; - $timeout(function() { - $scope.$digest(); - }, 1); + return cb(null, inv); }); }); }; + var createTx = function(wallet, invoice, message, cb) { + var payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null; + + if (!payProUrl) { + return cb({ + title: gettextCatalog.getString('Error in Payment Protocol'), + message: gettextCatalog.getString('Invalid URL') + }); + } + + var outputs = []; + var toAddress = invoice.bitcoinAddress; + var amountSat = parseInt(invoice.btcDue * 100000000); // BTC to Satoshi + + 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(wallet, txp, function(err, ctxp) { + if (err) { + return cb({ + title: gettextCatalog.getString('Could not create transaction'), + message: bwcError.msg(err) + }); + } + return cb(null, ctxp); + }); + }; + + var parseAmount = function(wallet, cb) { + if (useSendMax) { + sendMaxService.getInfo(wallet, function(err, values) { + if (err) { + return cb({ + title: null, + message: err + }) + } + var maxAmountBtc = (values.amount / 100000000).toFixed(8); +console.log('[topup.js:152]',maxAmountBtc); //TODO/ + + createInvoice({amount: maxAmountBtc, currency: 'BTC'}, function(err, inv) { + if (err) return cb(err); + + return cb(null, txFormatService.parseAmount(maxAmountBtc - inv.btcDue, 'BTC')); + }); + }); + } else { + return cb(null, txFormatService.parseAmount(amount, currency)); + } + }; + + var initializeTopUp = function(wallet, parsedAmount) { + $scope.amountUnitStr = parsedAmount.amountUnitStr; + var dataSrc = { + amount: parsedAmount.amount, + currency: parsedAmount.currency + }; + ongoingProcess.set('loadingTxInfo', true); + createInvoice(dataSrc, function(err, invoice) { +console.log('[topup.js:155] INVOICE',invoice); //TODO/ + if (err) { + ongoingProcess.set('loadingTxInfo', false); + showErrorAndBack(err.title, err.message); + return; + } + + var invoiceFeeSat = (invoice.buyerPaidBtcMinerFee * 100000000).toFixed(); + + message = gettextCatalog.getString("Top up {{amountStr}} to debit card ({{cardLastNumber}})", { + amountStr: $scope.amountUnitStr, + cardLastNumber: $scope.lastFourDigits + }); + + createTx(wallet, invoice, message, function(err, ctxp) { +console.log('[topup.js:159] CREATE TX',ctxp); //TODO + ongoingProcess.set('loadingTxInfo', false); + if (err) { + showErrorAndBack(err.title, err.message); + return; + } + + createdTx = ctxp; + + var totalAmountSat = ctxp.amount + ctxp.fee; + $scope.totalAmountStr = txFormatService.formatAmountStr(totalAmountSat); + + setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); + + }); + + }); + + }; + $scope.$on("$ionicView.beforeLeave", function(event, data) { $ionicConfig.views.swipeBackEnabled(true); }); @@ -84,136 +215,64 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }); $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, gettextCatalog.getString('No card selected')); - return; - } - - var parsedAmount = txFormatService.parseAmount( - data.stateParams.amount, - data.stateParams.currency); - - dataSrc['amount'] = parsedAmount.amount; - dataSrc['currency'] = parsedAmount.currency; - $scope.amountUnitStr = parsedAmount.amountUnitStr; - - $scope.network = bitpayService.getEnvironment().network; - $scope.wallets = profileService.getWallets({ - onlyComplete: true, - network: $scope.network, - hasFunds: true, - minAmount: parsedAmount.amountSat - }); - - if (lodash.isEmpty($scope.wallets)) { - showErrorAndBack(null, gettextCatalog.getString('Insufficient funds')); - return; - } - $scope.onWalletSelect($scope.wallets[0]); // Default first wallet + useSendMax = data.stateParams.useSendMax; + amount = data.stateParams.amount; + currency = data.stateParams.currency; +console.log('[topup.js:201]',cardId, useSendMax, amount, currency); //TODO/ bitpayCardService.get({ cardId: cardId, noRefresh: true }, function(err, card) { +console.log('[topup.js:203]',card[0]); //TODO/ if (err) { showErrorAndBack(null, err); return; } - $scope.cardInfo = card[0]; - bitpayCardService.setCurrencySymbol($scope.cardInfo); - bitpayCardService.getRates($scope.cardInfo.currency, function(err, data) { - if (err) $log.error(err); - $scope.rate = data.rate; + bitpayCardService.setCurrencySymbol(card[0]); + $scope.lastFourDigits = card[0].lastFourDigits; + $scope.currencySymbol = card[0].currencySymbol; + $scope.currencyIsoCode = card[0].currency; + + $scope.wallets = profileService.getWallets({ + onlyComplete: true, + network: bitpayService.getEnvironment().network, + hasFunds: true }); - }); - }); - - $scope.topUpConfirm = function() { - 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; - - ongoingProcess.set('topup', true, statusChangeHandler); - - 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')); + if (lodash.isEmpty($scope.wallets)) { + showErrorAndBack(null, gettextCatalog.getString('No wallets with funds')); return; } - payproService.getPayProDetails(payProUrl, function(err, payProDetails) { + bitpayCardService.getRates($scope.currencyIsoCode, function(err, r) { + if (err) $log.error(err); + $scope.rate = r.rate; + }); + + $scope.onWalletSelect($scope.wallets[0]); // Default first wallet + }); + }); + + $scope.topUpConfirm = function() { + var title = gettextCatalog.getString('Confirm'); + var okText = gettextCatalog.getString('OK'); + var cancelText = gettextCatalog.getString('Cancel'); + popupService.showConfirm(title, message, okText, cancelText, function(ok) { + if (!ok) { + $scope.sendStatus = ''; + return; + } + + ongoingProcess.set('topup', true, statusChangeHandler); + publishAndSign($scope.wallet, createdTx, function() {}, function(err, txSent) { if (err) { - ongoingProcess.set('topup', false, statusChangeHandler); - showError(gettextCatalog.getString('Error fetching invoice'), err); + ongoingProcess.set('topup', false); + $scope.sendStatus = ''; + showError(gettextCatalog.getString('Could not send transaction'), err); return; } - - 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(gettextCatalog.getString('Could not create transaction'), bwcError.msg(err)); - return; - } - - title = gettextCatalog.getString('Sending {{amountStr}} from {{walletName}}', { - amountStr: txFormatService.formatAmountStr(ctxp.amount, true), - walletName: $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); - if (!ok) { - $scope.sendStatus = ''; - return; - } - - $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) { - showError(gettextCatalog.getString('Could not send transaction'), err); - return; - } - }); - }); - }); - }, true); // Disable loader + ongoingProcess.set('topup', false, statusChangeHandler); + }); }); }; @@ -223,38 +282,17 @@ 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); - sendMaxService.getInfo($scope.wallet, function(err, values) { - ongoingProcess.set('retrievingInputs', false); - if (err) { - showErrorAndBack(null, err); - return; - } - var unitName = configWallet.settings.unitName; - var amountUnit = txFormatService.satToUnit(values.amount); - var parsedAmount = txFormatService.parseAmount( - amountUnit, - unitName); - - 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.')); + ongoingProcess.set('retrievingInputs', true); + parseAmount(wallet, function(err, parsedAmount) { +console.log('[topup.js:287]',parsedAmount); //TODO/ + ongoingProcess.set('retrievingInputs', false); + if (err) { + showErrorAndBack(err.title, err.message); + return; + } + initializeTopUp(wallet, parsedAmount); + }); }; $scope.goBackHome = function() { diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js index 454d566f8..0e7db5bfd 100644 --- a/src/js/services/onGoingProcess.js +++ b/src/js/services/onGoingProcess.js @@ -45,8 +45,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti 'cancelingGiftCard': 'Canceling Gift Card...', 'creatingGiftCard': 'Creating Gift Card...', 'buyingGiftCard': 'Buying Gift Card...', - 'topup': gettext('Top up in progress...'), - 'creatingInvoice': gettext('Creating invoice...') + 'topup': gettext('Top up in progress...') }; root.clear = function() { diff --git a/src/js/services/sendMax.js b/src/js/services/sendMax.js index 142679f2a..a9c238a1e 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.getCurrentFeeRate(wallet.credentials.network, null, function(err, feePerKb) { + feeService.getCurrentFeeRate(wallet.credentials.network, function(err, feePerKb) { if (err) return cb(err); var config = configService.getSync().wallet; diff --git a/src/js/services/txFormatService.js b/src/js/services/txFormatService.js index fee503a18..269064ac4 100644 --- a/src/js/services/txFormatService.js +++ b/src/js/services/txFormatService.js @@ -23,6 +23,26 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, return root.formatAmount(satoshis) + ' ' + config.unitName; }; + root.formatToCode = function(satoshis, code, cb) { + if (isNaN(satoshis)) return; + var val = function() { + var v1 = rateService.toFiat(satoshis, code); + if (!v1) return null; + + return v1.toFixed(2); + }; + + // Async version + if (cb) { + rateService.whenAvailable(function() { + return cb(val()); + }); + } else { + if (!rateService.isAvailable()) return null; + return val(); + }; + }; + root.formatToUSD = function(satoshis, cb) { if (isNaN(satoshis)) return; var val = function() { @@ -181,8 +201,8 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, } return { - amount: amount, - currency: currency, + amount: amount, + currency: currency, alternativeIsoCode: alternativeIsoCode, amountSat: amountSat, amountUnitStr: amountUnitStr diff --git a/www/views/topup.html b/www/views/topup.html index e5a5550e5..145a22f67 100644 --- a/www/views/topup.html +++ b/www/views/topup.html @@ -2,25 +2,27 @@ - Add funds + + {{'Add funds' | translate}} + -
+
- BitPay Card - Visa ® Prepaid Debit + BitPay Visa® Card ({{lastFourDigits}})
{{amountUnitStr}}
@ - {{rate | currency:cardInfo.currencySymbol:2}} per BTC + {{rate | currency:currencySymbol:2}} {{currencyIsoCode}} per BTC ...
@@ -40,44 +42,36 @@
- Deposit into + Details
- Card + Funds to be added - xxxx-xxxx-xxxx-{{cardInfo.lastFourDigits}} + {{amount | currency:currencySymbol:2}} {{currencyIsoCode}} + ...
- Account + Invoice Fee - {{cardInfo.email}} - -
- -
- Invoice -
-
- Expire in - - {{formatted}} + {{invoiceFee | currency:currencySymbol:2}} {{currencyIsoCode}} + ...
- Fee + Network Fee - {{invoice.buyerPaidBtcMinerFee}} + {{networkFee | currency:currencySymbol:2}} {{currencyIsoCode}} + ...
Total - - {{invoice.buyerTotalBtcAmount}} + + {{totalAmount | currency:currencySymbol:2}} {{currencyIsoCode}} + ({{totalAmountStr}})
-
@@ -85,16 +79,16 @@ + is-disabled="!wallet"> Add funds + is-disabled="!wallet"> Slide to confirm Date: Tue, 27 Jun 2017 20:09:20 -0300 Subject: [PATCH 2/6] Fix sendmax. Remove comments --- src/js/controllers/topup.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index 67bb35da7..7cb3236c7 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -149,13 +149,12 @@ angular.module('copayApp.controllers').controller('topUpController', function($s message: err }) } - var maxAmountBtc = (values.amount / 100000000).toFixed(8); -console.log('[topup.js:152]',maxAmountBtc); //TODO/ + var maxAmountBtc = Number((values.amount / 100000000).toFixed(8)); createInvoice({amount: maxAmountBtc, currency: 'BTC'}, function(err, inv) { if (err) return cb(err); - return cb(null, txFormatService.parseAmount(maxAmountBtc - inv.btcDue, 'BTC')); + return cb(null, txFormatService.parseAmount(maxAmountBtc - inv.buyerPaidBtcMinerFee, 'BTC')); }); }); } else { @@ -171,7 +170,6 @@ console.log('[topup.js:152]',maxAmountBtc); //TODO/ }; ongoingProcess.set('loadingTxInfo', true); createInvoice(dataSrc, function(err, invoice) { -console.log('[topup.js:155] INVOICE',invoice); //TODO/ if (err) { ongoingProcess.set('loadingTxInfo', false); showErrorAndBack(err.title, err.message); @@ -186,7 +184,6 @@ console.log('[topup.js:155] INVOICE',invoice); //TODO/ }); createTx(wallet, invoice, message, function(err, ctxp) { -console.log('[topup.js:159] CREATE TX',ctxp); //TODO ongoingProcess.set('loadingTxInfo', false); if (err) { showErrorAndBack(err.title, err.message); @@ -195,8 +192,7 @@ console.log('[topup.js:159] CREATE TX',ctxp); //TODO createdTx = ctxp; - var totalAmountSat = ctxp.amount + ctxp.fee; - $scope.totalAmountStr = txFormatService.formatAmountStr(totalAmountSat); + $scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); @@ -220,10 +216,8 @@ console.log('[topup.js:159] CREATE TX',ctxp); //TODO useSendMax = data.stateParams.useSendMax; amount = data.stateParams.amount; currency = data.stateParams.currency; -console.log('[topup.js:201]',cardId, useSendMax, amount, currency); //TODO/ bitpayCardService.get({ cardId: cardId, noRefresh: true }, function(err, card) { -console.log('[topup.js:203]',card[0]); //TODO/ if (err) { showErrorAndBack(null, err); return; @@ -285,7 +279,6 @@ console.log('[topup.js:203]',card[0]); //TODO/ $scope.wallet = wallet; ongoingProcess.set('retrievingInputs', true); parseAmount(wallet, function(err, parsedAmount) { -console.log('[topup.js:287]',parsedAmount); //TODO/ ongoingProcess.set('retrievingInputs', false); if (err) { showErrorAndBack(err.title, err.message); From 7e861532727f9d9f84800c400088382b1fcfc17d Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Wed, 28 Jun 2017 10:21:53 -0300 Subject: [PATCH 3/6] Fix names. Fix sendMax --- src/js/controllers/topup.js | 31 +++++++++++++++++++----------- src/js/services/txFormatService.js | 10 ++++++++-- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index 7cb3236c7..c75672b42 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -29,8 +29,8 @@ angular.module('copayApp.controllers').controller('topUpController', function($s popupService.showAlert(title, msg); }; - var satToAlternative = function(sat, cb) { - txFormatService.formatToCode(sat, $scope.currencyIsoCode, function(value) { + var satToFiat = function(sat, cb) { + txFormatService.toFiat(sat, $scope.currencyIsoCode, function(value) { return cb(value); }); }; @@ -61,13 +61,13 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }; var setTotalAmount = function(amountSat, invoiceFeeSat, networkFeeSat) { - satToAlternative(amountSat, function(a) { + satToFiat(amountSat, function(a) { $scope.amount = Number(a); - satToAlternative(invoiceFeeSat, function(i) { + satToFiat(invoiceFeeSat, function(i) { $scope.invoiceFee = Number(i); - satToAlternative(networkFeeSat, function(n) { + satToFiat(networkFeeSat, function(n) { $scope.networkFee = Number(n); $scope.totalAmount = $scope.amount + $scope.invoiceFee + $scope.networkFee; $timeout(function() { @@ -140,25 +140,32 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }); }; - var parseAmount = function(wallet, cb) { + var calculateAmount = function(wallet, cb) { + // Global variables defined beforeEnter + var a = amount; + var c = currency; + if (useSendMax) { - sendMaxService.getInfo(wallet, function(err, values) { + sendMaxService.getInfo(wallet, function(err, maxValues) { if (err) { return cb({ title: null, message: err }) } - var maxAmountBtc = Number((values.amount / 100000000).toFixed(8)); + var maxAmountBtc = Number((maxValues.amount / 100000000).toFixed(8)); createInvoice({amount: maxAmountBtc, currency: 'BTC'}, function(err, inv) { if (err) return cb(err); - return cb(null, txFormatService.parseAmount(maxAmountBtc - inv.buyerPaidBtcMinerFee, 'BTC')); + var invoiceFeeSat = parseInt((inv.buyerPaidBtcMinerFee * 100000000).toFixed()); + var newAmountSat = maxValues.amount - invoiceFeeSat; + + return cb(null, newAmountSat, 'sat'); }); }); } else { - return cb(null, txFormatService.parseAmount(amount, currency)); + return cb(null, a, c); } }; @@ -190,6 +197,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s return; } + // Save TX in memory createdTx = ctxp; $scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); @@ -278,12 +286,13 @@ angular.module('copayApp.controllers').controller('topUpController', function($s $scope.onWalletSelect = function(wallet) { $scope.wallet = wallet; ongoingProcess.set('retrievingInputs', true); - parseAmount(wallet, function(err, parsedAmount) { + calculateAmount(wallet, function(err, a, c) { ongoingProcess.set('retrievingInputs', false); if (err) { showErrorAndBack(err.title, err.message); return; } + var parsedAmount = txFormatService.parseAmount(a, c); initializeTopUp(wallet, parsedAmount); }); }; diff --git a/src/js/services/txFormatService.js b/src/js/services/txFormatService.js index 269064ac4..0df46fe86 100644 --- a/src/js/services/txFormatService.js +++ b/src/js/services/txFormatService.js @@ -23,7 +23,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, return root.formatAmount(satoshis) + ' ' + config.unitName; }; - root.formatToCode = function(satoshis, code, cb) { + root.toFiat = function(satoshis, code, cb) { if (isNaN(satoshis)) return; var val = function() { var v1 = rateService.toFiat(satoshis, code); @@ -189,9 +189,15 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, var alternativeIsoCode = config.alternativeIsoCode; // If fiat currency - if (currency != 'bits' && currency != 'BTC') { + if (currency != 'bits' && currency != 'BTC' && currency != 'sat') { amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency; amountSat = rateService.fromFiat(amount, currency).toFixed(0); + } else if (currency == 'sat') { + amountSat = amount; + amountUnitStr = root.formatAmountStr(amountSat); + // convert sat to BTC + amount = (amountSat * satToBtc).toFixed(8); + currency = 'BTC'; } else { amountSat = parseInt((amount * unitToSatoshi).toFixed(0)); amountUnitStr = root.formatAmountStr(amountSat); From 55f002144478215107462592591aa239209e2900 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Wed, 28 Jun 2017 10:49:20 -0300 Subject: [PATCH 4/6] Removes unused variable --- src/js/controllers/topup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index c75672b42..3b72623c6 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -50,7 +50,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 && !hasError) { + if (processName == 'topup' && !isOn) { $scope.sendStatus = 'success'; $timeout(function() { $scope.$digest(); From 0b514c0b448e7ebb4b90305213474c19c44d9c99 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Wed, 28 Jun 2017 13:49:37 -0300 Subject: [PATCH 5/6] Fix when insufficient funds --- src/js/controllers/topup.js | 25 ++++++++++++-- www/views/topup.html | 68 +++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index 3b72623c6..a6261fd35 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -21,12 +21,13 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }); }; - var showError = function(title, msg) { + var showError = function(title, msg, cb) { + cb = cb || function() {}; title = title || gettextCatalog.getString('Error'); $scope.sendStatus = ''; $log.error(msg); msg = msg.errors ? msg.errors[0].message : msg; - popupService.showAlert(title, msg); + popupService.showAlert(title, msg, cb); }; var satToFiat = function(sat, cb) { @@ -153,6 +154,11 @@ angular.module('copayApp.controllers').controller('topUpController', function($s message: err }) } + + if (maxValues.amount == 0) { + return cb({message: gettextCatalog.getString('Insufficient funds for fee')}); + } + var maxAmountBtc = Number((maxValues.amount / 100000000).toFixed(8)); createInvoice({amount: maxAmountBtc, currency: 'BTC'}, function(err, inv) { @@ -161,6 +167,10 @@ angular.module('copayApp.controllers').controller('topUpController', function($s var invoiceFeeSat = parseInt((inv.buyerPaidBtcMinerFee * 100000000).toFixed()); var newAmountSat = maxValues.amount - invoiceFeeSat; + if (newAmountSat <= 0) { + return cb({message: gettextCatalog.getString('Insufficient funds for fee')}); + } + return cb(null, newAmountSat, 'sat'); }); }); @@ -256,6 +266,12 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }); $scope.topUpConfirm = function() { + + if (!createdTx) { + showError(null, gettextCatalog.getString('Transaction has not been created')); + return; + } + var title = gettextCatalog.getString('Confirm'); var okText = gettextCatalog.getString('OK'); var cancelText = gettextCatalog.getString('Cancel'); @@ -289,7 +305,10 @@ angular.module('copayApp.controllers').controller('topUpController', function($s calculateAmount(wallet, function(err, a, c) { ongoingProcess.set('retrievingInputs', false); if (err) { - showErrorAndBack(err.title, err.message); + createdTx = message = $scope.totalAmountStr = $scope.amountUnitStr = $scope.wallet = null; + showError(err.title, err.message, function() { + $scope.showWalletSelector(); + }); return; } var parsedAmount = txFormatService.parseAmount(a, c); diff --git a/www/views/topup.html b/www/views/topup.html index 145a22f67..76d43082d 100644 --- a/www/views/topup.html +++ b/www/views/topup.html @@ -20,7 +20,7 @@
{{amountUnitStr}}
-
+
@ {{rate | currency:currencySymbol:2}} {{currencyIsoCode}} per BTC ... @@ -41,36 +41,38 @@
-
- Details -
-
- Funds to be added - - {{amount | currency:currencySymbol:2}} {{currencyIsoCode}} - ... - -
-
- Invoice Fee - - {{invoiceFee | currency:currencySymbol:2}} {{currencyIsoCode}} - ... - -
-
- Network Fee - - {{networkFee | currency:currencySymbol:2}} {{currencyIsoCode}} - ... - -
-
- Total - - {{totalAmount | currency:currencySymbol:2}} {{currencyIsoCode}} - ({{totalAmountStr}}) - +
+
+ Details +
+
+ Funds to be added + + {{amount | currency:currencySymbol:2}} {{currencyIsoCode}} + ... + +
+
+ Invoice Fee + + {{invoiceFee | currency:currencySymbol:2}} {{currencyIsoCode}} + ... + +
+
+ Network Fee + + {{networkFee | currency:currencySymbol:2}} {{currencyIsoCode}} + ... + +
+
+ Total + + {{totalAmount | currency:currencySymbol:2}} {{currencyIsoCode}} + ({{totalAmountStr}}) + +
@@ -81,14 +83,14 @@ ng-click="topUpConfirm()" ng-if="!isCordova" click-send-status="sendStatus" - is-disabled="!wallet"> + is-disabled="!wallet || !totalAmountStr"> Add funds + is-disabled="!wallet || !totalAmountStr"> Slide to confirm Date: Wed, 28 Jun 2017 15:22:03 -0300 Subject: [PATCH 6/6] Fix UI --- src/sass/views/bitpayCard.scss | 4 ++++ www/views/topup.html | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sass/views/bitpayCard.scss b/src/sass/views/bitpayCard.scss index 3d84f32a5..5c2df4425 100644 --- a/src/sass/views/bitpayCard.scss +++ b/src/sass/views/bitpayCard.scss @@ -55,6 +55,10 @@ span { text-transform: capitalize; } + + .big-icon-svg { + padding: 0 12px 0 0; + } } .amount-label{ line-height: 30px; diff --git a/www/views/topup.html b/www/views/topup.html index 76d43082d..b033c88e5 100644 --- a/www/views/topup.html +++ b/www/views/topup.html @@ -87,7 +87,7 @@ Add funds