From 94363704abd33a2c8a54f6cf14cb24f507169bd9 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 24 Aug 2017 17:02:49 -0300 Subject: [PATCH] Adds bitcoin cash basic support (unit convertion, integrations, request specific amount, etc) --- src/js/controllers/addresses.js | 6 +- src/js/controllers/amount.js | 13 +- src/js/controllers/buyAmazon.js | 7 +- src/js/controllers/buyCoinbase.js | 152 +++++++------- src/js/controllers/buyGlidera.js | 71 ++++--- src/js/controllers/buyMercadoLibre.js | 7 +- src/js/controllers/confirm.js | 44 ++--- src/js/controllers/customAmount.js | 22 ++- src/js/controllers/modals/txpDetails.js | 2 +- src/js/controllers/sellCoinbase.js | 250 ++++++++++++------------ src/js/controllers/sellGlidera.js | 76 +++---- src/js/controllers/tab-receive.js | 3 +- src/js/controllers/topup.js | 7 +- src/js/controllers/tx-details.js | 2 +- src/js/filters/filters.js | 4 +- src/js/routes.js | 21 +- src/js/services/configService.js | 8 + src/js/services/feeService.js | 1 - src/js/services/profileService.js | 17 +- src/js/services/txFormatService.js | 34 ++-- src/js/services/walletService.js | 38 ++-- src/sass/views/amount.scss | 14 +- www/views/amount.html | 11 +- www/views/customAmount.html | 2 +- 24 files changed, 443 insertions(+), 369 deletions(-) diff --git a/src/js/controllers/addresses.js b/src/js/controllers/addresses.js index 47ec668ce..3bc0b4fea 100644 --- a/src/js/controllers/addresses.js +++ b/src/js/controllers/addresses.js @@ -88,9 +88,9 @@ angular.module('copayApp.controllers').controller('addressesController', functio $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.lowUtxosSum = txFormatService.formatAmountStr($scope.wallet, lodash.sum(resp.lowUtxos || 0, 'satoshis')); + $scope.allUtxosSum = txFormatService.formatAmountStr($scope.wallet, allSum); + $scope.minFee = txFormatService.formatAmountStr($scope.wallet, resp.minFee || 0); $scope.minFeePer = per.toFixed(2) + '%'; diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index 99912b99f..55c101024 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -21,6 +21,8 @@ angular.module('copayApp.controllers').controller('amountController', function($ $scope.nextStep = data.stateParams.nextStep; $scope.currency = data.stateParams.currency; $scope.forceCurrency = data.stateParams.forceCurrency; + $scope.forceChain = data.stateParams.forceChain || null; + $scope.chain = $scope.forceChain || data.stateParams.chain || 'BTC'; $scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' || $ionicHistory.backView().stateName == 'tabs.bitpayCard'); @@ -63,7 +65,6 @@ angular.module('copayApp.controllers').controller('amountController', function($ }); var config = configService.getSync().wallet.settings; - $scope.unitName = config.unitName; if (data.stateParams.currency) { $scope.alternativeIsoCode = data.stateParams.currency; } else { @@ -124,6 +125,12 @@ angular.module('copayApp.controllers').controller('amountController', function($ } }; + $scope.toggleChain = function() { + if ($scope.forceCurrency || $scope.forceChain) return; + + $scope.chain = $scope.chain == 'BTC' ? 'BCH' : 'BTC'; + }; + function checkFontSize() { if ($scope.amount && $scope.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true; else $scope.smallFont = false; @@ -227,7 +234,8 @@ angular.module('copayApp.controllers').controller('amountController', function($ $state.transitionTo($scope.nextStep, { id: _id, amount: $scope.useSendMax ? null : _amount, - currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : $scope.unitName, + currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : $scope.chain, + chain: $scope.chain, useSendMax: $scope.useSendMax }); } else { @@ -239,6 +247,7 @@ angular.module('copayApp.controllers').controller('amountController', function($ toName: $scope.toName, toEmail: $scope.toEmail, toColor: $scope.toColor, + chain: $scope.chain, useSendMax: $scope.useSendMax }); } diff --git a/src/js/controllers/buyAmazon.js b/src/js/controllers/buyAmazon.js index 986b2c908..e2418e80e 100644 --- a/src/js/controllers/buyAmazon.js +++ b/src/js/controllers/buyAmazon.js @@ -216,7 +216,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio }); var initialize = function(wallet) { - var parsedAmount = txFormatService.parseAmount(amount, currency); + var parsedAmount = txFormatService.parseAmount(wallet, amount, currency); $scope.currencyIsoCode = parsedAmount.currency; $scope.amountUnitStr = parsedAmount.amountUnitStr; var dataSrc = { @@ -260,7 +260,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio invoiceUrl: invoice.url, invoiceTime: invoice.invoiceTime }; - $scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); + $scope.totalAmountStr = txFormatService.formatAmountStr(wallet, ctxp.amount); setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); }); }); @@ -292,7 +292,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio $scope.wallets = profileService.getWallets({ onlyComplete: true, network: $scope.network, - hasFunds: true + hasFunds: true, + chain: 'BTC' }); if (lodash.isEmpty($scope.wallets)) { showErrorAndBack(null, gettextCatalog.getString('No wallets available')); diff --git a/src/js/controllers/buyCoinbase.js b/src/js/controllers/buyCoinbase.js index 57a95a0c7..57d9db779 100644 --- a/src/js/controllers/buyCoinbase.js +++ b/src/js/controllers/buyCoinbase.js @@ -33,6 +33,52 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct } }; + var processPaymentInfo = function() { + ongoingProcess.set('connectingCoinbase', true); + coinbaseService.init(function(err, res) { + 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.paymentMethods = []; + $scope.selectedPaymentMethodId = { value : null }; + coinbaseService.getPaymentMethods(accessToken, function(err, p) { + if (err) { + ongoingProcess.set('connectingCoinbase', false); + showErrorAndBack(err); + return; + } + + 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(); + }); + }); + }; + $scope.$on("$ionicView.beforeLeave", function(event, data) { $ionicConfig.views.swipeBackEnabled(true); }); @@ -42,81 +88,22 @@ 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.currency); + $scope.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false; + amount = data.stateParams.amount; + currency = data.stateParams.currency; - // Buy always in BTC - amount = (parsedAmount.amountSat / 100000000).toFixed(8); - currency = 'BTC'; - - $scope.amountUnitStr = parsedAmount.amountUnitStr; - - ongoingProcess.set('calculatingFee', true); - coinbaseService.checkEnoughFundsForFee(amount, function(err) { - ongoingProcess.set('calculatingFee', false); - if (err) { - showErrorAndBack(err); - return; - } - - $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) { - 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.paymentMethods = []; - $scope.selectedPaymentMethodId = { value : null }; - coinbaseService.getPaymentMethods(accessToken, function(err, p) { - if (err) { - ongoingProcess.set('connectingCoinbase', false); - showErrorAndBack(err); - return; - } - - 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(); - }); - }); + $scope.network = coinbaseService.getNetwork(); + $scope.wallets = profileService.getWallets({ + onlyComplete: true, + network: $scope.network, + chain: 'BTC' }); + + if (lodash.isEmpty($scope.wallets)) { + showErrorAndBack('No wallets available'); + return; + } + $scope.onWalletSelect($scope.wallets[0]); // Default first wallet }); $scope.buyRequest = function() { @@ -248,6 +235,25 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct $scope.onWalletSelect = function(wallet) { $scope.wallet = wallet; + var parsedAmount = txFormatService.parseAmount( + wallet, + amount, + currency); + + // Buy always in BTC + amount = (parsedAmount.amountSat / 100000000).toFixed(8); + currency = 'BTC'; + + $scope.amountUnitStr = parsedAmount.amountUnitStr; + ongoingProcess.set('calculatingFee', true); + coinbaseService.checkEnoughFundsForFee(amount, function(err) { + ongoingProcess.set('calculatingFee', false); + if (err) { + showErrorAndBack(err); + return; + } + processPaymentInfo(); + }); }; $scope.goBackHome = function() { diff --git a/src/js/controllers/buyGlidera.js b/src/js/controllers/buyGlidera.js index 46d0c3238..3b0ef1265 100644 --- a/src/js/controllers/buyGlidera.js +++ b/src/js/controllers/buyGlidera.js @@ -35,36 +35,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi } }; - $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.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false; - var parsedAmount = txFormatService.parseAmount( - data.stateParams.amount, - data.stateParams.currency); - - amount = parsedAmount.amount; - currency = parsedAmount.currency; - $scope.amountUnitStr = parsedAmount.amountUnitStr; - - $scope.network = glideraService.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 - + var processPaymentInfo = function() { ongoingProcess.set('connectingGlidera', true); glideraService.init(function(err, data) { if (err) { @@ -88,6 +59,33 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi $scope.buyInfo = buy; }); }); + }; + + $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.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false; + amount = data.stateParams.amount; + currency = data.stateParams.currency; + + $scope.network = glideraService.getNetwork(); + $scope.wallets = profileService.getWallets({ + onlyComplete: true, + network: $scope.network, + chain: 'BTC' + }); + + if (lodash.isEmpty($scope.wallets)) { + showErrorAndBack('No wallets available'); + return; + } + $scope.onWalletSelect($scope.wallets[0]); // Default first wallet }); var ask2FaCode = function(mode, cb) { @@ -105,7 +103,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi popupService.showPrompt(title, message, null, function(twoFaCode) { if (typeof twoFaCode == 'undefined') return cb(); return cb(twoFaCode); - }); + }); } else { return cb(); } @@ -116,7 +114,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi var okText = 'Confirm'; var cancelText = 'Cancel'; popupService.showConfirm(null, message, okText, cancelText, function(ok) { - if (!ok) return; + if (!ok) return; ongoingProcess.set('buyingBitcoin', true, statusChangeHandler); glideraService.get2faCode($scope.token, function(err, tfa) { if (err) { @@ -162,6 +160,15 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi $scope.onWalletSelect = function(wallet) { $scope.wallet = wallet; + var parsedAmount = txFormatService.parseAmount( + wallet, + amount, + currency); + + amount = parsedAmount.amount; + currency = parsedAmount.currency; + $scope.amountUnitStr = parsedAmount.amountUnitStr; + processPaymentInfo(); }; $scope.goBackHome = function() { diff --git a/src/js/controllers/buyMercadoLibre.js b/src/js/controllers/buyMercadoLibre.js index fa01a6143..a89a38d83 100644 --- a/src/js/controllers/buyMercadoLibre.js +++ b/src/js/controllers/buyMercadoLibre.js @@ -214,7 +214,7 @@ angular.module('copayApp.controllers').controller('buyMercadoLibreController', f }); var initialize = function(wallet) { - var parsedAmount = txFormatService.parseAmount(amount, currency); + var parsedAmount = txFormatService.parseAmount(wallet, amount, currency); $scope.currencyIsoCode = parsedAmount.currency; $scope.amountUnitStr = parsedAmount.amountUnitStr; var dataSrc = { @@ -258,7 +258,7 @@ angular.module('copayApp.controllers').controller('buyMercadoLibreController', f invoiceUrl: invoice.url, invoiceTime: invoice.invoiceTime }; - $scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); + $scope.totalAmountStr = txFormatService.formatAmountStr(wallet, ctxp.amount); setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); }); }); @@ -284,7 +284,8 @@ angular.module('copayApp.controllers').controller('buyMercadoLibreController', f $scope.network = mercadoLibreService.getNetwork(); $scope.wallets = profileService.getWallets({ onlyComplete: true, - network: $scope.network + network: $scope.network, + chain: 'BTC' }); if (lodash.isEmpty($scope.wallets)) { showErrorAndBack(null, gettextCatalog.getString('No wallets available')); diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index eff5aa4b2..4135ec4b3 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -69,14 +69,15 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.$on("$ionicView.beforeEnter", function(event, data) { - function setWalletSelector(network, minAmount, cb) { + function setWalletSelector(chain, network, minAmount, cb) { // no min amount? (sendMax) => look for no empty wallets minAmount = minAmount || 1; $scope.wallets = profileService.getWallets({ onlyComplete: true, - network: network + network: network, + chain: chain }); if (!$scope.wallets || !$scope.wallets.length) { @@ -137,6 +138,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, + chain: data.stateParams.chain || 'BTC', txp: {}, }; @@ -146,23 +148,21 @@ angular.module('copayApp.controllers').controller('confirmController', function( $scope.isWindowsPhoneApp = isWindowsPhoneApp; $scope.showAddress = false; - updateTx(tx, null, {}, function() { - $scope.walletSelectorTitle = gettextCatalog.getString('Send from'); + $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); - } - }); + setWalletSelector(tx.chain, 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); + } }); + }); @@ -238,7 +238,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( if (!tx.toAmount) return; // Amount - tx.amountStr = txFormatService.formatAmountStr(tx.toAmount); + tx.amountStr = txFormatService.formatAmountStr(wallet, tx.toAmount); tx.amountValueStr = tx.amountStr.split(' ')[0]; tx.amountUnitStr = tx.amountStr.split(' ')[1]; txFormatService.formatAlternativeStr(tx.toAmount, function(v) { @@ -280,7 +280,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( tx.sendMaxInfo = sendMaxInfo; tx.toAmount = tx.sendMaxInfo.amount; updateAmount(); - showSendMaxWarning(sendMaxInfo); + showSendMaxWarning(wallet, sendMaxInfo); } // txp already generated for this wallet? @@ -292,7 +292,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) { if (err) return cb(err); - txp.feeStr = txFormatService.formatAmountStr(txp.fee); + txp.feeStr = txFormatService.formatAmountStr(wallet, txp.fee); txFormatService.formatAlternativeStr(txp.fee, function(v) { txp.alternativeFeeStr = v; }); @@ -337,26 +337,26 @@ angular.module('copayApp.controllers').controller('confirmController', function( }; - function showSendMaxWarning(sendMaxInfo) { + function showSendMaxWarning(wallet, 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) + amountBelowFeeStr: txFormatService.formatAmountStr(wallet, sendMaxInfo.amountBelowFee) })); } 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) + amountAboveMaxSizeStr: txFormatService.formatAmountStr(wallet, sendMaxInfo.amountAboveMaxSize) })); } return warningMsg.join('\n'); }; var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", { - fee: txFormatService.formatAmountStr(sendMaxInfo.fee) + fee: txFormatService.formatAmountStr(wallet, sendMaxInfo.fee) }); var warningMsg = verifyExcludedUtxos(); diff --git a/src/js/controllers/customAmount.js b/src/js/controllers/customAmount.js index 9a2b46f6c..093edd568 100644 --- a/src/js/controllers/customAmount.js +++ b/src/js/controllers/customAmount.js @@ -15,7 +15,7 @@ angular.module('copayApp.controllers').controller('customAmountController', func showErrorAndBack('Error', 'No wallet selected'); return; } - + $scope.showShareButton = platformInfo.isCordova ? (platformInfo.isIOS ? 'iOS' : 'Android') : null; $scope.wallet = profileService.getWallet(walletId); @@ -25,11 +25,13 @@ angular.module('copayApp.controllers').controller('customAmountController', func showErrorAndBack('Error', 'Could not get the address'); return; } - + $scope.address = addr; - + + $scope.chain = (data.stateParams.chain).toLowerCase(); var parsedAmount = txFormatService.parseAmount( - data.stateParams.amount, + $scope.wallet, + data.stateParams.amount, data.stateParams.currency); // Amount in USD or BTC @@ -37,16 +39,16 @@ angular.module('copayApp.controllers').controller('customAmountController', func var currency = parsedAmount.currency; $scope.amountUnitStr = parsedAmount.amountUnitStr; - if (currency != 'BTC') { - // Convert to BTC + if (currency != 'BTC' && currency != 'BCH') { + // Convert to BTC or BCH var config = configService.getSync().wallet.settings; var amountUnit = txFormatService.satToUnit(parsedAmount.amountSat); - var btcParsedAmount = txFormatService.parseAmount(amountUnit, config.unitName); - + var btcParsedAmount = txFormatService.parseAmount($scope.wallet, amountUnit, $scope.wallet.chain); + $scope.amountBtc = btcParsedAmount.amount; $scope.altAmountStr = btcParsedAmount.amountUnitStr; } else { - $scope.amountBtc = amount; // BTC + $scope.amountBtc = amount; // BTC or BCH $scope.altAmountStr = txFormatService.formatAlternativeStr(parsedAmount.amountSat); } }); @@ -66,7 +68,7 @@ angular.module('copayApp.controllers').controller('customAmountController', func } $scope.copyToClipboard = function() { - return 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc; + return 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc + '&chain=' + $scope.chain; }; }); diff --git a/src/js/controllers/modals/txpDetails.js b/src/js/controllers/modals/txpDetails.js index 68c6d0778..79c8738c6 100644 --- a/src/js/controllers/modals/txpDetails.js +++ b/src/js/controllers/modals/txpDetails.js @@ -219,7 +219,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi copayerId: $scope.wallet.credentials.copayerId }); - $scope.tx = txFormatService.processTx(tx); + $scope.tx = txFormatService.processTx($scope.wallet, tx); if (!action && tx.status == 'pending') $scope.tx.pendingForUs = true; diff --git a/src/js/controllers/sellCoinbase.js b/src/js/controllers/sellCoinbase.js index c6fd31f58..3bee99602 100644 --- a/src/js/controllers/sellCoinbase.js +++ b/src/js/controllers/sellCoinbase.js @@ -34,124 +34,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func }, onSendStatusChange); }; - var checkTransaction = lodash.throttle(function(count, txp) { - $log.warn('Check if transaction has been received by Coinbase. Try ' + count + '/5'); - // TX amount in BTC - var satToBtc = 1 / 100000000; - var amountBTC = (txp.amount * satToBtc).toFixed(8); - coinbaseService.init(function(err, res) { - if (err) { - $log.error(err); - checkTransaction(count, txp); - return; - } - var accessToken = res.accessToken; - var accountId = res.accountId; - var sellPrice = null; - - coinbaseService.sellPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, sell) { - if (err) { - $log.debug(err); - checkTransaction(count, txp); - return; - } - sellPrice = sell.data; - - coinbaseService.getTransactions(accessToken, accountId, function(err, ctxs) { - if (err) { - $log.debug(err); - checkTransaction(count, txp); - return; - } - - var coinbaseTransactions = ctxs.data; - var txFound = false; - var ctx; - for(var i = 0; i < coinbaseTransactions.length; i++) { - ctx = coinbaseTransactions[i]; - if (ctx.type == 'send' && ctx.from && ctx.amount.amount == amountBTC ) { - $log.warn('Transaction found!', ctx); - txFound = true; - $log.debug('Saving transaction to process later...'); - ctx['payment_method'] = $scope.selectedPaymentMethodId.value; - ctx['status'] = 'pending'; // Forcing "pending" status to process later - ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data; - ctx['sell_price_amount'] = sellPrice ? sellPrice.amount : ''; - ctx['sell_price_currency'] = sellPrice ? sellPrice.currency : 'USD'; - ctx['description'] = appConfigService.nameCase + ' Wallet: ' + $scope.wallet.name; - coinbaseService.savePendingTransaction(ctx, null, function(err) { - ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); - if (err) $log.debug(err); - }); - return; - } - } - if (!txFound) { - // Transaction sent, but could not be verified by Coinbase.com - $log.warn('Transaction not found in Coinbase.'); - if (count < 5) { - checkTransaction(count + 1, txp); - } else { - ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); - showError('No transaction found'); - return; - } - } - }); - }); - }); - }, 8000, { - 'leading': true - }); - - var statusChangeHandler = function (processName, showName, isOn) { - $log.debug('statusChangeHandler: ', processName, showName, isOn); - if ( processName == 'sellingBitcoin' && !isOn) { - $scope.sendStatus = 'success'; - $timeout(function() { - $scope.$digest(); - }, 100); - } else if (showName) { - $scope.sendStatus = showName; - } - }; - - $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.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false; - var parsedAmount = txFormatService.parseAmount( - data.stateParams.amount, - data.stateParams.currency); - - amount = parsedAmount.amount; - currency = parsedAmount.currency; - $scope.amountUnitStr = parsedAmount.amountUnitStr; - - $scope.priceSensitivity = coinbaseService.priceSensitivity; - $scope.selectedPriceSensitivity = { data: coinbaseService.selectedPriceSensitivity }; - - $scope.network = coinbaseService.getNetwork(); - $scope.wallets = profileService.getWallets({ - m: 1, // Only 1-signature wallet - onlyComplete: true, - network: $scope.network, - hasFunds: true, - minAmount: parsedAmount.amountSat - }); - - if (lodash.isEmpty($scope.wallets)) { - showErrorAndBack('Insufficient funds'); - return; - } - $scope.wallet = $scope.wallets[0]; // Default first wallet - + var processPaymentInfo = function() { ongoingProcess.set('connectingCoinbase', true); coinbaseService.init(function(err, res) { if (err) { @@ -193,7 +76,121 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id; $scope.sellRequest(); }); - }); + }); + }; + + var checkTransaction = lodash.throttle(function(count, txp) { + $log.warn('Check if transaction has been received by Coinbase. Try ' + count + '/5'); + // TX amount in BTC + var satToBtc = 1 / 100000000; + var amountBTC = (txp.amount * satToBtc).toFixed(8); + coinbaseService.init(function(err, res) { + if (err) { + $log.error(err); + checkTransaction(count, txp); + return; + } + var accessToken = res.accessToken; + var accountId = res.accountId; + var sellPrice = null; + + coinbaseService.sellPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, sell) { + if (err) { + $log.debug(err); + checkTransaction(count, txp); + return; + } + sellPrice = sell.data; + + coinbaseService.getTransactions(accessToken, accountId, function(err, ctxs) { + if (err) { + $log.debug(err); + checkTransaction(count, txp); + return; + } + + var coinbaseTransactions = ctxs.data; + var txFound = false; + var ctx; + for(var i = 0; i < coinbaseTransactions.length; i++) { + ctx = coinbaseTransactions[i]; + if (ctx.type == 'send' && ctx.from && ctx.amount.amount == amountBTC ) { + $log.warn('Transaction found!', ctx); + txFound = true; + $log.debug('Saving transaction to process later...'); + ctx['payment_method'] = $scope.selectedPaymentMethodId.value; + ctx['status'] = 'pending'; // Forcing "pending" status to process later + ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data; + ctx['sell_price_amount'] = sellPrice ? sellPrice.amount : ''; + ctx['sell_price_currency'] = sellPrice ? sellPrice.currency : 'USD'; + ctx['description'] = appConfigService.nameCase + ' Wallet: ' + $scope.wallet.name; + coinbaseService.savePendingTransaction(ctx, null, function(err) { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + if (err) $log.debug(err); + }); + return; + } + } + if (!txFound) { + // Transaction sent, but could not be verified by Coinbase.com + $log.warn('Transaction not found in Coinbase.'); + if (count < 5) { + checkTransaction(count + 1, txp); + } else { + ongoingProcess.set('sellingBitcoin', false, statusChangeHandler); + showError('No transaction found'); + return; + } + } + }); + }); + }); + }, 8000, { + 'leading': true + }); + + var statusChangeHandler = function (processName, showName, isOn) { + $log.debug('statusChangeHandler: ', processName, showName, isOn); + if ( processName == 'sellingBitcoin' && !isOn) { + $scope.sendStatus = 'success'; + $timeout(function() { + $scope.$digest(); + }, 100); + } else if (showName) { + $scope.sendStatus = showName; + } + }; + + $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.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false; + amount = data.stateParams.amount; + currency = data.stateParams.currency; + + $scope.priceSensitivity = coinbaseService.priceSensitivity; + $scope.selectedPriceSensitivity = { data: coinbaseService.selectedPriceSensitivity }; + + $scope.network = coinbaseService.getNetwork(); + $scope.wallets = profileService.getWallets({ + m: 1, // Only 1-signature wallet + onlyComplete: true, + network: $scope.network, + hasFunds: true, + chain: 'BTC' + }); + + if (lodash.isEmpty($scope.wallets)) { + showErrorAndBack('Insufficient funds'); + return; + } + $scope.onWalletSelect($scope.wallets[0]); // Default first wallet }); $scope.sellRequest = function() { @@ -236,7 +233,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func var cancelText = 'Cancel'; popupService.showConfirm(null, message, okText, cancelText, function(ok) { if (!ok) return; - + ongoingProcess.set('sellingBitcoin', true, statusChangeHandler); coinbaseService.init(function(err, res) { if (err) { @@ -294,8 +291,8 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func checkTransaction(1, txSent); }); }); - }); - }); + }); + }); }); }; @@ -306,6 +303,15 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func $scope.onWalletSelect = function(wallet) { $scope.wallet = wallet; + var parsedAmount = txFormatService.parseAmount( + wallet, + amount, + currency); + + amount = parsedAmount.amount; + currency = parsedAmount.currency; + $scope.amountUnitStr = parsedAmount.amountUnitStr; + processPaymentInfo(); }; $scope.goBackHome = function() { diff --git a/src/js/controllers/sellGlidera.js b/src/js/controllers/sellGlidera.js index 90a6ed027..0978590c7 100644 --- a/src/js/controllers/sellGlidera.js +++ b/src/js/controllers/sellGlidera.js @@ -35,39 +35,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct } }; - $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.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false; - var parsedAmount = txFormatService.parseAmount( - data.stateParams.amount, - data.stateParams.currency); - - amount = parsedAmount.amount; - currency = parsedAmount.currency; - $scope.amountUnitStr = parsedAmount.amountUnitStr; - - $scope.network = glideraService.getNetwork(); - $scope.wallets = profileService.getWallets({ - m: 1, // Only 1-signature wallet - onlyComplete: true, - network: $scope.network, - hasFunds: true, - minAmount: parsedAmount.amountSat - }); - - if (lodash.isEmpty($scope.wallets)) { - showErrorAndBack('Insufficient funds'); - return; - } - $scope.wallet = $scope.wallets[0]; // Default first wallet - + var processPaymentInfo = function() { ongoingProcess.set('connectingGlidera', true); glideraService.init(function(err, data) { if (err) { @@ -91,6 +59,35 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct $scope.sellInfo = sell; }); }); + }; + + $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.isFiat = data.stateParams.currency != 'BCH' && data.stateParams.currency != 'BTC' ? true : false; + amount = data.stateParams.amount; + currency = data.stateParams.currency; + + $scope.network = glideraService.getNetwork(); + $scope.wallets = profileService.getWallets({ + m: 1, // Only 1-signature wallet + onlyComplete: true, + network: $scope.network, + hasFunds: true, + chain: 'BTC' + }); + + if (lodash.isEmpty($scope.wallets)) { + showErrorAndBack('Insufficient funds'); + return; + } + $scope.onWalletSelect($scope.wallets[0]); // Default first wallet }); var ask2FaCode = function(mode, cb) { @@ -108,7 +105,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct popupService.showPrompt(title, message, null, function(twoFaCode) { if (typeof twoFaCode == 'undefined') return cb(); return cb(twoFaCode); - }); + }); } else { return cb(); } @@ -119,7 +116,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct var okText = 'Confirm'; var cancelText = 'Cancel'; popupService.showConfirm(null, message, okText, cancelText, function(ok) { - if (!ok) return; + if (!ok) return; ongoingProcess.set('sellingBitcoin', true, statusChangeHandler); glideraService.get2faCode($scope.token, function(err, tfa) { if (err) { @@ -231,6 +228,15 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct $scope.onWalletSelect = function(wallet) { $scope.wallet = wallet; + var parsedAmount = txFormatService.parseAmount( + wallet, + amount, + currency); + + amount = parsedAmount.amount; + currency = parsedAmount.currency; + $scope.amountUnitStr = parsedAmount.amountUnitStr; + processPaymentInfo(); }; $scope.goBackHome = function() { diff --git a/src/js/controllers/tab-receive.js b/src/js/controllers/tab-receive.js index 39446924f..5bd61c70b 100644 --- a/src/js/controllers/tab-receive.js +++ b/src/js/controllers/tab-receive.js @@ -8,7 +8,8 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi $scope.requestSpecificAmount = function() { $state.go('tabs.paymentRequest.amount', { - id: $scope.wallet.credentials.walletId + id: $scope.wallet.credentials.walletId, + forceChain: $scope.wallet.chain }); }; diff --git a/src/js/controllers/topup.js b/src/js/controllers/topup.js index 3c66830b1..d5959e545 100644 --- a/src/js/controllers/topup.js +++ b/src/js/controllers/topup.js @@ -218,7 +218,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s // Save TX in memory createdTx = ctxp; - $scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount); + $scope.totalAmountStr = txFormatService.formatAmountStr(wallet, ctxp.amount); setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); @@ -256,7 +256,8 @@ angular.module('copayApp.controllers').controller('topUpController', function($s $scope.wallets = profileService.getWallets({ onlyComplete: true, network: bitpayService.getEnvironment().network, - hasFunds: true + hasFunds: true, + chain: 'BTC' }); if (lodash.isEmpty($scope.wallets)) { @@ -319,7 +320,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s }); return; } - var parsedAmount = txFormatService.parseAmount(a, c); + var parsedAmount = txFormatService.parseAmount(wallet, a, c); initializeTopUp(wallet, parsedAmount); }); }; diff --git a/src/js/controllers/tx-details.js b/src/js/controllers/tx-details.js index ebd44f6a5..58eb473aa 100644 --- a/src/js/controllers/tx-details.js +++ b/src/js/controllers/tx-details.js @@ -112,7 +112,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not available at this time')); } - $scope.btx = txFormatService.processTx(tx); + $scope.btx = txFormatService.processTx($scope.wallet, tx); txFormatService.formatAlternativeStr(tx.fees, function(v) { $scope.btx.feeFiatStr = v; $scope.btx.feeRateStr = ($scope.btx.fees / ($scope.btx.amount + $scope.btx.fees) * 100).toFixed(2) + '%'; diff --git a/src/js/filters/filters.js b/src/js/filters/filters.js index 8d9a56d10..e074f803b 100644 --- a/src/js/filters/filters.js +++ b/src/js/filters/filters.js @@ -27,12 +27,10 @@ angular.module('copayApp.filters', []) } }) .filter('formatFiatAmount', ['$filter', '$locale', 'configService', - function(filter, locale, configService) { + function(filter, locale) { var numberFilter = filter('number'); var formats = locale.NUMBER_FORMATS; - var config = configService.getSync().wallet.settings; return function(amount) { - if (!config) return amount; var fractionSize = 2; var value = numberFilter(amount, fractionSize); diff --git a/src/js/routes.js b/src/js/routes.js index 59cfad4fa..04ae0ad6f 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -287,7 +287,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr */ .state('tabs.send.amount', { - url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor', + url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor/:chain', views: { 'tab-send@tabs': { controller: 'amountController', @@ -296,7 +296,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }) .state('tabs.send.confirm', { - url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:useSendMax', + url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:chain/:useSendMax', views: { 'tab-send@tabs': { controller: 'confirmController', @@ -681,7 +681,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr }) .state('tabs.paymentRequest.amount', { - url: '/amount', + url: '/amount/:forceChain', views: { 'tab-receive@tabs': { controller: 'amountController', @@ -690,7 +690,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }) .state('tabs.paymentRequest.confirm', { - url: '/confirm/:amount/:currency', + url: '/confirm/:amount/:currency/:chain', views: { 'tab-receive@tabs': { controller: 'customAmountController', @@ -923,6 +923,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr controllerAs: 'glidera', templateUrl: 'views/glidera.html' } + }, + params: { + forceChain: 'BTC' } }) .state('tabs.buyandsell.glidera.amount', { @@ -976,6 +979,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr controllerAs: 'coinbase', templateUrl: 'views/coinbase.html' } + }, + params: { + forceChain: 'BTC' } }) .state('tabs.preferences.coinbase', { @@ -1064,7 +1070,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr params: { nextStep: 'tabs.giftcards.mercadoLibre.buy', currency: 'BRL', - forceCurrency: true + forceCurrency: true, + forceChain: 'BTC' } }) .state('tabs.giftcards.mercadoLibre.buy', { @@ -1115,7 +1122,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr params: { nextStep: 'tabs.giftcards.amazon.buy', currency: 'USD', - forceCurrency: true + forceCurrency: true, + forceChain: 'BTC' } }) .state('tabs.giftcards.amazon.buy', { @@ -1155,6 +1163,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr params: { id: null, currency: 'USD', + forceChain: 'BTC', useSendMax: null } }) diff --git a/src/js/services/configService.js b/src/js/services/configService.js index a17fcf628..3fa2f1f59 100644 --- a/src/js/services/configService.js +++ b/src/js/services/configService.js @@ -143,6 +143,14 @@ angular.module('copayApp.services').factory('configService', function(storageSer configCache.bitpayAccount = defaultConfig.bitpayAccount; } + if (configCache.wallet.settings.unitCode == 'bit') { + // Convert to BTC. Bits will be disabled + configCache.wallet.settings.unitName = defaultConfig.wallet.settings.unitName; + configCache.wallet.settings.unitToSatoshi = defaultConfig.wallet.settings.unitToSatoshi; + configCache.wallet.settings.unitDecimals = defaultConfig.wallet.settings.unitDecimals; + configCache.wallet.settings.unitCode = defaultConfig.wallet.settings.unitCode; + } + } else { configCache = lodash.clone(defaultConfig); }; diff --git a/src/js/services/feeService.js b/src/js/services/feeService.js index 3a289bfd8..852c0cf31 100644 --- a/src/js/services/feeService.js +++ b/src/js/services/feeService.js @@ -64,7 +64,6 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou } var walletClient = bwcService.getClient(); - var unitName = configService.getSync().wallet.settings.unitName; walletClient.getFeeLevels('livenet', function(errLivenet, levelsLivenet) { walletClient.getFeeLevels('testnet', function(errTestnet, levelsTestnet) { diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js index 9f32b137f..b1d7b30e1 100644 --- a/src/js/services/profileService.js +++ b/src/js/services/profileService.js @@ -89,6 +89,7 @@ angular.module('copayApp.services') wallet.copayerId = wallet.credentials.copayerId; wallet.m = wallet.credentials.m; wallet.n = wallet.credentials.n; + wallet.chain = wallet.credentials.chain; root.updateWalletSettings(wallet); root.wallet[walletId] = wallet; @@ -222,11 +223,13 @@ angular.module('copayApp.services') return ((config.bwsFor && config.bwsFor[walletId]) || defaults.bws.url); }; - var client = bwcService.getClient(JSON.stringify(credentials), { bwsurl: getBWSURL(credentials.walletId), }); + // TODO: Should return "chain" = "BTC" or "BCH" + client.credentials.chain = 'BTC'; + var skipKeyValidation = shouldSkipValidation(credentials.walletId); if (!skipKeyValidation) root.runValidation(client, 500); @@ -749,6 +752,12 @@ angular.module('copayApp.services') var ret = lodash.values(root.wallet); + if (opts.chain) { + ret = lodash.filter(ret, function(x) { + return (x.credentials.chain == opts.chain); + }); + } + if (opts.network) { ret = lodash.filter(ret, function(x) { return (x.credentials.network == opts.network); @@ -848,7 +857,7 @@ angular.module('copayApp.services') }); }; - function process(notifications) { + function process(wallet, notifications) { if (!notifications) return []; var shown = lodash.sortBy(notifications, 'createdOn').reverse(); @@ -861,7 +870,7 @@ angular.module('copayApp.services') x.types = [x.type]; if (x.data && x.data.amount) - x.amountStr = txFormatService.formatAmountStr(x.data.amount); + x.amountStr = txFormatService.formatAmountStr(wallet, x.data.amount); x.action = function() { // TODO? @@ -939,7 +948,7 @@ angular.module('copayApp.services') notifications = lodash.sortBy(notifications, 'createdOn'); notifications = lodash.compact(lodash.flatten(notifications)).slice(0, MAX); var total = notifications.length; - return cb(null, process(notifications), total); + return cb(null, process(wallet, notifications), total); }; }); }); diff --git a/src/js/services/txFormatService.js b/src/js/services/txFormatService.js index 0df46fe86..e203ad69a 100644 --- a/src/js/services/txFormatService.js +++ b/src/js/services/txFormatService.js @@ -17,10 +17,10 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, return this.Utils.formatAmount(satoshis, config.unitCode, opts); }; - root.formatAmountStr = function(satoshis) { + root.formatAmountStr = function(wallet, satoshis) { +console.log('[txFormatService.js:20]',wallet); //TODO/ if (isNaN(satoshis)) return; - var config = configService.getSync().wallet.settings; - return root.formatAmount(satoshis) + ' ' + config.unitName; + return root.formatAmount(satoshis) + ' ' + wallet.chain; }; root.toFiat = function(satoshis, code, cb) { @@ -86,7 +86,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, }; }; - root.processTx = function(tx) { + root.processTx = function(wallet, tx) { if (!tx || tx.action == 'invalid') return tx; @@ -101,7 +101,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, tx.hasMultiplesOutputs = true; } tx.amount = lodash.reduce(tx.outputs, function(total, o) { - o.amountStr = root.formatAmountStr(o.amount); + o.amountStr = root.formatAmountStr(wallet, o.amount); o.alternativeAmountStr = root.formatAlternativeStr(o.amount); return total + o.amount; }, 0); @@ -109,9 +109,9 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, tx.toAddress = tx.outputs[0].toAddress; } - tx.amountStr = root.formatAmountStr(tx.amount); + tx.amountStr = root.formatAmountStr(wallet, tx.amount); tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount); - tx.feeStr = root.formatAmountStr(tx.fee || tx.fees); + tx.feeStr = root.formatAmountStr(wallet, tx.fee || tx.fees); if (tx.amountStr) { tx.amountValueStr = tx.amountStr.split(' ')[0]; @@ -145,8 +145,6 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, lodash.each(txps, function(tx) { - tx = txFormatService.processTx(tx); - // no future transactions... if (tx.createdOn > now) tx.createdOn = now; @@ -157,6 +155,8 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, return; } + tx = txFormatService.processTx(tx.wallet, tx); + var action = lodash.find(tx.actions, { copayerId: tx.wallet.copayerId }); @@ -180,7 +180,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, return txps; }; - root.parseAmount = function(amount, currency) { + root.parseAmount = function(wallet, amount, currency) { var config = configService.getSync().wallet.settings; var satToBtc = 1 / 100000000; var unitToSatoshi = config.unitToSatoshi; @@ -189,21 +189,21 @@ angular.module('copayApp.services').factory('txFormatService', function($filter, var alternativeIsoCode = config.alternativeIsoCode; // If fiat currency - if (currency != 'bits' && currency != 'BTC' && currency != 'sat') { + if (currency != 'BCH' && 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 + amountUnitStr = root.formatAmountStr(wallet, amountSat); + // convert sat to BTC or BCH amount = (amountSat * satToBtc).toFixed(8); - currency = 'BTC'; + currency = wallet.chain; } else { amountSat = parseInt((amount * unitToSatoshi).toFixed(0)); - amountUnitStr = root.formatAmountStr(amountSat); - // convert unit to BTC + amountUnitStr = root.formatAmountStr(wallet, amountSat); + // convert unit to BTC or BCH amount = (amountSat * satToBtc).toFixed(8); - currency = 'BTC'; + currency = wallet.chain; } return { diff --git a/src/js/services/walletService.js b/src/js/services/walletService.js index 5414da09c..e90aa1a1d 100644 --- a/src/js/services/walletService.js +++ b/src/js/services/walletService.js @@ -2,8 +2,8 @@ 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) { - // Ratio low amount warning (fee/amount) in incoming TX - var LOW_AMOUNT_RATIO = 0.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; @@ -130,7 +130,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim lodash.each(txps, function(tx) { - tx = txFormatService.processTx(tx); + tx = txFormatService.processTx(wallet, tx); // no future transactions... if (tx.createdOn > now) @@ -213,14 +213,13 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim // Selected unit cache.unitToSatoshi = config.settings.unitToSatoshi; cache.satToUnit = 1 / cache.unitToSatoshi; - cache.unitName = config.settings.unitName; //STR - cache.totalBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat) + ' ' + cache.unitName; - cache.lockedBalanceStr = txFormatService.formatAmount(cache.lockedBalanceSat) + ' ' + cache.unitName; - cache.availableBalanceStr = txFormatService.formatAmount(cache.availableBalanceSat) + ' ' + cache.unitName; - cache.spendableBalanceStr = txFormatService.formatAmount(cache.spendableAmount) + ' ' + cache.unitName; - cache.pendingBalanceStr = txFormatService.formatAmount(cache.pendingAmount) + ' ' + cache.unitName; + cache.totalBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat) + ' ' + wallet.chain; + cache.lockedBalanceStr = txFormatService.formatAmount(cache.lockedBalanceSat) + ' ' + wallet.chain; + cache.availableBalanceStr = txFormatService.formatAmount(cache.availableBalanceSat) + ' ' + wallet.chain; + cache.spendableBalanceStr = txFormatService.formatAmount(cache.spendableAmount) + ' ' + wallet.chain; + cache.pendingBalanceStr = txFormatService.formatAmount(cache.pendingAmount) + ' ' + wallet.chain; cache.alternativeName = config.settings.alternativeName; cache.alternativeIsoCode = config.settings.alternativeIsoCode; @@ -366,7 +365,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim wallet.hasUnsafeConfirmed = false; lodash.each(txs, function(tx) { - tx = txFormatService.processTx(tx); + tx = txFormatService.processTx(wallet, tx); // no future transactions... if (tx.time > now) @@ -400,7 +399,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim var LIMIT = 50; var requestLimit = FIRST_LIMIT; var walletId = wallet.credentials.walletId; - var config = configService.getSync().wallet.settings; var opts = opts || {}; var progressFn = opts.progressFn || function() {}; @@ -414,17 +412,15 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim var fixTxsUnit = function(txs) { if (!txs || !txs[0] || !txs[0].amountStr) return; - var cacheUnit = txs[0].amountStr.split(' ')[1]; + var cacheChain = txs[0].amountStr.split(' ')[1]; - if (cacheUnit == config.unitName) + if (cacheChain == wallet.chain) return; - var name = ' ' + config.unitName; - - $log.debug('Fixing Tx Cache Unit to:' + name) + $log.debug('Fixing Tx Cache Unit to: ' + wallet.chain) lodash.each(txs, function(tx) { - tx.amountStr = txFormatService.formatAmount(tx.amount) + name; - tx.feeStr = txFormatService.formatAmount(tx.fees) + name; + tx.amountStr = txFormatService.formatAmountStr(wallet, tx.amount); + tx.feeStr = txFormatService.formatAmountStr(wallet, tx.fees); }); }; @@ -788,7 +784,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim //prefs.email (may come from arguments) prefs.email = config.emailNotifications.email; prefs.language = uxLanguage.getCurrentLanguage(); - prefs.unit = walletSettings.unitCode; + // prefs.unit = walletSettings.unitCode; // TODO: remove, not used updateRemotePreferencesFor(lodash.clone(clients), prefs, function(err) { if (err) return cb(err); @@ -922,7 +918,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }; - // Approx utxo amount, from which the uxto is economically redeemable + // Approx utxo amount, from which the uxto is economically redeemable root.getMinFee = function(wallet, feeLevels, nbOutputs) { var lowLevelRate = (lodash.find(feeLevels[wallet.network], { level: 'normal', @@ -933,7 +929,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim }; - // Approx utxo amount, from which the uxto is economically redeemable + // 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); diff --git a/src/sass/views/amount.scss b/src/sass/views/amount.scss index 627f905e8..1f6a242d6 100644 --- a/src/sass/views/amount.scss +++ b/src/sass/views/amount.scss @@ -139,6 +139,19 @@ } } .amount { + .icon-toggle { + font-size: 1.2em; + width: auto; + margin: 0.8em auto; + border: 1px solid $v-subtle-gray; + color: $v-dark-gray; + border-radius: 3px; + padding: 0 10px; + cursor: pointer; + @media(max-height: 280px) { + margin: 0.1em auto; + } + } &__editable { &--minimize { font-size: 22px; @@ -196,7 +209,6 @@ &__result-equiv { color: $v-mid-gray; font-size: 1.2em; - margin-top: 2rem; @media(max-height: 480px) { margin-top: 0; font-size: 16px; diff --git a/www/views/amount.html b/www/views/amount.html index 5dfee29e5..b3b4b0cfd 100644 --- a/www/views/amount.html +++ b/www/views/amount.html @@ -48,16 +48,19 @@
+
+
-
{{globalResult}} {{unitName}}
+
{{globalResult}} {{chain}}
≈ {{amountResult || '0.00'}} {{alternativeIsoCode}}
{{globalResult}} {{alternativeIsoCode}}
-
{{alternativeResult || '0.00'}} {{unitName}}
+
{{alternativeResult || '0.00'}} {{chain}}
diff --git a/www/views/customAmount.html b/www/views/customAmount.html index f9d5aafb7..6cd7be9c3 100644 --- a/www/views/customAmount.html +++ b/www/views/customAmount.html @@ -21,7 +21,7 @@
- +