diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index 77bd6d0ec..c291e7c13 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -20,8 +20,8 @@ angular.module('copayApp.controllers').controller('amountController', function($ $scope.isGlidera = data.stateParams.isGlidera; $scope.glideraAccessToken = data.stateParams.glideraAccessToken; - // Coinbase parameters - $scope.isCoinbase = data.stateParams.isCoinbase; + // Coinbase + $scope.coinbase = data.stateParams.coinbase; $scope.cardId = data.stateParams.cardId; $scope.showMenu = $ionicHistory.backView() && $ionicHistory.backView().stateName == 'tabs.send'; @@ -30,13 +30,13 @@ angular.module('copayApp.controllers').controller('amountController', function($ $scope.toAddress = data.stateParams.toAddress; $scope.toName = data.stateParams.toName; $scope.toEmail = data.stateParams.toEmail; - $scope.showAlternativeAmount = !!$scope.cardId || !!$scope.isGiftCard || !!$scope.isGlidera || !!$scope.isCoinbase; + $scope.showAlternativeAmount = !!$scope.cardId || !!$scope.isGiftCard || !!$scope.isGlidera || !!$scope.coinbase; $scope.toColor = data.stateParams.toColor; $scope.showSendMax = false; $scope.customAmount = data.stateParams.customAmount; - if (!$scope.cardId && !$scope.isGiftCard && !$scope.isGlidera && !$scope.isCoinbase && !data.stateParams.toAddress) { + if (!$scope.cardId && !$scope.isGiftCard && !$scope.isGlidera && !$scope.coinbase && !data.stateParams.toAddress) { $log.error('Bad params at amount') throw ('bad params'); } @@ -50,51 +50,6 @@ angular.module('copayApp.controllers').controller('amountController', function($ }); } - if ($scope.isCoinbase) { - var currency = 'USD'; - - coinbaseService.init(function(err, data) { - if ($scope.isCoinbase == 'buy') { - coinbaseService.buyPrice(data.accessToken, currency, function(err, b) { - $scope.coinbaseBuyPrice = b.data || null; - }); - } else { - coinbaseService.sellPrice(data.accessToken, currency, function(err, s) { - $scope.coinbaseSellPrice = s.data || null; - }); - - var dataSrc = { - name: 'Received from ' + appConfigService.nameCase - }; - coinbaseService.createAddress(data.accessToken, data.accountId, dataSrc, function(err, data) { - $scope.toAddress = data.data.address; - }); - } - - $scope.coinbasePaymentMethods = []; - $scope.coinbaseSelectedPaymentMethodId = { value : null }; - coinbaseService.getPaymentMethods(data.accessToken, function(err, p) { - lodash.each(p.data, function(pm) { - if ($scope.isCoinbase == 'sell') { - if (pm.allow_sell) { - $scope.coinbasePaymentMethods.push(pm); - } - if (pm.allow_sell && pm.primary_sell) { - $scope.coinbaseSelectedPaymentMethodId.value = pm.id; - } - } else { - if (pm.allow_buy) { - $scope.coinbasePaymentMethods.push(pm); - } - if (pm.allow_buy && pm.primary_buy) { - $scope.coinbaseSelectedPaymentMethodId.value = pm.id; - } - } - }); - }); - }); - } - var reNr = /^[1234567890\.]$/; var reOp = /^[\*\+\-\/]$/; @@ -120,7 +75,11 @@ angular.module('copayApp.controllers').controller('amountController', function($ var config = configService.getSync().wallet.settings; $scope.unitName = config.unitName; - $scope.alternativeIsoCode = !!$scope.cardId || !!$scope.isGiftCard ? 'USD' : config.alternativeIsoCode; + if (data.stateParams.currency) { + $scope.alternativeIsoCode = data.stateParams.currency; + } else { + $scope.alternativeIsoCode = !!$scope.cardId || !!$scope.isGiftCard ? 'USD' : config.alternativeIsoCode; + } $scope.specificAmount = $scope.specificAlternativeAmount = ''; $scope.isCordova = platformInfo.isCordova; unitToSatoshi = config.unitToSatoshi; @@ -398,29 +357,17 @@ angular.module('copayApp.controllers').controller('amountController', function($ isGlidera: $scope.isGlidera, glideraAccessToken: $scope.glideraAccessToken }); - } else if ($scope.isCoinbase) { - if (lodash.isEmpty($scope.coinbaseSelectedPaymentMethodId.value)) { - popupService.showAlert(gettextCatalog.getString('Error'), 'No Payment Method Selected'); - return; - } - if ($scope.isCoinbase == 'sell' && lodash.isEmpty($scope.toAddress)) { - popupService.showAlert(gettextCatalog.getString('Error'), 'No Destination Address'); - return; - } - var amountUSD = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount)); - if (amountUSD < 1) { - popupService.showAlert(gettextCatalog.getString('Error'), 'Amount must be at least 1.00 USD'); + } else if ($scope.coinbase) { + var amountAlternative = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount)); + if (amountAlternative < 1) { + popupService.showAlert(gettextCatalog.getString('Error'), 'Amount must be at least 1.00 ' + $scope.alternativeIsoCode); return; } - var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount; - $state.transitionTo('tabs.buyandsell.coinbase.confirm', { - toAmount: (amount * unitToSatoshi).toFixed(0), - toAddress: $scope.toAddress, - isCoinbase: $scope.isCoinbase, - coinbasePaymentMethodId: $scope.coinbaseSelectedPaymentMethodId.value, - coinbaseAmount: amountUSD, - coinbaseAmountCurrency: 'USD' + var goTo = 'tabs.buyandsell.coinbase.' + $scope.coinbase; + $state.transitionTo(goTo, { + amount: amountAlternative, + currency: $scope.alternativeIsoCode }); } else { var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount; diff --git a/src/js/controllers/buyCoinbase.js b/src/js/controllers/buyCoinbase.js new file mode 100644 index 000000000..6454b6cbe --- /dev/null +++ b/src/js/controllers/buyCoinbase.js @@ -0,0 +1,166 @@ +'use strict'; + +angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService) { + + var amount; + var currency; + + var initError = function(err) { + $log.error(err); + popupService.showAlert('Error', 'Could not connect to Coinbase', function() { + $ionicHistory.goBack(); + }); + }; + + $scope.$on("$ionicView.beforeEnter", function(event, data) { + amount = data.stateParams.amount; + currency = data.stateParams.currency; + + $scope.network = coinbaseService.getNetwork(); + $scope.wallets = profileService.getWallets({ + onlyComplete: true, + network: $scope.network + }); + $scope.wallet = $scope.wallets[0]; // Default first wallet + + ongoingProcess.set('connectingCoinbase', true); + coinbaseService.init(function(err, res) { + if (err) { + ongoingProcess.set('connectingCoinbase', false); + initError(err); + return; + } + var accessToken = res.accessToken; + + $scope.paymentMethods = []; + $scope.selectedPaymentMethodId = { value : null }; + coinbaseService.getPaymentMethods(accessToken, function(err, p) { + if (err) { + ongoingProcess.set('connectingCoinbase', false); + initError(err); + return; + } + lodash.each(p.data, function(pm) { + if (pm.allow_buy) { + $scope.paymentMethods.push(pm); + } + if (pm.allow_buy && pm.primary_buy) { + $scope.selectedPaymentMethodId.value = pm.id; + $scope.buyRequest(); + } + }); + }); + }); + }); + + $scope.buyRequest = function() { + ongoingProcess.set('connectingCoinbase', true); + coinbaseService.init(function(err, res) { + if (err) { + ongoingProcess.set('connectingCoinbase', false); + initError(err); + return; + } + var accessToken = res.accessToken; + var accountId = res.accountId; + var dataSrc = { + amount: amount, + currency: currency, + payment_method: $scope.selectedPaymentMethodId.value + }; + coinbaseService.buyRequest(accessToken, accountId, dataSrc, function(err, data) { + ongoingProcess.set('connectingCoinbase', false); + if (err) { + $log.error(err); + popupService.showAlert('Error', 'Could not create a buy request', function() { + $ionicHistory.goBack(); + }); + return; + } + $scope.buyRequestInfo = data.data; + }); + }); + }; + + $scope.buyConfirm = function() { + var message = 'Buy bitcoin for ' + amount + ' ' + currency; + var okText = 'Confirm'; + var cancelText = 'Cancel'; + popupService.showConfirm(null, message, okText, cancelText, function(ok) { + if (!ok) return; + + ongoingProcess.set('buyingBitcoin', true); + coinbaseService.init(function(err, res) { + if (err) { + ongoingProcess.set('buyingBitcoin', false); + initError(err); + return; + } + var accessToken = res.accessToken; + var accountId = res.accountId; + coinbaseService.buyCommit(accessToken, accountId, $scope.buyRequestInfo.id, function(err, b) { + if (err) { + ongoingProcess.set('buyingBitcoin', false); + popupService.showAlert('Error', 'Could not complete purchase'); + return; + } + var tx = b.data.transaction; + if (!tx) { + ongoingProcess.set('buyingBitcoin', false); + popupService.showAlert('Error', 'Transaction not found'); + return; + } + + $timeout(function() { + coinbaseService.getTransaction(accessToken, accountId, tx.id, function(err, updatedTx) { + if (err) { + ongoingProcess.set('buyingBitcoin', false); + popupService.showAlert('Error', 'Transaction error'); + return; + } + walletService.getAddress($scope.wallet, false, function(err, walletAddr) { + if (err) { + ongoingProcess.set('buyingBitcoin', false); + popupService.showAlert('Error', err); + return; + } + updatedTx.data['toAddr'] = walletAddr; + updatedTx.data['status'] = 'pending'; // Forcing "pending" status to process later + + $log.debug('Saving transaction to process later...'); + coinbaseService.savePendingTransaction(updatedTx.data, {}, function(err) { + if (err) $log.debug(err); + ongoingProcess.set('buyingBitcoin', false); + $scope.buySuccess = updatedTx.data; + $timeout(function() { + $scope.$apply(); + }); + }); + }); + }); + }, 8000); + }); + }); + }); + }; + + $scope.showWalletSelector = function() { + $scope.walletSelectorTitle = ($scope.action) == 'buy' ? 'Receive in' : 'Sell From'; + $scope.showWallets = true; + }; + + $scope.onWalletSelect = function(wallet) { + $scope.wallet = wallet; + }; + + $scope.goBackHome = function() { + $ionicHistory.nextViewOptions({ + disableAnimate: true, + historyRoot: true + }); + $ionicHistory.clearHistory(); + $state.go('tabs.home').then(function() { + $state.transitionTo('tabs.buyandsell.coinbase'); + }); + }; +}); diff --git a/src/js/controllers/coinbase.js b/src/js/controllers/coinbase.js index 3e03cefd3..5f3c9684c 100644 --- a/src/js/controllers/coinbase.js +++ b/src/js/controllers/coinbase.js @@ -6,6 +6,8 @@ angular.module('copayApp.controllers').controller('coinbaseController', function var isCordova = platformInfo.isCordova; var init = function() { + var config = configService.getSync().wallet.settings; + $scope.currency = getCurrency(config.alternativeIsoCode); ongoingProcess.set('connectingCoinbase', true); coinbaseService.init(function(err, data) { ongoingProcess.set('connectingCoinbase', false); @@ -15,6 +17,15 @@ angular.module('copayApp.controllers').controller('coinbaseController', function } return; } + + // Show rates + coinbaseService.buyPrice(data.accessToken, $scope.currency, function(err, b) { + $scope.buyPrice = b.data || null; + }); + coinbaseService.sellPrice(data.accessToken, $scope.currency, function(err, s) { + $scope.sellPrice = s.data || null; + }); + // Updating accessToken and accountId $timeout(function() { $scope.accessToken = data.accessToken; @@ -25,6 +36,14 @@ angular.module('copayApp.controllers').controller('coinbaseController', function }); }; + var getCurrency = function(code) { + // ONLY "USD" and "EUR" + switch(code) { + case 'EUR' : return 'EUR'; + default : return 'USD' + }; + }; + $scope.updateTransactions = function() { $log.debug('Getting transactions...'); $scope.pendingTransactions = { data: {} }; diff --git a/src/js/routes.js b/src/js/routes.js index 38ae9331a..c458a689b 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -942,41 +942,32 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }) .state('tabs.buyandsell.coinbase.amount', { - url: '/amount/:isCoinbase', - views: { - 'tab-home@tabs': { - controller: 'amountController', - templateUrl: 'views/amount.html' - } + url: '/amount/:coinbase/:currency', + views: { + 'tab-home@tabs': { + controller: 'amountController', + templateUrl: 'views/amount.html' } - }) - .state('tabs.buyandsell.coinbase.confirm', { - url: '/confirm/:toAmount/:toAddress/:isCoinbase/:coinbasePaymentMethodId/:coinbaseAmount/:coinbaseAmountCurrency', - views: { - 'tab-home@tabs': { - controller: 'confirmController', - templateUrl: 'views/confirm.html' - } - } - }) - /* - .state('tabs.buyandsell.coinbase.buy', { - url: '/buy', + } + }) + .state('tabs.buyandsell.coinbase.buy', { + url: '/buy/:amount/:currency', + views: { 'tab-home@tabs': { controller: 'buyCoinbaseController', - controllerAs: 'buy', templateUrl: 'views/buyCoinbase.html' } - }) - .state('tabs.buyandsell.coinbase.sell', { - url: '/sell', + } + }) + .state('tabs.buyandsell.coinbase.sell', { + url: '/sell/:amount/:currency', + views: { 'tab-home@tabs': { controller: 'sellCoinbaseController', - controllerAs: 'sell', templateUrl: 'views/sellCoinbase.html' } - }) - */ + } + }) /* * diff --git a/src/js/services/coinbaseService.js b/src/js/services/coinbaseService.js index 81dce1731..1e3a3cd33 100644 --- a/src/js/services/coinbaseService.js +++ b/src/js/services/coinbaseService.js @@ -394,7 +394,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ amount: data.amount, currency: data.currency, payment_method: data.payment_method || null, - commit: false + commit: data.commit || false }; $http(_post('/accounts/' + accountId + '/buys', token, data)).then(function(data) { $log.info('Coinbase Buy Request: SUCCESS'); diff --git a/www/views/amount.html b/www/views/amount.html index 023e2125e..f42c024bb 100644 --- a/www/views/amount.html +++ b/www/views/amount.html @@ -1,7 +1,7 @@ - {{'Enter Amount' | translate}} + {{coinbase ? (coinbase == 'buy' ? 'Buy bitcoin' : 'Sell bitcoin') : ('Enter Amount' | translate)}} @@ -14,7 +14,7 @@ -
+
Recipient
@@ -39,11 +39,12 @@
-
+
- Amount + Amount
Purchase Amount is limited to USD 1000 per day
{{exchangeRate}}
@@ -66,26 +67,6 @@ (remaining {{limits.monthlySellRemaining|currency:'':2}} {{limits.currency}})
- -
-
- -
-
- 1 BTC ~ {{coinbaseBuyPrice.amount}} {{coinbaseBuyPrice.currency}} -
-
- 1 BTC ~ {{coinbaseSellPrice.amount}} {{coinbaseSellPrice.currency}} -
-
diff --git a/www/views/buyCoinbase.html b/www/views/buyCoinbase.html new file mode 100644 index 000000000..df6e43ee6 --- /dev/null +++ b/www/views/buyCoinbase.html @@ -0,0 +1,96 @@ + + + + + Buy bitcoin + + + + +
+
+ Purchase Info +
+ + +
+
+ Amount + + {{buyRequestInfo.amount.amount}} {{buyRequestInfo.amount.currency}} + +
+
+ Payout at + + {{buyRequestInfo.payout_at | amCalendar}} + +
+
+ Receive in + {{wallet ? wallet.name : '...'}} +
+ +
+ Fees +
+
+ {{fee.type}} + + {{fee.amount.amount}} {{fee.amount.currency}} + +
+ +
+ Total +
+
+ Subtotal + + {{buyRequestInfo.subtotal.amount}} {{buyRequestInfo.subtotal.currency}} + +
+
+ Total + + {{buyRequestInfo.total.amount}} {{buyRequestInfo.total.currency}} + +
+
+
+ + + +
+
+ Bitcoin purchase completed. Coinbase has queued the transfer to your selected wallet +
+ +
+
+ + +
diff --git a/www/views/coinbase.html b/www/views/coinbase.html index 054fb89ab..87ebe2397 100644 --- a/www/views/coinbase.html +++ b/www/views/coinbase.html @@ -59,16 +59,22 @@
+
+ {{buyPrice.amount}} {{buyPrice.currency}} + | + {{sellPrice.amount}} {{sellPrice.currency}} +
+