diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index f9c5a554e..55da74976 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -52,7 +52,7 @@ angular.module('copayApp.controllers').controller('amountController', function($ if ($scope.isCoinbase) { var currency = 'USD'; - coinbaseService.init($scope.coinbaseAccessToken, function(err, data) { + coinbaseService.init(function(err, data) { if ($scope.isCoinbase == 'buy') { coinbaseService.buyPrice(data.accessToken, currency, function(err, b) { $scope.coinbaseBuyPrice = b.data || null; @@ -394,11 +394,14 @@ angular.module('copayApp.controllers').controller('amountController', function($ popupService.showAlert(gettextCatalog.getString('Error'), 'No Payment Method Selected'); return; } + var amountUSD = $scope.showAlternativeAmount ? _amount : $filter('formatFiatAmount')(toFiat(_amount)); var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount; $state.transitionTo('tabs.buyandsell.coinbase.confirm', { toAmount: (amount * unitToSatoshi).toFixed(0), isCoinbase: $scope.isCoinbase, - coinbasePaymentMethodId: $scope.coinbaseSelectedPaymentMethod.id + coinbasePaymentMethodId: $scope.coinbaseSelectedPaymentMethod.id, + coinbaseAmount: amountUSD, + coinbaseAmountCurrency: 'USD' }); } else { var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount; diff --git a/src/js/controllers/coinbase.js b/src/js/controllers/coinbase.js index ef2ef3749..333ab1ee6 100644 --- a/src/js/controllers/coinbase.js +++ b/src/js/controllers/coinbase.js @@ -6,8 +6,8 @@ angular.module('copayApp.controllers').controller('coinbaseController', function var init = function() { ongoingProcess.set('connectingCoinbase', true); - coinbaseService.init($scope.accessToken, function(err, data) { -console.log('[coinbase.js:9]',data); //TODO) + coinbaseService.init(function(err, data) { +console.log('[coinbase.js:9]',err, data); //TODO) ongoingProcess.set('connectingCoinbase', false); if (err || lodash.isEmpty(data)) { if (err) { @@ -28,7 +28,7 @@ console.log('[coinbase.js:9]',data); //TODO) $scope.updateTransactions = function() { $log.debug('Checking for transactions...'); coinbaseService.getPendingTransactions($scope.accessToken, $scope.accountId, function(err, txs) { -console.log('[coinbase.js:43]',txs); //TODO) +console.log('[coinbase.js:43]',txs); //TODO $scope.pendingTransactions = txs; }); diff --git a/src/js/controllers/confirm.js b/src/js/controllers/confirm.js index 11e2f7444..9cc0e8ec1 100644 --- a/src/js/controllers/confirm.js +++ b/src/js/controllers/confirm.js @@ -28,6 +28,8 @@ angular.module('copayApp.controllers').controller('confirmController', function( // Coinbase parameters $scope.isCoinbase = data.stateParams.isCoinbase; $scope.coinbasePaymentMethodId = data.stateParams.coinbasePaymentMethodId; + $scope.coinbaseAmount = data.stateParams.coinbaseAmount; + $scope.coinbaseAmountCurrency = data.stateParams.coinbaseAmountCurrency; toAmount = data.stateParams.toAmount; cachedSendMax = {}; @@ -180,6 +182,10 @@ angular.module('copayApp.controllers').controller('confirmController', function( } if ($scope.isGlidera == 'buy') $scope.getBuyPrice(); if ($scope.isGlidera == 'sell') $scope.getSellPrice(); + + if ($scope.isCoinbase == 'buy') { + coinbaseBuyRequest($scope.coinbaseAmount, $scope.coinbaseAmountCurrency, $scope.coinbasePaymentMethodId); + } }; function resetValues() { @@ -532,6 +538,50 @@ angular.module('copayApp.controllers').controller('confirmController', function( } }); return; + } + + if ($scope.isCoinbase) { + + ongoingProcess.set('buyingBitcoin', true, onSendStatusChange); + coinbaseService.init(function(err, res) { + if (err) { + $log.error(err); + return; + } + var token = res.accessToken; + var accountId = res.accountId; + coinbaseService.buyCommit(token, accountId, $scope.coinbaseBuyRequest.id, function(err, b) { +console.log('[confirm.js:508] BUY COMMIT',b); //TODO + if (err) { + $log.error(err); + return; + } + var tx = b.data.transaction; + if (!tx) return; + + coinbaseService.getTransaction(token, accountId, tx.id, function(err, updatedTx) { +console.log('[confirm.js:517] GET TRANSACTION',updatedTx); //TODO + if (err) $log.debug(err); + walletService.getAddress($scope.wallet, false, function(err, walletAddr) { +console.log('[confirm.js:521] GET ADDRESS',walletAddr); //TODO + if (err) { + return; + } + updatedTx.data['toAddr'] = walletAddr; + coinbaseService.savePendingTransaction(updatedTx.data, {}, function(err) { + if (err) $log.debug(err); + if (updatedTx.data.status == 'completed') { + coinbaseSendToCopay(token, accountId, updatedTx.data, onSendStatusChange); + } else { + ongoingProcess.set('buyingBitcoin', false, onSendStatusChange); + $scope.coinbaseBuySuccess = updatedTx.data; + } + }); + }); + }); + }); + }); + return; } ongoingProcess.set('creatingTx', true, onSendStatusChange); @@ -582,12 +632,15 @@ angular.module('copayApp.controllers').controller('confirmController', function( $log.debug('statusChangeHandler: ', processName, showName, isOn); if ( ( - processName === 'broadcastingTx' || - ((processName === 'signingTx') && $scope.wallet.m > 1) || - (processName == 'sendingTx' && !$scope.wallet.canSign() && !$scope.wallet.isPrivKeyExternal()) + processName === 'broadcastingTx' || + ((processName === 'signingTx') && $scope.wallet.m > 1) || + (processName == 'sendingTx' && !$scope.wallet.canSign() && !$scope.wallet.isPrivKeyExternal()) || + (processName == 'buyingBitcoin') ) && !isOn) { $scope.sendStatus = 'success'; - $scope.$digest(); + $timeout(function() { + $scope.$digest(); + }, 100) } else if (showName) { $scope.sendStatus = showName; } @@ -604,6 +657,7 @@ angular.module('copayApp.controllers').controller('confirmController', function( var fromBitPayCard = previousView.match(/tabs.bitpayCard/) ? true : false; var fromAmazon = previousView.match(/tabs.giftcards.amazon/) ? true : false; var fromGlidera = previousView.match(/tabs.buyandsell.glidera/) ? true : false; + var fromCoinbase = previousView.match(/tabs.buyandsell.coinbase/) ? true : false; $ionicHistory.nextViewOptions({ disableAnimate: true @@ -637,6 +691,15 @@ angular.module('copayApp.controllers').controller('confirmController', function( $state.go('tabs.home').then(function() { $state.transitionTo('tabs.buyandsell.glidera'); }); + } else if (fromCoinbase) { + $ionicHistory.nextViewOptions({ + disableAnimate: true, + historyRoot: true + }); + $ionicHistory.clearHistory(); + $state.go('tabs.home').then(function() { + $state.transitionTo('tabs.buyandsell.coinbase'); + }); } else { $ionicHistory.nextViewOptions({ disableAnimate: true, @@ -897,10 +960,61 @@ angular.module('copayApp.controllers').controller('confirmController', function( } if (lodash.isEmpty(res)) return; if (unitName == 'bits') { - $scope.exchangeRate = '1,000,000 bits ~ ' + res.rate + ' ' + alternativeIsoCode; + $scope.exchangeRate = '1,000,000 bits ~ ' + res.data.rate + ' ' + alternativeIsoCode; } else { - $scope.exchangeRate = '1 BTC ~ ' + res.rate + ' ' + alternativeIsoCode; + $scope.exchangeRate = '1 BTC ~ ' + res.data.rate + ' ' + alternativeIsoCode; } }); }; + + var coinbaseBuyRequest = function(amount, currency, paymentMethodId) { + var dataSrc = { + amount: amount, + currency: currency, + payment_method: paymentMethodId + }; + coinbaseService.init(function(err, res) { + if (err) { + $log.error(err); + return; + } + coinbaseService.buyRequest(res.accessToken, res.accountId, dataSrc, function(err, data) { +console.log('[confirm.js:931] BUY REQUEST',data); //TODO + if (err) { + $log.error(err); + return; + } + $scope.coinbaseBuyRequest = data.data; + }); + }); + }; + + var coinbaseSendToCopay = function(token, accountId, tx, onSendStatusChange) { + var data = { + to: tx.toAddr, + amount: tx.amount.amount, + currency: tx.amount.currency, + description: 'Copay Wallet: ' + $scope.wallet.name + }; + coinbaseService.sendTo(token, accountId, data, function(err, res) { +console.log('[confirm.js:938] SEND TO',res); //TODO + if (err) { + return; + } + $scope.coinbaseReceiveInfo = res.data; + if (!res.data.id) return; + coinbaseService.getTransaction(token, accountId, res.data.id, function(err, sendTx) { +console.log('[confirm.js:945] GET TRANSACTION',sendTx); //TODO + coinbaseService.savePendingTransaction(tx, { + remove: true + }, function(err) { + coinbaseService.savePendingTransaction(sendTx.data, {}, function(err) { + ongoingProcess.set('buyingBitcoin', false, onSendStatusChange); +console.log('[confirm.js:948] LISTO',err); //TODO + // TODO + }); + }); + }); + }); + }; }); diff --git a/src/js/controllers/modals/coinbaseTxDetails.js b/src/js/controllers/modals/coinbaseTxDetails.js index feebfd47d..3d952b168 100644 --- a/src/js/controllers/modals/coinbaseTxDetails.js +++ b/src/js/controllers/modals/coinbaseTxDetails.js @@ -7,11 +7,11 @@ angular.module('copayApp.controllers').controller('coinbaseTxDetailsController', remove: true }, function(err) { $rootScope.$emit('Local/CoinbaseTx'); - $scope.cancel(); + $scope.close(); }); }; - $scope.cancel = function() { + $scope.close = function() { $scope.coinbaseTxDetailsModal.hide(); }; diff --git a/src/js/routes.js b/src/js/routes.js index d466a17eb..ad0bcca17 100644 --- a/src/js/routes.js +++ b/src/js/routes.js @@ -955,7 +955,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr } }) .state('tabs.buyandsell.coinbase.confirm', { - url: '/confirm/:toAmount/:isCoinbase/:coinbasePaymentMethodId', + url: '/confirm/:toAmount/:isCoinbase/:coinbasePaymentMethodId/:coinbaseAmount/:coinbaseAmountCurrency', views: { 'tab-home@tabs': { controller: 'confirmController', diff --git a/src/js/services/coinbaseService.js b/src/js/services/coinbaseService.js index 6a05b99cb..6bccb318d 100644 --- a/src/js/services/coinbaseService.js +++ b/src/js/services/coinbaseService.js @@ -180,21 +180,13 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }); }; - root.init = function(accessToken, cb) { + root.init = function(cb) { if (lodash.isEmpty(credentials.CLIENT_ID)) { return cb('Coinbase is Disabled'); } $log.debug('Init Token...'); - var getToken = function(cb) { - if (accessToken) { - cb(null, accessToken); - } else { - storageService.getCoinbaseToken(credentials.NETWORK, cb); - } - }; - - getToken(function(err, accessToken) { + storageService.getCoinbaseToken(credentials.NETWORK, function(err, accessToken) { if (err || !accessToken) return cb(); else { _getMainAccountId(accessToken, function(err, accountId) { @@ -279,6 +271,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; root.getTransaction = function(token, accountId, transactionId, cb) { + if (isFake) return cb(null, get_transaction); if (!token) return cb('Invalid Token'); $http(_get('/accounts/' + accountId + '/transactions/' + transactionId, token)).then(function(data) { $log.info('Coinbase Transaction: SUCCESS'); @@ -392,6 +385,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; root.buyRequest = function(token, accountId, data, cb) { + if (isFake) return cb(null, buy_request); var data = { amount: data.amount, currency: data.currency, @@ -408,6 +402,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; root.buyCommit = function(token, accountId, buyId, cb) { + if (isFake) return cb(null, buy_commit); $http(_post('/accounts/' + accountId + '/buys/' + buyId + '/commit', token)).then(function(data) { $log.info('Coinbase Buy Commit: SUCCESS'); return cb(null, data.data); @@ -431,6 +426,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; root.sendTo = function(token, accountId, data, cb) { + if (isFake) return cb(null, send_to_copay); var data = { type: 'send', to: data.to, @@ -448,6 +444,10 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }; // Pending transactions + + root.savePendingTransaction = function(ctx, opts, cb) { + _savePendingTransaction(ctx, opts, cb); + }; var _savePendingTransaction = function(ctx, opts, cb) { storageService.getCoinbaseTxs(credentials.NETWORK, function(err, oldTxs) { @@ -478,11 +478,12 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ storageService.getCoinbaseTxs(credentials.NETWORK, function(err, txs) { txs = txs ? JSON.parse(txs) : {}; coinbasePendingTransactions = lodash.isEmpty(txs) ? null : txs; - lodash.forEach(txs, function(dataFromStorage, txId) { + lodash.forEach(coinbasePendingTransactions, function(dataFromStorage, txId) { if ((dataFromStorage.type == 'sell' && dataFromStorage.status == 'completed') || (dataFromStorage.type == 'buy' && dataFromStorage.status == 'completed') || dataFromStorage.status == 'error' || - (dataFromStorage.type == 'send' && dataFromStorage.status == 'completed')) return; + (dataFromStorage.type == 'send' && dataFromStorage.status == 'completed')) + return cb(null, coinbasePendingTransactions); root.getTransaction(accessToken, accountId, txId, function(err, tx) { if (err) { _savePendingTransaction(dataFromStorage, { @@ -491,7 +492,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }, function(err) { if (err) $log.debug(err); }); - return; + return cb(err); } _updateCoinbasePendingTransactions(dataFromStorage, tx.data); coinbasePendingTransactions[txId] = dataFromStorage; @@ -504,7 +505,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }, function(err) { if (err) $log.debug(err); }); - return cb(); + return cb(err); } var newSellPrice = s.data.amount; var variance = Math.abs((newSellPrice - dataFromStorage.sell_price_amount) / dataFromStorage.sell_price_amount * 100); @@ -632,6 +633,46 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ }); }; + var buy_request = { + "data" : { + "id": "a333743d-184a-5b5b-abe8-11612fc44ab5", + "status": "created", + "payment_method": { + "id": "83562370-3e5c-51db-87da-752af5ab9559", + "resource": "payment_method", + "resource_path": "/v2/payment-methods/83562370-3e5c-51db-87da-752af5ab9559" + }, + "transaction": { + "id": "763d1401-fd17-5a18-852a-9cca5ac2f9c0", + "resource": "transaction", + "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/441b9494-b3f0-5b98-b9b0-4d82c21c252a" + }, + "amount": { + "amount": "10.00000000", + "currency": "BTC" + }, + "total": { + "amount": "102.01", + "currency": "USD" + }, + "subtotal": { + "amount": "101.00", + "currency": "USD" + }, + "created_at": "2015-04-01T18:43:37-07:00", + "updated_at": "2015-04-01T18:43:37-07:00", + "resource": "buy", + "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/buys/a333743d-184a-5b5b-abe8-11612fc44ab5", + "committed": false, + "instant": false, + "fee": { + "amount": "1.01", + "currency": "USD" + }, + "payout_at": "2015-04-07T18:43:37-07:00" + } + }; + var payment_methods = { "pagination": { "ending_before": null, @@ -686,6 +727,114 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $ ] }; + var get_transaction = { + "data" : { + "id": "57ffb4ae-0c59-5430-bcd3-3f98f797a66c", + "type": "send", + "status": "completed", + "amount": { + "amount": "-0.00100000", + "currency": "BTC" + }, + "native_amount": { + "amount": "-0.01", + "currency": "USD" + }, + "description": null, + "created_at": "2015-03-11T13:13:35-07:00", + "updated_at": "2015-03-26T15:55:43-07:00", + "resource": "transaction", + "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/57ffb4ae-0c59-5430-bcd3-3f98f797a66c", + "network": { + "status": "off_blockchain", + "name": "bitcoin" + }, + "to": { + "id": "a6b4c2df-a62c-5d68-822a-dd4e2102e703", + "resource": "user", + "resource_path": "/v2/users/a6b4c2df-a62c-5d68-822a-dd4e2102e703" + }, + "details": { + "title": "Send bitcoin", + "subtitle": "to User 2" + } + } + }; + + var buy_commit = { + "data" : { + "id": "a333743d-184a-5b5b-abe8-11612fc44ab5", + "status": "created", + "payment_method": { + "id": "83562370-3e5c-51db-87da-752af5ab9559", + "resource": "payment_method", + "resource_path": "/v2/payment-methods/83562370-3e5c-51db-87da-752af5ab9559" + }, + "transaction": { + "id": "763d1401-fd17-5a18-852a-9cca5ac2f9c0", + "resource": "transaction", + "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/441b9494-b3f0-5b98-b9b0-4d82c21c252a" + }, + "amount": { + "amount": "10.00000000", + "currency": "BTC" + }, + "total": { + "amount": "102.01", + "currency": "USD" + }, + "subtotal": { + "amount": "101.00", + "currency": "USD" + }, + "created_at": "2015-04-01T18:43:37-07:00", + "updated_at": "2015-04-01T18:43:37-07:00", + "resource": "buy", + "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/buys/a333743d-184a-5b5b-abe8-11612fc44ab5", + "committed": true, + "instant": false, + "fee": { + "amount": "1.01", + "currency": "USD" + }, + "payout_at": "2015-04-07T18:43:37-07:00" + } + }; + + var send_to_copay = { + "data" : { + "id": "3c04e35e-8e5a-5ff1-9155-00675db4ac02", + "type": "send", + "status": "pending", + "amount": { + "amount": "-0.10000000", + "currency": "BTC" + }, + "native_amount": { + "amount": "-1.00", + "currency": "USD" + }, + "description": null, + "created_at": "2015-01-31T20:49:02Z", + "updated_at": "2015-03-31T17:25:29-07:00", + "resource": "transaction", + "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/3c04e35e-8e5a-5ff1-9155-00675db4ac02", + "network": { + "status": "unconfirmed", + "hash": "463397c87beddd9a61ade61359a13adc9efea26062191fe07147037bce7f33ed", + "name": "bitcoin" + }, + "to": { + "resource": "bitcoin_address", + "address": "1AUJ8z5RuHRTqD1eikyfUUetzGmdWLGkpT" + }, + "details": { + "title": "Send bitcoin", + "subtitle": "to User 2" + } + } + }; + return root; }); diff --git a/www/views/confirm.html b/www/views/confirm.html index 9bfdcdeeb..4cf9e823f 100644 --- a/www/views/confirm.html +++ b/www/views/confirm.html @@ -116,6 +116,17 @@ +
- This action will remove the transaction. -
- -