diff --git a/src/js/controllers/buyCoinbase.js b/src/js/controllers/buyCoinbase.js index fb6a625a5..6066207ba 100644 --- a/src/js/controllers/buyCoinbase.js +++ b/src/js/controllers/buyCoinbase.js @@ -44,66 +44,77 @@ 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); - amount = parsedAmount.amount; - currency = parsedAmount.currency; + // Buy always in BTC + amount = (parsedAmount.amountSat / 100000000).toFixed(8); + currency = 'BTC'; + $scope.amountUnitStr = parsedAmount.amountUnitStr; - $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(); + }); }); }); }); @@ -139,12 +150,12 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct }; $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) { if (!ok) return; - + ongoingProcess.set('buyingBitcoin', true, statusChangeHandler); coinbaseService.init(function(err, res) { if (err) { diff --git a/src/js/services/coinbaseService.js b/src/js/services/coinbaseService.js index cce8544de..81566fa2b 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,19 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; }; + root.checkEnoughFundsForFee = function(amount, cb) { + _getNetAmount(amount, function(err, reducedAmount) { + if (err) return cb(err); + + // Check if transaction has enough funds to transfer bitcoin from Coinbase to Copay + if (reducedAmount < 0) { + return cb('Not enough funds for fee'); + } + + return cb(); + }); + }; + root.getSignupUrl = function() { return credentials.HOST + '/signup'; } @@ -153,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', @@ -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) { + _getNetAmount(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); + }); + }); }); - }); - } + } + }); }); };