diff --git a/i18n/po/template.pot b/i18n/po/template.pot index 56318008c..ebac52c11 100644 --- a/i18n/po/template.pot +++ b/i18n/po/template.pot @@ -3901,4 +3901,24 @@ msgstr "" #: www/views/includes/incomingDataMenu.html:90 msgid "Open in web browser" +msgstr "" + +#: src/js/services/shapeshift.service.js.html:90 +msgid "Invalid address" +msgstr "" + +#: src/js/services/shapeshift.service.js.html:90 +msgid "Amount is not defined" +msgstr "" + +#: src/js/services/shapeshift.service.js.html:90 +msgid "Amount is below the minimun" +msgstr "" + +#: src/js/services/shapeshift.service.js.html:90 +msgid "Amount is above the limit" +msgstr "" + +#: src/js/services/shapeshift.service.js.html:90 +msgid "Invalid response from Shapeshift" msgstr "" \ No newline at end of file diff --git a/src/js/controllers/amount.js b/src/js/controllers/amount.js index e861b36ff..c1cd9a118 100644 --- a/src/js/controllers/amount.js +++ b/src/js/controllers/amount.js @@ -2,7 +2,7 @@ angular.module('copayApp.controllers').controller('amountController', amountController); -function amountController(configService, $filter, gettextCatalog, $ionicHistory, $ionicModal, $ionicScrollDelegate, lodash, $log, nodeWebkitService, rateService, $scope, $state, $timeout, sendFlowService, shapeshiftService, txFormatService, platformInfo, profileService, walletService, $window) { +function amountController(configService, $filter, gettextCatalog, $ionicModal, $ionicScrollDelegate, lodash, $log, nodeWebkitService, rateService, $scope, $state, $timeout, sendFlowService, shapeshiftService, txFormatService, platformInfo, profileService, walletService, $window, ongoingProcess, popupService) { var vm = this; vm.allowSend = false; @@ -74,7 +74,6 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory, initCurrencies(); passthroughParams = sendFlowService.state.getClone(); - console.log('amount onBeforeEnter after back sendflow ', passthroughParams); vm.fromWalletId = passthroughParams.fromWalletId; @@ -94,9 +93,20 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory, vm.fromWallet = profileService.getWallet(vm.fromWalletId); vm.toWallet = profileService.getWallet(vm.toWalletId); - shapeshiftService.getMarketData(vm.fromWallet.coin, vm.toWallet.coin, function(data) { - vm.thirdParty.data['minAmount'] = vm.minAmount = parseFloat(data.minimum); - vm.thirdParty.data['maxAmount'] = vm.maxAmount = parseFloat(data.maxLimit); + ongoingProcess.set('connectingShapeshift', true); + shapeshiftService.getMarketData(vm.fromWallet.coin, vm.toWallet.coin, function(err, data) { + + if (err) { + // Error stop here + ongoingProcess.set('connectingShapeshift', false); + popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () { + $ionicHistory.goBack(); + }); + } else { + vm.thirdParty.data['minAmount'] = vm.minAmount = parseFloat(data.minimum); + vm.thirdParty.data['maxAmount'] = vm.maxAmount = parseFloat(data.maxLimit); + ongoingProcess.set('connectingShapeshift', false); + } }); } } @@ -113,7 +123,7 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory, var reOp = /^[\*\+\-\/]$/; if (!isAndroid && !isIos) { - var disableKeys = angular.element($window).on('keydown', function(e) { + angular.element($window).on('keydown', function(e) { if (!e.key) return; if (e.which === 8) { // you can add others here inside brackets. if (!altCurrencyModal) { diff --git a/src/js/controllers/review.controller.js b/src/js/controllers/review.controller.js index dbf14937f..c82838f7c 100644 --- a/src/js/controllers/review.controller.js +++ b/src/js/controllers/review.controller.js @@ -93,26 +93,48 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit if (sendFlowData.thirdParty) { vm.thirdParty = sendFlowData.thirdParty; - handleThirdPartyInitIfBip70(); - handleThirdPartyInitIfShapeshift(); + switch (vm.thirdParty.id) { + case 'shapeshift': + initShapeshift(function (err) { + if (err) { + // Error stop here + ongoingProcess.set('connectingShapeshift', false); + popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () { + $ionicHistory.goBack(); + }); + } else { + _next(data); + } + }); + break; + case 'bip70': + initBip70(); + default: + _next(data); + break; + } + } else { + _next(data); } - configService.get(function onConfig(err, configCache) { - if (err) { - $log.err('Error getting config.', err); - } else { - config = configCache; - priceDisplayIsFiat = config.wallet.settings.priceDisplay === 'fiat'; - vm.origin.currencyColor = (vm.originWallet.coin === 'btc' ? defaults.bitcoinWalletColor : defaults.bitcoinCashWalletColor); - console.log("coin", vm.originWallet.coin, vm.origin.currencyColor, config.bitcoinWalletColor, vm.originWallet.coin === 'btc'); - unitFromSat = 1 / config.wallet.settings.unitToSatoshi; - } - updateSendAmounts(); - getOriginWalletBalance(vm.originWallet); - handleDestinationAsAddress(toAddress, coin); - handleDestinationAsWallet(sendFlowData.toWalletId); - createVanityTransaction(data); - }); + function _next() { + configService.get(function onConfig(err, configCache) { + if (err) { + $log.err('Error getting config.', err); + } else { + config = configCache; + priceDisplayIsFiat = config.wallet.settings.priceDisplay === 'fiat'; + vm.origin.currencyColor = (vm.originWallet.coin === 'btc' ? defaults.bitcoinWalletColor : defaults.bitcoinCashWalletColor); + console.log("coin", vm.originWallet.coin, vm.origin.currencyColor, config.bitcoinWalletColor, vm.originWallet.coin === 'btc'); + unitFromSat = 1 / config.wallet.settings.unitToSatoshi; + } + updateSendAmounts(); + getOriginWalletBalance(vm.originWallet); + handleDestinationAsAddress(toAddress, coin); + handleDestinationAsWallet(sendFlowData.toWalletId); + createVanityTransaction(data); + }); + } } vm.approve = function() { @@ -458,72 +480,62 @@ function reviewController(addressbookService, bitcoinCashJsService, bitcore, bit vm.destination.balanceCurrency = balanceText.currency; } - function handleThirdPartyInitIfBip70() { - if (vm.thirdParty.id === 'bip70') { - vm.sendingTitle = gettextCatalog.getString('You are paying'); - vm.memo = vm.thirdParty.memo; - vm.memoExpanded = !!vm.memo; - vm.destination.name = vm.thirdParty.name; + function initBip70() { + vm.sendingTitle = gettextCatalog.getString('You are paying'); + vm.memo = vm.thirdParty.memo; + vm.memoExpanded = !!vm.memo; + vm.destination.name = vm.thirdParty.name; - txPayproData = { - caTrusted: vm.thirdParty.caTrusted, - domain: vm.thirdParty.domain, - expires: vm.thirdParty.expires, - toAddress: toAddress, - url: vm.thirdParty.url, - verified: vm.thirdParty.verified, - }; - } + txPayproData = { + caTrusted: vm.thirdParty.caTrusted, + domain: vm.thirdParty.domain, + expires: vm.thirdParty.expires, + toAddress: toAddress, + url: vm.thirdParty.url, + verified: vm.thirdParty.verified, + }; } - function handleThirdPartyInitIfShapeshift() { - if (vm.thirdParty.id === 'shapeshift') { - vm.sendingTitle = gettextCatalog.getString('You are shifting'); - if (!vm.thirdParty.data) { - vm.thirdParty.data = {}; - } + function initShapeshift(cb) { + vm.sendingTitle = gettextCatalog.getString('You are shifting'); + if (!vm.thirdParty.data) { + vm.thirdParty.data = {}; + } - var toWallet = profileService.getWallet(destinationWalletId); - vm.destination.name = toWallet.name; - vm.destination.color = toWallet.color; - vm.destination.currency = toWallet.coin.toUpperCase(); + var toWallet = profileService.getWallet(destinationWalletId); + vm.destination.name = toWallet.name; + vm.destination.color = toWallet.color; + vm.destination.currency = toWallet.coin.toUpperCase(); - ongoingProcess.set('connectingShapeshift', true); - walletService.getAddress(vm.originWallet, false, function onReturnWalletAddress(err, returnAddr) { + ongoingProcess.set('connectingShapeshift', true); + walletService.getAddress(vm.originWallet, false, function onReturnWalletAddress(err, returnAddr) { + if (err) { + return cb(err); + } + walletService.getAddress(toWallet, false, function onWithdrawalWalletAddress(err, withdrawalAddr) { if (err) { - ongoingProcess.set('connectingShapeshift', false); - popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () { - $ionicHistory.goBack(); - }); - return; + return cb(err); } - walletService.getAddress(toWallet, false, function onWithdrawalWalletAddress(err, withdrawalAddr) { - if (err) { - ongoingProcess.set('connectingShapeshift', false); - popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () { - $ionicHistory.goBack(); - }); - return; - } - shapeshiftService.shiftIt(vm.originWallet.coin, toWallet.coin, withdrawalAddr, returnAddr, function onShiftIt(err, shapeshiftData) { - if (err && err != null) { - ongoingProcess.set('connectingShapeshift', false); - popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () { - $ionicHistory.goBack(); - }); - } else { - vm.memo = 'ShapeShift Order:\nhttps://www.shapeshift.io/#/status/' + shapeshiftData.orderId; - vm.memoExpanded = !!vm.memo; - tx.toAddress = shapeshiftData.toAddress; - vm.destination.address = toAddress; - vm.destination.kind = 'shapeshift'; - } - }); + // Need to use the correct service to do it. + var amount = parseFloat(satoshis / 100000000); + + shapeshiftService.shiftIt(vm.originWallet.coin, toWallet.coin, withdrawalAddr, returnAddr, amount, function onShiftIt(err, shapeshiftData) { + if (err) { + return cb(err); + } else { + vm.destination.kind = 'shapeshift'; + vm.destination.address = toAddress; + tx.toAddress = shapeshiftData.toAddress; + vm.memo = 'ShapeShift Order:\nhttps://www.shapeshift.io/#/status/' + shapeshiftData.orderId; + vm.memoExpanded = !!vm.memo; + ongoingProcess.set('connectingShapeshift', false); + cb(); + } }); }); - } + }); } function onShareTransaction() { diff --git a/src/js/services/onGoingProcess.js b/src/js/services/onGoingProcess.js index 147985dbb..9c25c3c26 100644 --- a/src/js/services/onGoingProcess.js +++ b/src/js/services/onGoingProcess.js @@ -52,11 +52,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti root.clear = function() { ongoingProcess = {}; - if (isCordova && !isWindowsPhoneApp) { - window.plugins.spinnerDialog.hide(); - } else { - $ionicLoading.hide(); - } + $ionicLoading.hide(); }; root.get = function(processName) { @@ -82,23 +78,14 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti if (customHandler) { customHandler(processName, showName, isOn); } else if (root.onGoingProcessName) { - if (isCordova && !isWindowsPhoneApp) { - window.plugins.spinnerDialog.show(null, showName, root.clear); - } else { - - var tmpl; - if (isWindowsPhoneApp) tmpl = '
' + showName + '
'; - else tmpl = '
' + showName + '
'; - $ionicLoading.show({ - template: tmpl - }); - } + var tmpl; + if (isWindowsPhoneApp) tmpl = '
' + showName + '
'; + else tmpl = '
' + showName + '
'; + $ionicLoading.show({ + template: tmpl, + }); } else { - if (isCordova && !isWindowsPhoneApp) { - window.plugins.spinnerDialog.hide(); - } else { - $ionicLoading.hide(); - } + $ionicLoading.hide(); } }; diff --git a/src/js/services/send-flow-state.service.js b/src/js/services/send-flow-state.service.js index bec2c8a3c..c19317515 100644 --- a/src/js/services/send-flow-state.service.js +++ b/src/js/services/send-flow-state.service.js @@ -101,7 +101,7 @@ angular Object.keys(params).forEach(function forNewParam(key) { service.state[key] = params[key]; }); - }; + } /** * Pop state @@ -116,7 +116,7 @@ angular } else { clear(); } - }; + } /** * Push state @@ -129,14 +129,14 @@ angular service.previousStates.push(currentParams); clearCurrent(); map(params); - }; + } /** * Is empty stack */ function isEmpty() { return service.previousStates.length == 0; - }; + } }; })(); \ No newline at end of file diff --git a/src/js/services/send-flow.service.js b/src/js/services/send-flow.service.js index 1b02c0d34..e8be2e487 100644 --- a/src/js/services/send-flow.service.js +++ b/src/js/services/send-flow.service.js @@ -144,6 +144,5 @@ angular sendFlowStateService.pop(); sendFlowRouterService.goBack(); } - }; - + } })(); \ No newline at end of file diff --git a/src/js/services/shapeShiftApiService.js b/src/js/services/shapeShiftApiService.js index 210ae0fbd..cc5fb0792 100644 --- a/src/js/services/shapeShiftApiService.js +++ b/src/js/services/shapeShiftApiService.js @@ -328,18 +328,23 @@ angular.module('copayApp.services').factory('shapeshiftApiService', function($q) $scope.amount, $scope.withdrawalAddress, $scope.coinIn, $scope.coinOut ); + console.log('shapeshiftApiService.FixedAmountTx()'); console.log(fixedTx); SSA.FixedAmountTx(fixedTx, function (data) { - console.log(data) - return promise.resolve({ fixedTxData : data.success }); + console.log(data); + promise.resolve(data); }); return promise.promise; }, NormalTx : function($scope){ var promise = $q.defer(); var normalTx = SSA.CreateNormalTx($scope.withdrawalAddress, $scope.coinIn, $scope.coinOut); + + console.log('shapeshiftApiService.NormalTx()'); + console.log(normalTx); SSA.NormalTx(normalTx, function (data) { - promise.resolve({ normalTxData : data }); + console.log(data); + promise.resolve(data); }); return promise.promise; }, @@ -360,11 +365,12 @@ angular.module('copayApp.services').factory('shapeshiftApiService', function($q) return promise.promise; }, ValidateAddress : function(address, coin) { - var promise = $q.defer(); - SSA.ValidateAdddress(address, coin, function(data){ - promise.resolve(data); - }); - return promise.promise; + var promise = $q.defer(); + SSA.ValidateAdddress(address, coin, function onRequest(data){ + console.log(data); + promise.resolve(data); + }); + return promise.promise; } }; }); diff --git a/src/js/services/shapeshift.service.js b/src/js/services/shapeshift.service.js new file mode 100644 index 000000000..77f0de297 --- /dev/null +++ b/src/js/services/shapeshift.service.js @@ -0,0 +1,112 @@ +'use strict'; + +(function(){ + +angular + .module('bitcoincom.services') + .factory('shapeshiftService', shapeshiftService); + + function shapeshiftService(shapeshiftApiService, gettextCatalog) { + + var service = { + // Variables + coinIn: '', + coinOut: '', + withdrawalAddress: '', + returnAddress: '', + amount: '', + marketData: {}, + coins: { + 'BTC': {name: 'Bitcoin', symbol: 'BTC'}, + 'BCH': {name: 'Bitcoin Cash', symbol: 'BCH'} + }, + + // Functions + getMarketData: getMarketData, + shiftIt: shiftIt + }; + + return service; + + function handleError(response, defaultMessage, cb) { + if (response && typeof response.error === "string") { + cb(new Error(response.error)); + } else if (response && response.error && response.error.message) { + cb(new Error(response.error.message)); + } else { + cb(new Error(defaultMessage)); + } + } + + function getMarketData(coinIn, coinOut, cb) { + service.coinIn = coinIn; + service.coinOut = coinOut; + shapeshiftApiService + .marketInfo(service.coinIn, service.coinOut) + .then(function (response) { + if (!response || response.error) { + handleError(response, 'Invalid response from Shapeshift', cb); + } else { + service.marketData = response; + service.rateString = service.marketData.rate.toString() + ' ' + coinOut.toUpperCase() + '/' + coinIn.toUpperCase(); + cb(null, response); + } + }); + } + + function shiftIt(coinIn, coinOut, withdrawalAddress, returnAddress, amount, cb) { + // Test if the amount is correct depending on the min and max + if (!amount || typeof amount !== 'number') { + cb(new Error(gettextCatalog.getString('Amount is not defined')))); + } else if (amount < service.marketData.minimum) { + cb(new Error(gettextCatalog.getString('Amount is below the minimun'))); + } else if (amount > service.marketData.maxLimit) { + cb(new Error(gettextCatalog.getString('Amount is above the limit'))); + } else { + // Init service data + service.withdrawalAddress = withdrawalAddress; + service.returnAddress = returnAddress; + service.coinIn = coinIn; + service.coinOut = coinOut; + service.amount = amount; + + // Check the address + shapeshiftApiService + .ValidateAddress(withdrawalAddress, coinOut) + .then(function onSuccess(response) { + if (response && response.isvalid) { + // Prepare the transaction shapeshift side + shapeshiftApiService.NormalTx(service).then(function onResponse(response) { + // If error, return it + if (!response || response.error) { + handleError(response, gettextCatalog.getString('Invalid response from Shapeshift'), cb); + } else { + var txData = response; + + // If the content is not that it was expected, get back an error + if (!txData || !txData.orderId || !txData.deposit) { + cb(new Error(gettextCatalog.getString('Invalid response from Shapeshift'))); + } else { + // Get back the data + service.depositInfo = txData; + var shapeshiftData = { + coinIn: coinIn, + coinOut: coinOut, + toWalletId: service.toWalletId, + minAmount: service.marketData.minimum, + maxAmount: service.marketData.maxLimit, + orderId: txData.orderId, + toAddress: txData.deposit + }; + cb(null, shapeshiftData); + } + } + }); + } else { + cb(new Error(gettextCatalog.getString('Invalid address'))); + } + }); + } + } + } +})(); \ No newline at end of file diff --git a/src/js/services/shapeshiftService.js b/src/js/services/shapeshiftService.js deleted file mode 100644 index b1d2f6e7d..000000000 --- a/src/js/services/shapeshiftService.js +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -angular.module('copayApp.services').factory('shapeshiftService', function ($http, $interval, $log, lodash, moment, ongoingProcess, shapeshiftApiService, storageService, configService, incomingDataService, platformInfo, servicesService) { - var root = {}; - root.ShiftState = 'Shift'; - root.coinIn = ''; - root.coinOut = ''; - root.withdrawalAddress = ''; - root.returnAddress = ''; - root.amount = ''; - root.marketData = {}; - - root.getMarketDataIn = function (coin) { - if (coin === root.coinOut) return root.getMarketData(root.coinOut, root.coinIn); - return root.getMarketData(coin, root.coinOut); - }; - root.getMarketDataOut = function (coin) { - if (coin === root.coinIn) return root.getMarketData(root.coinOut, root.coinIn); - return root.getMarketData(root.coinIn, coin); - }; - root.getMarketData = function (coinIn, coinOut, cb) { - root.coinIn = coinIn; - root.coinOut = coinOut; - if (root.coinIn === undefined || root.coinOut === undefined) return; - shapeshiftApiService - .marketInfo(root.coinIn, root.coinOut) - .then(function (marketData) { - root.marketData = marketData; - root.rateString = root.marketData.rate.toString() + ' ' + coinOut.toUpperCase() + '/' + coinIn.toUpperCase(); - if (cb) { - cb(marketData); - } - }); - }; - - /*shapeshiftApiService.coins().then(function(coins){ - root.coins = coins; - root.coinIn = coins['BTC'].symbol; - root.coinOut = coins['BCH'].symbol; - root.getMarketData(root.coinIn, root.coinOut); - });*/ - - root.coins = { - 'BTC': {name: 'Bitcoin', symbol: 'BTC'}, - 'BCH': {name: 'Bitcoin Cash', symbol: 'BCH'} - }; - - function checkForError(data) { - if (data.err) return true; - return false; - } - - root.shiftIt = function (coinIn, coinOut, withdrawalAddress, returnAddress, cb) { - ongoingProcess.set('connectingShapeshift', true); - root.withdrawalAddress = withdrawalAddress; - root.returnAddress = returnAddress; - root.coinIn = coinIn; - root.coinOut = coinOut; - shapeshiftApiService.ValidateAddress(withdrawalAddress, coinOut).then(function (valid) { - var tx = ShapeShift(); - var coin; - console.log("Starting"); - tx.then(function (txData) { - console.log("Got txData", txData); - if (txData['fixedTxData']) { - txData = txData.fixedTxData; - if (checkForError(txData)) return cb(txData.err); - //console.log(txData) - var coinPair = txData.pair.split('_'); - txData.depositType = coinPair[0].toUpperCase(); - txData.withdrawalType = coinPair[1].toUpperCase(); - coin = root.coins[txData.depositType].name.toLowerCase(); - - txData.depositQR = coin + ":" + txData.deposit + "?amount=" + txData.depositAmount; - - root.txFixedPending = true; - - } else if (txData['normalTxData']) { - txData = txData.normalTxData; - if (checkForError(txData)) return cb(txData.err); - coin = root.coins[txData.depositType.toUpperCase()].name.toLowerCase(); - txData.depositQR = coin + ":" + txData.deposit; - } else if (txData['cancelTxData']) { - txData = txData.cancelTxData; - if (checkForError(txData)) return cb(txData.err); - if (root.txFixedPending) { - root.txFixedPending = false; - } - root.ShiftState = 'Shift'; - } - root.depositInfo = txData; - //console.log(root.marketData); - //console.log(root.depositInfo); - var sendAddress = txData.depositQR; - if (sendAddress && sendAddress.indexOf('bitcoin cash') >= 0) - sendAddress = sendAddress.replace('bitcoin cash', 'bitcoincash'); - - ongoingProcess.set('connectingShapeshift', false); - - root.ShiftState = 'Cancel'; - //root.GetStatus(); - //root.txInterval=$interval(root.GetStatus, 8000); - - var shapeshiftData = { - coinIn: coinIn, - coinOut: coinOut, - toWalletId: root.toWalletId, - minAmount: root.marketData.minimum, - maxAmount: root.marketData.maxLimit, - orderId: root.depositInfo.orderId, - toAddress: txData.deposit - }; - // - // if (incomingDataService.redir(sendAddress, 'shapeshift', shapeshiftData)) { - ongoingProcess.set('connectingShapeshift', false); - // return; - // } - cb(null, shapeshiftData); - }); - }) - }; - - function ShapeShift() { - if (parseFloat(root.amount) > 0) return shapeshiftApiService.FixedAmountTx(root); - return shapeshiftApiService.NormalTx(root); - } - - root.GetStatus = function () { - var address = root.depositInfo.deposit - shapeshiftApiService.GetStatusOfDepositToAddress(address).then(function (data) { - root.DepositStatus = data; - if (root.DepositStatus.status === 'complete') { - $interval.cancel(root.txInterval); - root.depositInfo = null; - root.ShiftState = 'Shift' - } - }); - }; - - return root; -});