diff --git a/Gruntfile.js b/Gruntfile.js index 7968f2510..4ac23e47a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -71,7 +71,7 @@ module.exports = function(grunt) { sign_android: { // When the build log outputs "Built the following apk(s):", it seems to need the filename to start with "android-release". // It looks like it simply lists all apk files starting with "android-release" - command: 'rm -f platforms/android/build/outputs/apk/android-release-signed-*.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-unsigned.apk bitcoin-com && zipalign -v 4 platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/bitcoin-com-wallet-<%= pkg.fullVersion %>-android-signed-aligned.apk', + command: 'rm -f platforms/android/build/outputs/apk/release/*-android-signed-aligned.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../bitcoin-com-release-key.jks -signedjar platforms/android/build/outputs/apk/release/android-release-signed.apk platforms/android/build/outputs/apk/release/android-release-unsigned.apk bitcoin-com && zipalign -v 4 platforms/android/build/outputs/apk/release/android-release-signed.apk platforms/android/build/outputs/apk/release/bitcoin-com-wallet-<%= pkg.fullVersion %>-android-signed-aligned.apk', stdin: true, }, sign_desktop_dist: { diff --git a/app-template/config-template.xml b/app-template/config-template.xml index 8686b7b36..b24b86fae 100644 --- a/app-template/config-template.xml +++ b/app-template/config-template.xml @@ -77,7 +77,7 @@ - + diff --git a/src/android/build-extras.gradle b/src/android/build-extras.gradle index e7dd50572..c90145418 100644 --- a/src/android/build-extras.gradle +++ b/src/android/build-extras.gradle @@ -1,5 +1,6 @@ ext { ANDROID_SUPPORT_V4_VERSION = '26.1.0' + ANDROID_SUPPORT_ANNOTATIONS_VERSION = '26.1.0' } configurations.all { diff --git a/src/js/controllers/amount.controller.js b/src/js/controllers/amount.controller.js index 07f31bb3e..219245e54 100644 --- a/src/js/controllers/amount.controller.js +++ b/src/js/controllers/amount.controller.js @@ -8,31 +8,7 @@ angular function amountController(configService, $filter, gettextCatalog, $ionicHistory, $ionicModal, $ionicScrollDelegate, lodash, $log, nodeWebkitService, rateService, $scope, $state, $timeout, sendFlowService, shapeshiftService, txFormatService, platformInfo, ongoingProcess, popupService, profileService, walletService, $window) { var vm = this; - - // Variables - vm.allowSend = false; - vm.altCurrencyList = []; - vm.alternativeAmount = ''; - vm.alternativeUnit = ''; - vm.amount = '0'; - vm.availableFunds = ''; - vm.canSendAllAvailableFunds = true; - vm.errorMessage = ''; - // Use insufficient for logic, as when the amount is invalid, funds being - // either sufficent or insufficient doesn't make sense. - vm.fundsAreInsufficient = false; - vm.globalResult = ''; - vm.isRequestingSpecificAmount = false; - vm.listComplete = false; - vm.lastUsedPopularList = []; - vm.maxAmount = 0; - vm.minAmount = 0; - vm.sendableFunds = ''; - vm.showSendMaxButton = false; - vm.showSendLimitMaxButton = false; - vm.thirdParty = false; - vm.unit = ''; - + // Functions vm.changeUnit = changeUnit; vm.close = close; @@ -46,7 +22,6 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory, vm.removeDigit = removeDigit; vm.save = save; vm.sendMax = sendMax; - $scope.$on('$ionicView.beforeEnter', onBeforeEnter); $scope.$on('$ionicView.leave', onLeave); @@ -79,8 +54,55 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory, satoshis: null }; - function onLeave() { - angular.element($window).off('keydown'); + function initVariables() { + // Private variables + altCurrencyModal = null; + altUnitIndex = 0; + availableUnits = []; + canSendMax = true; + fiatCode; + isNW = platformInfo.isNW; + isAndroid = platformInfo.isAndroid; + isIos = platformInfo.isIOS; + lastUsedAltCurrencyList = []; + passthroughParams = {}; + satToUnit; + transactionSendableAmount = { + crypto: '', + satoshis: null + }; + unitDecimals; + unitIndex = 0; + unitToSatoshi; + useSendMax = false; + walletSpendableAmount = { + crypto: '', + satoshis: null + }; + + // Public variables + vm.allowSend = false; + vm.altCurrencyList = []; + vm.alternativeAmount = ''; + vm.alternativeUnit = ''; + vm.amount = '0'; + vm.availableFunds = ''; + vm.canSendAllAvailableFunds = true; + vm.errorMessage = ''; + // Use insufficient for logic, as when the amount is invalid, funds being + // either sufficent or insufficient doesn't make sense. + vm.fundsAreInsufficient = false; + vm.globalResult = ''; + vm.isRequestingSpecificAmount = false; + vm.listComplete = false; + vm.lastUsedPopularList = []; + vm.maxAmount = 0; + vm.minAmount = 0; + vm.sendableFunds = ''; + vm.showSendMaxButton = false; + vm.showSendLimitMaxButton = false; + vm.thirdParty = null; + vm.unit = ''; } function onBeforeEnter(event, data) { @@ -88,11 +110,19 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory, sendFlowService.state.pop(); } + + // Init before entering on this screen + initVariables(); initCurrencies(); + // Then start passthroughParams = sendFlowService.state.getClone(); console.log('amount onBeforeEnter after back sendflow ', passthroughParams); + + // Init thirdParty, should be done for all the variable + vm.thirdParty = null; + vm.fromWalletId = passthroughParams.fromWalletId; vm.toWalletId = passthroughParams.toWalletId; vm.minAmount = parseFloat(passthroughParams.minAmount); @@ -218,6 +248,10 @@ function amountController(configService, $filter, gettextCatalog, $ionicHistory, } } + function onLeave() { + angular.element($window).off('keydown'); + } + function goBack() { sendFlowService.router.goBack(); } diff --git a/src/js/controllers/review.controller.js b/src/js/controllers/review.controller.js index 2311b2cb6..5352d609a 100644 --- a/src/js/controllers/review.controller.js +++ b/src/js/controllers/review.controller.js @@ -6,58 +6,9 @@ angular .module('copayApp.controllers') .controller('reviewController', reviewController); - function reviewController(addressbookService, bitcoinCashJsService, bitcore, bitcoreCash, bwcError, clipboardService, configService, feeService, gettextCatalog, $interval, $ionicHistory, $ionicModal, ionicToast, lodash, $log, ongoingProcess, platformInfo, popupService, profileService, $scope, sendFlowService, shapeshiftService, soundService, $state, $timeout, txConfirmNotification, txFormatService, walletService) { + function reviewController(addressbookService, externalLinkService, bitcoinCashJsService, bitcore, bitcoreCash, bwcError, clipboardService, configService, feeService, gettextCatalog, $interval, $ionicHistory, $ionicModal, ionicToast, lodash, $log, ongoingProcess, platformInfo, popupService, profileService, $scope, sendFlowService, shapeshiftService, soundService, $state, $timeout, txConfirmNotification, txFormatService, walletService) { var vm = this; - vm.buttonText = ''; - vm.destination = { - address: '', - balanceAmount: '', - balanceCurrency: '', - coin: '', - color: '', - currency: '', - currencyColor: '', - kind: '', // 'address', 'contact', 'wallet' - name: '' - }; - vm.displayAddress = ''; - vm.feeCrypto = ''; - vm.feeFiat = ''; - vm.fiatCurrency = ''; - vm.feeIsHigh = false; - vm.feeLessThanACent = false; - vm.isCordova = platformInfo.isCordova; - vm.memo = ''; - vm.notReadyMessage = ''; - vm.origin = { - balanceAmount: '', - balanceCurrency: '', - currency: '', - currencyColor: '', - }; - vm.originWallet = null; - vm.paymentExpired = false; - vm.personalNotePlaceholder = gettextCatalog.getString('Enter text here'); - vm.primaryAmount = ''; - vm.primaryCurrency = ''; - vm.usingMerchantFee = false; - vm.readyToSend = false; - vm.remainingTimeStr = ''; - vm.secondaryAmount = ''; - vm.secondaryCurrency = ''; - vm.sendingTitle = gettextCatalog.getString('You are sending'); - vm.sendStatus = ''; - vm.showAddress = true; - vm.thirdParty = false; - vm.wallet = null; - vm.memoExpanded = false; - - // Functions - vm.goBack = goBack; - vm.onSuccessConfirm = onSuccessConfirm; - vm.onShareTransaction = onShareTransaction; - var sendFlowData; var config = null; var coin = ''; @@ -76,23 +27,90 @@ angular var unitFromSat = 0; var FEE_TOO_HIGH_LIMIT_PERCENTAGE = 15; + + // Functions + vm.goBack = goBack; + vm.onSuccessConfirm = onSuccessConfirm; + vm.onShareTransaction = onShareTransaction; + + function initVariables() { + // Private variables + sendFlowData; + config = null; + coin = ''; + countDown = null; + defaults = {}; + usingCustomFee = false; + usingMerchantFee = false; + destinationWalletId = ''; + lastTxId = ''; + originWalletId = ''; + priceDisplayIsFiat = true; + satoshis = null; + toAddress = ''; + tx = {}; + txPayproData = null; + unitFromSat = 0; + + // Public variables + vm.buttonText = ''; + vm.destination = { + address: '', + balanceAmount: '', + balanceCurrency: '', + coin: '', + color: '', + currency: '', + currencyColor: '', + kind: '', // 'address', 'contact', 'wallet' + name: '' + }; + vm.displayAddress = ''; + vm.feeCrypto = ''; + vm.feeFiat = ''; + vm.fiatCurrency = ''; + vm.feeIsHigh = false; + vm.feeLessThanACent = false; + vm.isCordova = platformInfo.isCordova; + vm.memo = ''; + vm.notReadyMessage = ''; + vm.origin = { + balanceAmount: '', + balanceCurrency: '', + currency: '', + currencyColor: '', + }; + vm.originWallet = null; + vm.paymentExpired = false; + vm.personalNotePlaceholder = gettextCatalog.getString('Enter text here'); + vm.primaryAmount = ''; + vm.primaryCurrency = ''; + vm.usingMerchantFee = false; + vm.readyToSend = false; + vm.remainingTimeStr = ''; + vm.secondaryAmount = ''; + vm.secondaryCurrency = ''; + vm.sendingTitle = gettextCatalog.getString('You are sending'); + vm.sendStatus = ''; + vm.showAddress = true; + vm.thirdParty = null; + vm.wallet = null; + vm.memoExpanded = false; + } $scope.$on("$ionicView.beforeEnter", onBeforeEnter); - function onBeforeEnter(event, data) { - console.log('review onBeforeEnter sendflow ', sendFlowService.state); - // Reset from last time - vm.memo = ''; + $log.debug('reviewController onBeforeEnter sendflow ', sendFlowService.state); + + // Init before entering on this screen + initVariables(); + // Then start defaults = configService.getDefaults(); sendFlowData = sendFlowService.state.getClone(); originWalletId = sendFlowData.fromWalletId; - if (typeof sendFlowData.amount === 'string') { - satoshis = parseInt(sendFlowData.amount, 10); - } else { - satoshis = sendFlowData.amount; - } + satoshis = parseInt(sendFlowData.amount, 10); toAddress = sendFlowData.toAddress; destinationWalletId = sendFlowData.toWalletId; @@ -105,11 +123,14 @@ angular vm.thirdParty = sendFlowData.thirdParty; switch (vm.thirdParty.id) { case 'shapeshift': - initShapeshift(function (err) { + initShapeshift(function onInitShapeshift(err) { if (err) { // Error stop here ongoingProcess.set('connectingShapeshift', false); - popupService.showAlert(gettextCatalog.getString('Shapeshift Error'), err.toString(), function () { + popupService.showConfirm(gettextCatalog.getString('Shapeshift Error'), err.toString(), gettextCatalog.getString('Open') + " Shapeshift", gettextCatalog.getString('Go Back'), function onConfirm(hasConfirm) { + if (hasConfirm) { + externalLinkService.open("https://shapeshift.io"); + } $ionicHistory.goBack(); }); } else { @@ -135,7 +156,6 @@ angular 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(); @@ -152,18 +172,18 @@ angular if (!tx || !vm.originWallet) return; if (vm.paymentExpired) { - popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.', function () { + popupService.showAlert(null, gettextCatalog.getString('This bitcoin payment request has expired.', function onAlert() { $ionicHistory.goBack(); })); vm.sendStatus = ''; - $timeout(function() { + $timeout(function onTimeout() { $scope.$apply(); }); return; } ongoingProcess.set('creatingTx', true, statusChangeHandler); - getTxp(lodash.clone(tx), vm.originWallet, false, function(err, txp) { + getTxp(lodash.clone(tx), vm.originWallet, false, function onGetTxp(err, txp) { ongoingProcess.set('creatingTx', false, statusChangeHandler); if (err) return; @@ -180,12 +200,12 @@ angular if (!vm.originWallet.canSign() && !vm.originWallet.isPrivKeyExternal()) { $log.info('No signing proposal: No private key'); - return walletService.onlyPublish(vm.originWallet, txp, function(err) { + return walletService.onlyPublish(vm.originWallet, txp, function onOnlyPublish(err) { if (err) setSendError(err); }, statusChangeHandler); } - walletService.publishAndSign(vm.originWallet, txp, function(err, txp) { + walletService.publishAndSign(vm.originWallet, txp, function onPublishAndSign(err, txp) { if (err) return setSendError(err); if (config.confirmedTxsNotifications && config.confirmedTxsNotifications.enabled) { txConfirmNotification.subscribe(vm.originWallet, { @@ -199,7 +219,7 @@ angular confirmTx(function(nok) { if (nok) { vm.sendStatus = ''; - $timeout(function() { + $timeout(function onTimeout() { $scope.$apply(); }); return; @@ -256,7 +276,6 @@ angular }; function createVanityTransaction(data) { - console.log('createVanityTransaction()'); var configFeeLevel = config.wallet.settings.feeLevel ? config.wallet.settings.feeLevel : 'normal'; // Grab stateParams @@ -280,6 +299,9 @@ angular txp: {}, }; + if (vm.thirdParty && vm.thirdParty.id === "shapeshift") { + tx.toAddress = vm.thirdParty.toAddress; + } if (data.stateParams.requiredFeeRate) { vm.usingMerchantFee = true; @@ -293,29 +315,35 @@ angular var B = tx.coin === 'bch' ? bitcoreCash : bitcore; var networkName; try { - if (vm.destination.kind === 'wallet') { // This is a wallet-to-wallet transfer + // Final destination is a wallet, but this transaction must go to an address for the first stage of the exchange. + if (sendFlowData.thirdParty && sendFlowData.thirdParty.id === 'shapeshift') { + networkName = (new B.Address(tx.toAddress)).network.name; + tx.network = networkName; + setupTx(tx); + + } else if (vm.destination.kind === 'wallet') { // This is a wallet-to-wallet transfer ongoingProcess.set('generatingNewAddress', true); var toWallet = profileService.getWallet(destinationWalletId); // We need an address to send to, so we ask the walletService to create a new address for the toWallet. - console.log('Getting address for wallet...'); walletService.getAddress(toWallet, true, function onWalletAddress(err, addr) { - console.log('getAddress cb called', err); + if (err) { + $log.error('Error getting address for wallet.', err); + throw new Error(err.message); + } ongoingProcess.set('generatingNewAddress', false); tx.toAddress = addr; networkName = (new B.Address(tx.toAddress)).network.name; tx.network = networkName; - console.log('calling setupTx() for wallet.'); setupTx(tx); }); } else { // This is a Wallet-to-address transfer networkName = (new B.Address(tx.toAddress)).network.name; tx.network = networkName; - console.log('calling setupTx() for address.'); setupTx(tx); } } catch (e) { - console.error('Error setting up tx', e); + $log.error('Error setting up tx', e); var message = gettextCatalog.getString('Invalid address'); popupService.showAlert(null, message, function () { $ionicHistory.nextViewOptions({ @@ -385,7 +413,7 @@ angular } txp.excludeUnconfirmedUtxos = !tx.spendUnconfirmed; txp.dryRun = dryRun; - walletService.createTx(wallet, txp, function(err, ctxp) { + walletService.createTx(wallet, txp, function onCreateTx(err, ctxp) { if (err) { setSendError(err); return cb(err); @@ -405,7 +433,7 @@ angular var walletStatus = null; if (wallet.status && wallet.status.isValid) { walletStatus = wallet.status; - } else if (wallet.cachedStatus.isValid) { + } else if (wallet.cachedStatus && wallet.cachedStatus.isValid) { walletStatus = wallet.cachedStatus; } @@ -444,7 +472,7 @@ angular } // Check if the recipient is a contact - addressbookService.get(originCoin + address, function(err, contact) { + addressbookService.get(originCoin + address, function onGetContact(err, contact) { if (!err && contact) { handleDestinationAsAddressOfContact(contact); } else { @@ -517,7 +545,6 @@ angular vm.destination.color = toWallet.color; vm.destination.currency = toWallet.coin.toUpperCase(); - ongoingProcess.set('connectingShapeshift', true); walletService.getAddress(vm.originWallet, false, function onReturnWalletAddress(err, returnAddr) { if (err) { @@ -535,9 +562,8 @@ angular if (err) { return cb(err); } else { - vm.destination.kind = 'shapeshift'; - vm.destination.address = toAddress; - tx.toAddress = shapeshiftData.toAddress; + // Want it to appear like a wallet-to-wallet transfer, so don't set the main toAddress. + vm.thirdParty.toAddress = shapeshiftData.toAddress; vm.memo = 'ShapeShift Order:\nhttps://www.shapeshift.io/#/status/' + shapeshiftData.orderId; vm.memoExpanded = !!vm.memo; ongoingProcess.set('connectingShapeshift', false); @@ -572,7 +598,6 @@ angular }, 1000); function setExpirationTime() { - console.log('setExpirationTime()'); var now = Math.floor(Date.now() / 1000); if (now > expirationTime) { @@ -690,7 +715,7 @@ angular $timeout(function() { $scope.$apply(); }); - popupService.showAlert(gettextCatalog.getString('Error at confirm'), bwcError.msg(msg), function () { + popupService.showAlert(gettextCatalog.getString('Error at confirm'), bwcError.msg(msg), function onAlert() { $ionicHistory.goBack(); }); }; @@ -702,7 +727,7 @@ angular tx.displayAddress = tx.toAddress; } - addressbookService.get(tx.coin+tx.toAddress, function(err, addr) { // Check if the recipient is a contact + addressbookService.get(tx.coin+tx.toAddress, function onGetContact(err, addr) { // Check if the recipient is a contact if (!err && addr) { tx.toName = addr.name; tx.toEmail = addr.email; @@ -721,23 +746,10 @@ angular updateTx(tx, vm.originWallet, { dryRun: true }, function(err) { - $timeout(function() { + $timeout(function onTimeout() { $scope.$apply(); }, 10); - }); - - // setWalletSelector(tx.coin, tx.network, tx.amount, function(err) { - // if (err) { - // return exitWithError('Could not update wallets'); - // } - // - // if (vm.wallets.length > 1) { - // vm.showWalletSelector(); - // } else if (vm.wallets.length) { - // setWallet(vm.wallets[0], tx); - // } - // }); } function showSendMaxWarning(wallet, sendMaxInfo) { @@ -848,7 +860,7 @@ angular // refresh(); var feeServiceLevel = usingMerchantFee && vm.originWallet.coin == 'btc' ? 'urgent' : tx.feeLevel; - feeService.getFeeRate(vm.originWallet.coin, tx.network, feeServiceLevel, function(err, feeRate) { + feeService.getFeeRate(vm.originWallet.coin, tx.network, feeServiceLevel, function onGetFeeRate(err, feeRate) { if (err) { ongoingProcess.set('calculatingFee', false); return cb(err); @@ -867,7 +879,7 @@ angular tx.feeRate = feeRate; } - getSendMaxInfo(lodash.clone(tx), wallet, function(err, sendMaxInfo) { + getSendMaxInfo(lodash.clone(tx), wallet, function onGetSendmaxInfo(err, sendMaxInfo) { if (err) { ongoingProcess.set('calculatingFee', false); var msg = gettextCatalog.getString('Error getting SendMax information'); @@ -881,7 +893,7 @@ angular if (tx.sendMax && sendMaxInfo.amount == 0) { ongoingProcess.set('calculatingFee', false); setNotReady(gettextCatalog.getString('Insufficient confirmed funds')); - popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'), function () { + popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'), function onAlert() { $ionicHistory.goBack(); }); return cb('no_funds'); @@ -906,8 +918,7 @@ angular return cb(); } - console.log('calling getTxp() from getSendMaxInfo cb.'); - getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) { + getTxp(lodash.clone(tx), wallet, opts.dryRun, function onGetTxp(err, txp) { ongoingProcess.set('calculatingFee', false); if (err) { if (err.message == 'Insufficient funds') { @@ -919,7 +930,7 @@ angular } txp.feeStr = txFormatService.formatAmountStr(wallet.coin, txp.fee); - txFormatService.formatAlternativeStr(wallet.coin, txp.fee, function(v) { + txFormatService.formatAlternativeStr(wallet.coin, txp.fee, function onFormatAlternativeStr(v) { // txp.alternativeFeeStr = v; // if (txp.alternativeFeeStr.substring(0, 4) == '0.00') // txp.alternativeFeeStr = '< ' + txp.alternativeFeeStr; @@ -928,8 +939,6 @@ angular if (v.substring(0, 1) === "<") { vm.feeLessThanACent = true; } - - console.log("fiat", vm.feeFiat); }); @@ -939,14 +948,11 @@ angular txp.feeToHigh = per > FEE_TOO_HIGH_LIMIT_PERCENTAGE; vm.feeCrypto = (unitFromSat * txp.fee).toFixed(8); vm.feeIsHigh = txp.feeToHigh; - console.log("crypto", vm.feeCrypto); - tx.txp[wallet.id] = txp; $log.debug('Confirm. TX Fully Updated for wallet:' + wallet.id, tx); vm.readyToSend = true; updateSendAmounts(); - console.log('readyToSend:', vm.readyToSend); $scope.$apply(); return cb(); diff --git a/src/js/controllers/wallet-selector.controller.js b/src/js/controllers/wallet-selector.controller.js index 036727333..7a5cc2d87 100644 --- a/src/js/controllers/wallet-selector.controller.js +++ b/src/js/controllers/wallet-selector.controller.js @@ -12,6 +12,17 @@ angular var unitDecimals = 0; var unitsFromSatoshis = 0; + // + // Needs to migrate $scope to vm. + // + function initVariables() { + // Private variables + fromWalletId = ''; + priceDisplayAsFiat = false; + unitDecimals = 0; + unitsFromSatoshis = 0; + } + $scope.$on("$ionicView.beforeEnter", onBeforeEnter); $scope.$on("$ionicView.enter", onEnter); @@ -20,6 +31,10 @@ angular sendFlowService.state.pop(); } + // Init before entering on this screen + initVariables(); + // Then start + $scope.params = sendFlowService.state.getClone(); console.log('walletSelector onBeforeEnter after back sendflow', $scope.params); @@ -52,9 +67,6 @@ angular $scope.specificAmount = $scope.specificAlternativeAmount = ''; $scope.isPaymentRequest = true; } - if ($scope.params.thirdParty) { - $scope.thirdParty = $scope.params.thirdParty; - } }; function onEnter (event, data) { @@ -62,7 +74,7 @@ angular $scope.selectedPriceDisplay = config.wallet.settings.priceDisplay; }); - if ($scope.thirdParty) { + if ($scope.params.thirdParty) { // Third party services specific logic handleThirdPartyIfShapeshift(); } @@ -102,8 +114,8 @@ angular } function handleThirdPartyIfShapeshift() { - console.log($scope.thirdParty, $scope.coin); - if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the + console.log($scope.params.thirdParty, $scope.coin); + if ($scope.params.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the $scope.coin = profileService.getWallet(fromWalletId).coin; if ($scope.coin === 'bch') { $scope.coin = 'btc'; @@ -117,6 +129,8 @@ angular var walletsAll = []; var walletsSufficientFunds = []; $scope.walletsInsufficientFunds = []; // For origin screen + $scope.walletsBtc = []; + $scope.walletsBch = []; if ($scope.type === 'origin') { $scope.headerTitle = gettextCatalog.getString('Choose a wallet to send from'); diff --git a/src/js/directives/incomingDataMenu.js b/src/js/directives/incomingDataMenu.js index 78856e62f..e093cb5e3 100644 --- a/src/js/directives/incomingDataMenu.js +++ b/src/js/directives/incomingDataMenu.js @@ -16,8 +16,8 @@ angular.module('copayApp.directives') scope.type = "url"; } else if (scope.data.parsed.publicAddress) { scope.type = "bitcoinAddress"; - var prefix = scope.data.parsed.isTestnet ? 'bchtest:' : 'bitcoincash:'; - scope.data.toAddress = (prefix + scope.data.parsed.publicAddress.cashAddr) || scope.data.parsed.publicAddress.legacy || scope.data.parsed.publicAddress.bitpay; + var prefix = scope.data.coin === 'bch' ? (scope.data.parsed.isTestnet ? 'bchtest:' : 'bitcoincash:') : ''; + scope.data.toAddress = (scope.data.parsed.publicAddress.cashAddr ? prefix + scope.data.parsed.publicAddress.cashAddr : false) || scope.data.parsed.publicAddress.legacy || scope.data.parsed.publicAddress.bitpay; } else { scope.type = "text"; } diff --git a/src/js/services/bitcoin-uri.service.js b/src/js/services/bitcoin-uri.service.js index 3da84f3da..669c14bf3 100644 --- a/src/js/services/bitcoin-uri.service.js +++ b/src/js/services/bitcoin-uri.service.js @@ -151,6 +151,7 @@ hasPassphrase: false, type: 1, }, + isTestnet: false, isValid: false, label: '', message: '', @@ -170,7 +171,6 @@ "req-param0": '', "req-param1": '' }, - testnet: false, url: '' // For BIP70 } @@ -204,7 +204,13 @@ } else if (/^(?:bitcoincash)|(?:bitcoin-cash)$/.test(preColonLower)) { parsed.coin = 'bch'; - parsed.test = false; + parsed.isTestnet = false; + addressAndParams = colonSplit[2].trim(); + console.log('Is bch'); + + } else if (/^(?:bch)$/.test(preColonLower)) { + parsed.coin = 'bch'; + parsed.isTestnet = false; addressAndParams = colonSplit[2].trim(); console.log('Is bch'); diff --git a/src/js/services/bitcoin-uri.service.spec.js b/src/js/services/bitcoin-uri.service.spec.js index 2ddbd0d2e..bf6c9ce9e 100644 --- a/src/js/services/bitcoin-uri.service.spec.js +++ b/src/js/services/bitcoin-uri.service.spec.js @@ -30,7 +30,7 @@ describe('bitcoinUriService', function() { expect(parsed.isValid).toBe(true); expect(parsed.coin).toBe('bch'); expect(parsed.publicAddress).toBeUndefined(); - expect(parsed.isTestnet).toBeUndefined(); + expect(parsed.isTestnet).toBe(false); expect(parsed.url).toBe('https://bitpay.com/i/SmHdie5dvBnG5kouZzEPzu'); }); @@ -171,6 +171,16 @@ describe('bitcoinUriService', function() { expect(parsed.isTestnet).toBe(false); }); + it('legacy address with bch prefix', function() { + + var parsed = bitcoinUriService.parse('bch:19yUdM2H7sADrabR6Afu9zTpmwqr6WYprX'); + + expect(parsed.isValid).toBe(true); + expect(parsed.coin).toBe('bch'); + expect(parsed.publicAddress.legacy).toBe('19yUdM2H7sADrabR6Afu9zTpmwqr6WYprX'); + expect(parsed.isTestnet).toBe(false); + }); + it('cashAddr testnet with prefix', function() { var parsed = bitcoinUriService.parse('bchtest:qpcz6pmurq9ctg5848trzz9zmuuygj4q5qam7ph3gt'); @@ -191,6 +201,16 @@ describe('bitcoinUriService', function() { expect(parsed.isTestnet).toBe(false); }); + it('cashAddr with bch prefix', function() { + + var parsed = bitcoinUriService.parse('bch:qpqzqtjqqc00nsxj0e3kevz65ujg4yt5z5w99jap5f'); + + expect(parsed.isValid).toBe(true); + expect(parsed.coin).toBe('bch'); + expect(parsed.publicAddress.cashAddr).toBe('qpqzqtjqqc00nsxj0e3kevz65ujg4yt5z5w99jap5f'); + expect(parsed.isTestnet).toBe(false); + }); + it('cashAddr with dash', function() { var parsed = bitcoinUriService.parse('bitcoin-cash:qpshfu3dk5s3e7zdcgdcun6xgxtra6uyxs7g580js0'); diff --git a/src/js/services/send-flow.service.js b/src/js/services/send-flow.service.js index e8be2e487..babf5096a 100644 --- a/src/js/services/send-flow.service.js +++ b/src/js/services/send-flow.service.js @@ -52,7 +52,7 @@ angular // Detect some merchant that we know if (payProData.memo.indexOf('eGifter') > -1) { name = 'eGifter' - } else if (paymentUrl.indexOf('https://bitpay.com') > -1) { + } else if (payProData.url.indexOf('https://bitpay.com') > -1) { name = 'BitPay'; } diff --git a/src/js/services/shapeShiftApiService.js b/src/js/services/shapeShiftApiService.js index cc5fb0792..a90e587d4 100644 --- a/src/js/services/shapeShiftApiService.js +++ b/src/js/services/shapeShiftApiService.js @@ -24,7 +24,7 @@ var ShapeShift = (function() { var parsedResponse = JP(xmlhttp.responseText); cb.apply(null, [parsedResponse]); } else { - cb.apply(null, [new Error('Request Failed')]) + cb.apply(null, [new Error('Request Failed')]); } } }; diff --git a/src/js/services/shapeshift.service.js b/src/js/services/shapeshift.service.js index 73410e478..8fdfe08b9 100644 --- a/src/js/services/shapeshift.service.js +++ b/src/js/services/shapeshift.service.js @@ -63,6 +63,7 @@ angular } 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; @@ -72,7 +73,7 @@ angular // Check the address shapeshiftApiService - .ValidateAddress(withdrawalAddress, coinOut) + .ValidateAddress(returnAddress, coinOut) .then(function onSuccess(response) { if (response && response.isvalid) { // Prepare the transaction shapeshift side diff --git a/src/js/services/wallet-history.service.js b/src/js/services/wallet-history.service.js index 512a2d8b1..a9792c170 100644 --- a/src/js/services/wallet-history.service.js +++ b/src/js/services/wallet-history.service.js @@ -7,8 +7,8 @@ .factory('walletHistoryService', walletHistoryService); function walletHistoryService(configService, storageService, lodash, $log, txFormatService) { - //var PAGE_SIZE = 50; - var PAGE_SIZE = 20; // For dev only + var PAGE_SIZE = 50; + //var PAGE_SIZE = 20; // For dev only // How much to overlap on each end of the page, for mitigating inconsistent sort order. var PAGE_OVERLAP_FRACTION = 0.2; var PAGE_OVERLAP = Math.floor(PAGE_SIZE * PAGE_OVERLAP_FRACTION); @@ -28,8 +28,8 @@ function addEarlyTransactions(walletId, cachedTxs, newTxs) { var cachedTxIndexFromId = {}; - cachedTxs.forEach(function forCachedTx(tx){ - cachedTxIndexFromId[tx.txid] = true; + cachedTxs.forEach(function forCachedTx(tx, txIndex){ + cachedTxIndexFromId[tx.txid] = txIndex; }); var confirmationsUpdated = false; @@ -49,8 +49,9 @@ var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); console.log('overlappingTxFraction:', overlappingTxFraction); + console.log('overlappingTxsCount:', overlappingTxsCount); - if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION) { // We are good + if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION || (someTransactionsWereNew && overlappingTxsCount === 0)) { // We are good if (someTransactionsWereNew) { saveTxHistory(walletId, cachedTxs); } else if (confirmationsUpdated) { @@ -93,7 +94,7 @@ var overlappingTxFraction = overlappingTxsCount / Math.min(cachedTxs.length, PAGE_OVERLAP); - if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION) { // We are good + if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION || (someTransactionsWereNew && overlappingTxsCount === 0)) { // We are good if (someTransactionsWereNew) { var allTxs = uniqueNewTxs.concat(cachedTxs); saveTxHistory(walletId, allTxs); @@ -147,7 +148,6 @@ * @param {function(error, txs)} cb - txs is always an array, may be empty */ function getCachedTxHistory(walletId, cb) { - console.log('txhistory updateLocalTxHistoryByPage()'); storageService.getTxHistory(walletId, function onGetTxHistory(err, txHistoryString){ if (err) { return cb(err, []); @@ -230,7 +230,6 @@ } function updateLocalTxHistoryByPage(wallet, getLatest, flushCacheOnNew, cb) { - console.log('txhistory updaetLocalTxHistoryByPage()'); if (flushCacheOnNew) { fetchTxHistoryByPage(wallet, 0, function onFetchTxHistory(err, txs){ if (err) {